zynqmp: pm: Reimplement clock get divider EEMI API
authorJolly Shah <jollys@xilinx.com>
Fri, 4 Jan 2019 19:53:37 +0000 (11:53 -0800)
committerJolly Shah <jollys@xilinx.com>
Fri, 4 Jan 2019 19:53:48 +0000 (11:53 -0800)
Clock get divider EEMI API is reimplemented to use system-level clock
get 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

index de849ee174a3d0872a254cedaa1a5f0bb1d804af..e8053060b773772ddd5b0761ee4f495d318bc929 100644 (file)
@@ -2628,90 +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_get_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;
-       unsigned int reg, val, i, div1 = 0, div2 = 0;
-       uint8_t div1_width = NA_WIDTH, div1_offset = NA_SHIFT;
-       uint8_t div2_width = NA_WIDTH, div2_offset = NA_SHIFT;
-
-       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++;
-       }
-
-       ret = pm_mmio_read(reg, &val);
-
-       if (div1_width == NA_WIDTH)
-               return PM_RET_ERROR_ARGS;
-
-       div1 = (val & BIT_MASK(div1_offset, div1_width)) >> div1_offset;
-
-       if (div2_width != NA_WIDTH)
-               div2 = (val & BIT_MASK(div2_offset, div2_width)) >> div2_offset;
-
-       *divider = div1 | (div2 << 16);
-
-       return ret;
-}
-
-static enum pm_ret_status pm_api_pll_get_divider(unsigned int clock_id,
-                                         unsigned int *divider)
-{
-       enum pm_ret_status ret = PM_RET_SUCCESS;
-       unsigned int reg, val;
-
-       reg = clocks[clock_id].control_reg;
-
-       ret = pm_mmio_read(reg, &val);
-       *divider = (val & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
-
-       return ret;
-}
-
-/**
- * pm_api_clock_getdivider - Get the clock divider for given id
- * @clock_id   Id of the clock
- * @divider    Divider value
- *
- * This function is used by master to get divider values
- * for any clock.
- *
- * Return: Returns status, either success or error+reason.
- */
-enum pm_ret_status pm_api_clock_getdivider(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_get_divider(clock_id, divider);
-       else
-               ret = pm_api_clk_get_divider(clock_id, divider);
-
-       return ret;
-}
-
 /**
  * pm_api_clock_setrate - Set the clock rate for given id
  * @clock_id   Id of the clock
@@ -2900,3 +2816,32 @@ enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id)
 
        return PM_RET_SUCCESS;
 }
+
+/**
+ * pm_clock_has_div() - Check if the clock has divider with given ID
+ * @clock_id   Clock ID
+ * @div_id     Divider ID
+ *
+ * @return     True(1)=clock has the divider, false(0)=otherwise
+ */
+uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id)
+{
+       uint32_t i;
+       struct pm_clock_node *nodes;
+
+       if (clock_id >= CLK_MAX_OUTPUT_CLK)
+               return 0;
+
+       nodes = *clocks[clock_id].nodes;
+       for (i = 0; i < clocks[clock_id].num_nodes; i++) {
+               if (nodes[i].type == TYPE_DIV1) {
+                       if (div_id == PM_CLOCK_DIV0_ID)
+                               return 1;
+               } else if (nodes[i].type == TYPE_DIV2) {
+                       if (div_id == PM_CLOCK_DIV1_ID)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
index 543f2ade1a09ad8d5b237117f5530256b9fd7d62..419690a14ee24498121835995425baf01e9aa7e5 100644 (file)
@@ -276,6 +276,7 @@ enum {
 
 struct pm_pll;
 struct pm_pll *pm_clock_get_pll(enum clock_id clock_id);
+uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id);
 
 enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name);
 enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks);
@@ -299,8 +300,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_getdivider(unsigned int clock_id,
-                                          unsigned int *divider);
 enum pm_ret_status pm_api_clock_setrate(unsigned int clock_id,
                                        uint64_t rate);
 enum pm_ret_status pm_api_clock_getrate(unsigned int clock_id,
index 91a146168e6dcd92cf7f7a15daa776e655483590..402b7c6881226709108788e4c39ad4dbff30c8e7 100644 (file)
@@ -1010,7 +1010,42 @@ enum pm_ret_status pm_clock_setdivider(unsigned int clock_id,
 enum pm_ret_status pm_clock_getdivider(unsigned int clock_id,
                                       unsigned int *divider)
 {
-       return pm_api_clock_getdivider(clock_id, divider);
+       enum pm_ret_status status;
+       enum pm_node_id nid;
+       uint32_t payload[PAYLOAD_ARG_CNT];
+       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_get_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 (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) {
+               /* Send request to the PMU to get div0 */
+               PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+                                PM_CLOCK_DIV0_ID);
+               status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+               if (status != PM_RET_SUCCESS)
+                       return status;
+               *divider = val;
+       }
+
+       if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) {
+               /* Send request to the PMU to get div1 */
+               PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+                                PM_CLOCK_DIV1_ID);
+               status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+               if (status != PM_RET_SUCCESS)
+                       return status;
+               *divider |= val << 16;
+       }
+
+       return status;
 }
 
 /**