summaryrefslogtreecommitdiff
path: root/plat/xilinx
diff options
context:
space:
mode:
authorJolly Shah <jollys@xilinx.com>2019-01-04 11:49:46 -0800
committerJolly Shah <jollys@xilinx.com>2019-01-04 11:51:05 -0800
commit48dc44e3837ff4663d3c84afbc1837eb05c88553 (patch)
treea43001cf2fb3ad86163abf936ea0e4d16a5fa0c8 /plat/xilinx
parentbd30503a9dc8f23d8ef7431efbc2f6c106ee326c (diff)
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>
Diffstat (limited to 'plat/xilinx')
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.c157
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.h3
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.c32
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_defs.h9
4 files changed, 40 insertions, 161 deletions
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
index 536889ce..de849ee1 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -2559,74 +2559,6 @@ enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
}
/**
- * 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)
{
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
index dfdaf895..543f2ade 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -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,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 49471dca..91a14616 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -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);
}
/**
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index 7c238938..cae36c9d 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -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 */