zynqmp: pm: Reimplement clock set divider EEMI API

Clock set divider EEMI API is reimplemented to use system-level clock
set divider EEMI API rather than direct MMIO read/write accesses to clock
control registers.

Signed-off-by: Mirela Simonovic <mirela.simonovic@aggios.com>
Acked-by: Will Wong <WILLW@xilinx.com>
Signed-off-by: Jolly Shah <jollys@xilinx.com>
This commit is contained in:
Jolly Shah 2019-01-04 11:49:46 -08:00
parent bd30503a9d
commit 48dc44e383
4 changed files with 40 additions and 161 deletions

View File

@ -2558,74 +2558,6 @@ enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
return PM_RET_ERROR_ARGS;
}
/**
* pll_get_lockbit() - Returns lockbit index for pll id
* @pll_id: Id of the pll
*
* This function return the PLL_LOCKED bit index in
* pll status register accosiated with given pll id.
*
* Return: Returns bit index
*/
static int pll_get_lockbit(unsigned int pll_id)
{
switch (pll_id) {
case CLK_APLL_INT:
case CLK_IOPLL_INT:
return 0;
case CLK_DPLL_INT:
case CLK_RPLL_INT:
return 1;
case CLK_VPLL_INT:
return 2;
default:
return -1;
}
}
/**
* pm_api_pll_bypass_and_reset() - Bypass and reset PLL
* @clock_id: Id of the PLL
*
* This function is to bypass and reset PLL.
*/
static inline enum pm_ret_status
pm_api_pll_bypass_and_reset(unsigned int clock_id, unsigned int flag)
{
enum pm_ret_status ret = PM_RET_SUCCESS;
unsigned int reg, val;
int lockbit;
reg = clocks[clock_id].control_reg;
if (flag & CLK_PLL_RESET_ASSERT) {
ret = pm_mmio_write(reg, PLLCTRL_BP_MASK, PLLCTRL_BP_MASK);
if (ret != PM_RET_SUCCESS)
return ret;
ret = pm_mmio_write(reg, PLLCTRL_RESET_MASK,
PLLCTRL_RESET_MASK);
if (ret != PM_RET_SUCCESS)
return ret;
}
if (flag & CLK_PLL_RESET_RELEASE) {
ret = pm_mmio_write(reg, PLLCTRL_RESET_MASK,
~PLLCTRL_RESET_MASK);
if (ret != PM_RET_SUCCESS)
return ret;
lockbit = pll_get_lockbit(clock_id);
do {
ret = pm_mmio_read(clocks[clock_id].status_reg, &val);
if (ret != PM_RET_SUCCESS)
return ret;
} while ((lockbit >= 0) && !(val & (1 << lockbit)));
ret = pm_mmio_write(reg, PLLCTRL_BP_MASK,
~(unsigned int)PLLCTRL_BP_MASK);
}
return ret;
}
/**
* pm_clock_pll_enable() - "Enable" the PLL clock (lock the PLL)
* @pll: PLL to be locked
@ -2696,95 +2628,6 @@ enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
return PM_RET_SUCCESS;
}
static enum pm_ret_status pm_api_clk_set_divider(unsigned int clock_id,
uint32_t divider)
{
enum pm_ret_status ret = PM_RET_SUCCESS;
struct pm_clock_node *nodes;
uint8_t num_nodes;
uint16_t div1, div2;
unsigned int reg, mask = 0, val = 0, i;
uint8_t div1_width = NA_WIDTH, div1_offset = NA_SHIFT;
uint8_t div2_width = NA_WIDTH, div2_offset = NA_SHIFT;
div1 = (uint16_t)(divider & 0xFFFFU);
div2 = (uint16_t)((divider >> 16) & 0xFFFFU);
reg = clocks[clock_id].control_reg;
nodes = *clocks[clock_id].nodes;
num_nodes = clocks[clock_id].num_nodes;
for (i = 0; i < num_nodes; i++) {
if (nodes->type == TYPE_DIV1) {
div1_offset = nodes->offset;
div1_width = nodes->width;
}
if (nodes->type == TYPE_DIV2) {
div2_offset = nodes->offset;
div2_width = nodes->width;
}
nodes++;
}
if (div1 != (uint16_t)-1) {
if (div1_width == NA_WIDTH)
return PM_RET_ERROR_NOTSUPPORTED;
val |= div1 << div1_offset;
mask |= BIT_MASK(div1_offset, div1_width);
}
if (div2 != (uint16_t)-1) {
if (div2_width == NA_WIDTH)
return PM_RET_ERROR_NOTSUPPORTED;
val |= div2 << div2_offset;
mask |= BIT_MASK(div2_offset, div2_width);
}
ret = pm_mmio_write(reg, mask, val);
return ret;
}
static enum pm_ret_status pm_api_pll_set_divider(unsigned int clock_id,
unsigned int divider)
{
unsigned int reg = clocks[clock_id].control_reg;
enum pm_ret_status ret;
pm_api_pll_bypass_and_reset(clock_id, CLK_PLL_RESET_ASSERT);
ret = pm_mmio_write(reg, PLL_FBDIV_MASK, divider << PLL_FBDIV_SHIFT);
pm_api_pll_bypass_and_reset(clock_id, CLK_PLL_RESET_RELEASE);
return ret;
}
/**
* pm_api_clock_setdivider - Set the clock divider for given id
* @clock_id Id of the clock
* @divider Divider value
*
* This function is used by master to set divider for any clock
* to achieve desired rate.
*
* Return: Returns status, either success or error+reason.
*/
enum pm_ret_status pm_api_clock_setdivider(unsigned int clock_id,
unsigned int divider)
{
enum pm_ret_status ret;
if (!pm_clock_valid(clock_id))
return PM_RET_ERROR_ARGS;
if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
return PM_RET_ERROR_NOTSUPPORTED;
if (ISPLL(clock_id))
ret = pm_api_pll_set_divider(clock_id, divider);
else
ret = pm_api_clk_set_divider(clock_id, divider);
return ret;
}
static enum pm_ret_status pm_api_clk_get_divider(unsigned int clock_id,
uint32_t *divider)
{

View File

@ -299,9 +299,6 @@ enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll);
enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll);
enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
unsigned int *state);
enum pm_ret_status pm_api_clock_setdivider(unsigned int clock_id,
unsigned int divider);
enum pm_ret_status pm_api_clock_getdivider(unsigned int clock_id,
unsigned int *divider);
enum pm_ret_status pm_api_clock_setrate(unsigned int clock_id,

View File

@ -964,7 +964,37 @@ enum pm_ret_status pm_clock_getstate(unsigned int clock_id,
enum pm_ret_status pm_clock_setdivider(unsigned int clock_id,
unsigned int divider)
{
return pm_api_clock_setdivider(clock_id, divider);
enum pm_ret_status status;
enum pm_node_id nid;
enum pm_clock_div_id div_id;
uint32_t payload[PAYLOAD_ARG_CNT];
const uint32_t div0 = 0xFFFF0000;
const uint32_t div1 = 0x0000FFFF;
uint32_t val;
/* Get PLL node ID using PLL clock ID */
status = pm_clock_get_pll_node_id(clock_id, &nid);
if (status == PM_RET_SUCCESS)
return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider);
/* Check if clock ID is a valid on-chip clock */
status = pm_clock_id_is_valid(clock_id);
if (status != PM_RET_SUCCESS)
return status;
if (div0 == (divider & div0)) {
div_id = PM_CLOCK_DIV0_ID;
val = divider & ~div0;
} else if (div1 == (divider & div1)) {
div_id = PM_CLOCK_DIV1_ID;
val = (divider & ~div1) >> 16;
} else {
return PM_RET_ERROR_ARGS;
}
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val);
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**

View File

@ -308,4 +308,13 @@ enum pm_pll_mode {
PM_PLL_MODE_MAX,
};
/**
* @PM_CLOCK_DIV0_ID: Clock divider 0
* @PM_CLOCK_DIV1_ID: Clock divider 1
*/
enum pm_clock_div_id {
PM_CLOCK_DIV0_ID,
PM_CLOCK_DIV1_ID,
};
#endif /* PM_DEFS_H */