blob: 8120d99626517b96da156d86922efc3f90c3e01a [file] [log] [blame]
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <mt8173_def.h>
#include <pmic_wrap_init.h>
/* pmic wrap module wait_idle and read polling interval (in microseconds) */
enum {
WAIT_IDLE_POLLING_DELAY_US = 1,
READ_POLLING_DELAY_US = 2
};
static inline uint32_t wait_for_state_idle(uint32_t timeout_us,
void *wacs_register,
void *wacs_vldclr_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
WAIT_IDLE_POLLING_DELAY_US;
do {
udelay(WAIT_IDLE_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
/* if last read command timeout,clear vldclr bit
read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
write:FSM_REQ-->idle */
switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
RDATA_WACS_FSM_MASK)) {
case WACS_FSM_WFVLDCLR:
mmio_write_32((uintptr_t)wacs_vldclr_register, 1);
ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
break;
case WACS_FSM_WFDLE:
ERROR("WACS_FSM = WACS_FSM_WFDLE\n");
break;
case WACS_FSM_REQ:
ERROR("WACS_FSM = WACS_FSM_REQ\n");
break;
case WACS_FSM_IDLE:
goto done;
default:
break;
}
retry--;
} while (retry);
done:
if (!retry) /* timeout */
return E_PWR_WAIT_IDLE_TIMEOUT;
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static inline uint32_t wait_for_state_ready(uint32_t timeout_us,
void *wacs_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
do {
udelay(READ_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)
== WACS_FSM_WFVLDCLR)
break;
retry--;
} while (retry);
if (!retry) { /* timeout */
ERROR("timeout when waiting for idle\n");
return E_PWR_WAIT_IDLE_TIMEOUT_READ;
}
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static int32_t pwrap_wacs2(uint32_t write,
uint32_t adr,
uint32_t wdata,
uint32_t *rdata,
uint32_t init_check)
{
uint32_t reg_rdata = 0;
uint32_t wacs_write = 0;
uint32_t wacs_adr = 0;
uint32_t wacs_cmd = 0;
uint32_t return_value = 0;
if (init_check) {
reg_rdata = mmio_read_32((uintptr_t)&mt8173_pwrap->wacs2_rdata);
/* Prevent someone to used pwrap before pwrap init */
if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
ERROR("initialization isn't finished\n");
return E_PWR_NOT_INIT_DONE;
}
}
reg_rdata = 0;
/* Check IDLE in advance */
return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE,
&mt8173_pwrap->wacs2_rdata,
&mt8173_pwrap->wacs2_vldclr,
0);
if (return_value != 0) {
ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value);
goto FAIL;
}
wacs_write = write << 31;
wacs_adr = (adr >> 1) << 16;
wacs_cmd = wacs_write | wacs_adr | wdata;
mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_cmd, wacs_cmd);
if (write == 0) {
if (NULL == rdata) {
ERROR("rdata is a NULL pointer\n");
return_value = E_PWR_INVALID_ARG;
goto FAIL;
}
return_value = wait_for_state_ready(TIMEOUT_READ,
&mt8173_pwrap->wacs2_rdata,
&reg_rdata);
if (return_value != 0) {
ERROR("wait_for_fsm_vldclr fail,return_value=%d\n",
return_value);
goto FAIL;
}
*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
& RDATA_WACS_RDATA_MASK);
mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_vldclr, 1);
}
FAIL:
return return_value;
}
/* external API for pmic_wrap user */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
{
return pwrap_wacs2(0, adr, 0, rdata, 1);
}
int32_t pwrap_write(uint32_t adr, uint32_t wdata)
{
return pwrap_wacs2(1, adr, wdata, 0, 1);
}