zynqmp: pm: Reimplement clock set divider EEMI API
authorJolly Shah <jollys@xilinx.com>
Fri, 4 Jan 2019 19:49:46 +0000 (11:49 -0800)
committerJolly Shah <jollys@xilinx.com>
Fri, 4 Jan 2019 19:51:05 +0000 (11:51 -0800)
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>
plat/xilinx/zynqmp/pm_service/pm_api_clock.c
plat/xilinx/zynqmp/pm_service/pm_api_clock.h
plat/xilinx/zynqmp/pm_service/pm_api_sys.c
plat/xilinx/zynqmp/pm_service/pm_defs.h

index 536889ce1b33209e288c6afc3b6f6eb3c6b16223..de849ee174a3d0872a254cedaa1a5f0bb1d804af 100644 (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)
 {
index dfdaf895f3c3279c5ede3cfcc96b9ca66bf90ebc..543f2ade1a09ad8d5b237117f5530256b9fd7d62 100644 (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,
index 49471dcac761b40e59c8572f655b65628b7ac04a..91a146168e6dcd92cf7f7a15daa776e655483590 100644 (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);
 }
 
 /**
index 7c2389385aba06d071323fefbe725af4bcc64d6b..cae36c9d8fc8d1fdf15455b1ae357ba087626a0e 100644 (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 */