diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c index 1fab38fac..ee8b38738 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; + /* 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); - /* - * 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); - - 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 3a70036f9..ab7a8a405 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 171c7e6c9..e33761c84 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -843,6 +843,36 @@ static enum pm_ret_status pm_clock_get_attributes(unsigned int clock_id, return pm_api_clock_get_attributes(clock_id, attr); } +/** + * 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 @@ -850,12 +880,20 @@ static enum pm_ret_status pm_clock_get_attributes(unsigned int clock_id, * 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); } /**