summaryrefslogtreecommitdiff
path: root/plat/xilinx
diff options
context:
space:
mode:
authorJolly Shah <jollys@xilinx.com>2019-01-04 11:45:59 -0800
committerJolly Shah <jollys@xilinx.com>2019-01-04 11:47:30 -0800
commitbd642dde65a51328ff2041a751550d19380f6658 (patch)
tree628995619145c32517c33726bc63b60207f739df /plat/xilinx
parenta5ae5a72fa71ceb4e14d23dc478d451ae7cfe834 (diff)
zynqmp: pm: Reimplement clock enable EEMI API
Clock enable EEMI API is reimplemented to use system-level clock and pll EEMI APIs rather than direct MMIO read/write accesses to clock and pll control registers. Since linux still uses clock enable API to trigger locking of the PLLs in the pm_clock_enable() implementation we need to workaround this by distinguishing two cases: 1) if the given clock ID corresponds to a PLL output clock ID; or 2) given clock ID is truly an on-chip clock that can be gated. For case 1) we'll call pm_api_clock_pll_enable() implemented in pm_api_clock.h/c. This function checks what is the buffered PLL mode and calls the system-level PLL set mode EEMI API with the buffered mode value specified as argument. Long term, if linux driver get fixed to use PLL EEMI API to control PLLs, this case could be removed from ATF. For case 2) we'll call the PMU to configure the clock gate. This is done using system-level clock enable EEMI API. 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.c49
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.h5
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.c44
3 files changed, 74 insertions, 24 deletions
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
index 1fab38fa..ee8b3873 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -2526,7 +2526,7 @@ static struct pm_pll pm_plls[] = {
*
* @return Pointer to PLL structure if found, NULL otherwise
*/
-static struct pm_pll *pm_clock_get_pll(enum clock_id clock_id)
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_id)
{
uint32_t i;
@@ -2679,32 +2679,24 @@ static enum pm_ret_status pm_api_clk_enable_disable(unsigned int clock_id,
}
/**
- * pm_api_clock_enable() - Enable the clock for given id
- * @clock_id: Id of the clock to be enabled
+ * pm_clock_pll_enable() - "Enable" the PLL clock (lock the PLL)
+ * @pll: PLL to be locked
*
- * This function is used by master to enable the clock
- * including peripherals and PLL clocks.
+ * This function is used to map IOCTL/linux-based PLL handling to system-level
+ * EEMI APIs
*
- * Return: Returns status, either success or error+reason.
+ * Return: Error if the argument is not valid or status as returned by PMU
*/
-enum pm_ret_status pm_api_clock_enable(unsigned int clock_id)
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll)
{
- enum pm_ret_status ret = PM_RET_SUCCESS;
-
- if (!pm_clock_valid(clock_id))
+ if (!pll)
return PM_RET_ERROR_ARGS;
- if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
- return PM_RET_ERROR_NOTSUPPORTED;
-
- /*
- * PLL type clock should not enable explicitly.
- * It is done by FSBL on boot-up and by PMUFW whenever required.
- */
- if (!ISPLL(clock_id))
- ret = pm_api_clk_enable_disable(clock_id, 1);
+ /* Set the PLL mode according to the buffered mode value */
+ if (pll->mode == PLL_FRAC_MODE)
+ return pm_pll_set_mode(pll->nid, PM_PLL_MODE_FRACTIONAL);
- return ret;
+ return pm_pll_set_mode(pll->nid, PM_PLL_MODE_INTEGER);
}
/**
@@ -3172,3 +3164,20 @@ enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
return PM_RET_SUCCESS;
}
+
+/**
+ * pm_clock_id_is_valid() - Check if given clock ID is valid
+ * @clock_id ID of the clock to be checked
+ *
+ * @return Returns success if clock_id is valid, otherwise an error
+ */
+enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id)
+{
+ 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;
+
+ return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
index 3a70036f..ab7a8a40 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -274,6 +274,8 @@ enum {
#define TYPE_DIV2 5U
#define TYPE_GATE 6U
+struct pm_pll;
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_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);
@@ -291,8 +293,9 @@ enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id,
enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
enum pm_node_id *node_id);
+enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id);
-enum pm_ret_status pm_api_clock_enable(unsigned int clock_id);
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll);
enum pm_ret_status pm_api_clock_disable(unsigned int clock_id);
enum pm_ret_status pm_api_clock_getstate(unsigned int clock_id,
unsigned int *state);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 171c7e6c..e33761c8 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -844,18 +844,56 @@ static enum pm_ret_status pm_clock_get_attributes(unsigned int clock_id,
}
/**
+ * pm_clock_gate() - Configure clock gate
+ * @clock_id Id of the clock to be configured
+ * @enable Flag 0=disable (gate the clock), !0=enable (activate the clock)
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+static enum pm_ret_status pm_clock_gate(unsigned int clock_id,
+ unsigned char enable)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ enum pm_ret_status status;
+ enum pm_api_id api_id;
+
+ /* Check if clock ID is valid and return an error if it is not */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS)
+ return status;
+
+ if (enable)
+ api_id = PM_CLOCK_ENABLE;
+ else
+ api_id = PM_CLOCK_DISABLE;
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, api_id, clock_id);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
* pm_clock_enable() - Enable the clock for given id
* @clock_id: Id of the clock to be enabled
*
* This function is used by master to enable the clock
* including peripherals and PLL clocks.
*
- * Return: Returns status, either success or error+reason.
+ * @return: Error if an argument is not valid or status as returned by the
+ * pm_clock_gate
*/
-
enum pm_ret_status pm_clock_enable(unsigned int clock_id)
{
- return pm_api_clock_enable(clock_id);
+ struct pm_pll *pll;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll(clock_id);
+ if (pll)
+ return pm_clock_pll_enable(pll);
+
+ /* It's an on-chip clock, PMU should configure clock's gate */
+ return pm_clock_gate(clock_id, 1);
}
/**