xref: /openbmc/linux/drivers/clk/zynqmp/clkc.c (revision a96cbb14)
13fde0e16SJolly Shah // SPDX-License-Identifier: GPL-2.0
23fde0e16SJolly Shah /*
33fde0e16SJolly Shah  * Zynq UltraScale+ MPSoC clock controller
43fde0e16SJolly Shah  *
5c1e846b8SRajan Vaja  *  Copyright (C) 2016-2019 Xilinx
63fde0e16SJolly Shah  *
73fde0e16SJolly Shah  * Based on drivers/clk/zynq/clkc.c
83fde0e16SJolly Shah  */
93fde0e16SJolly Shah 
103fde0e16SJolly Shah #include <linux/bitfield.h>
113fde0e16SJolly Shah #include <linux/clk.h>
123fde0e16SJolly Shah #include <linux/clk-provider.h>
133fde0e16SJolly Shah #include <linux/module.h>
14*a96cbb14SRob Herring #include <linux/of.h>
15*a96cbb14SRob Herring #include <linux/platform_device.h>
163fde0e16SJolly Shah #include <linux/slab.h>
173fde0e16SJolly Shah #include <linux/string.h>
183fde0e16SJolly Shah 
193fde0e16SJolly Shah #include "clk-zynqmp.h"
203fde0e16SJolly Shah 
213fde0e16SJolly Shah #define MAX_PARENT			100
223fde0e16SJolly Shah #define MAX_NODES			6
233fde0e16SJolly Shah #define MAX_NAME_LEN			50
243fde0e16SJolly Shah 
253fde0e16SJolly Shah /* Flags for parents */
263fde0e16SJolly Shah #define PARENT_CLK_SELF			0
273fde0e16SJolly Shah #define PARENT_CLK_NODE1		1
283fde0e16SJolly Shah #define PARENT_CLK_NODE2		2
293fde0e16SJolly Shah #define PARENT_CLK_NODE3		3
303fde0e16SJolly Shah #define PARENT_CLK_NODE4		4
313fde0e16SJolly Shah #define PARENT_CLK_EXTERNAL		5
323fde0e16SJolly Shah 
333fde0e16SJolly Shah #define END_OF_CLK_NAME			"END_OF_CLK"
343fde0e16SJolly Shah #define END_OF_TOPOLOGY_NODE		1
353fde0e16SJolly Shah #define END_OF_PARENTS			1
363fde0e16SJolly Shah #define RESERVED_CLK_NAME		""
373fde0e16SJolly Shah 
385852b136SMichael Tretter #define CLK_GET_NAME_RESP_LEN		16
395852b136SMichael Tretter #define CLK_GET_TOPOLOGY_RESP_WORDS	3
405852b136SMichael Tretter #define CLK_GET_PARENTS_RESP_WORDS	3
415852b136SMichael Tretter #define CLK_GET_ATTR_RESP_WORDS		1
423fde0e16SJolly Shah 
433fde0e16SJolly Shah enum clk_type {
443fde0e16SJolly Shah 	CLK_TYPE_OUTPUT,
453fde0e16SJolly Shah 	CLK_TYPE_EXTERNAL,
463fde0e16SJolly Shah };
473fde0e16SJolly Shah 
483fde0e16SJolly Shah /**
493fde0e16SJolly Shah  * struct clock_parent - Clock parent
503fde0e16SJolly Shah  * @name:	Parent name
513fde0e16SJolly Shah  * @id:		Parent clock ID
523fde0e16SJolly Shah  * @flag:	Parent flags
533fde0e16SJolly Shah  */
543fde0e16SJolly Shah struct clock_parent {
553fde0e16SJolly Shah 	char name[MAX_NAME_LEN];
563fde0e16SJolly Shah 	int id;
573fde0e16SJolly Shah 	u32 flag;
583fde0e16SJolly Shah };
593fde0e16SJolly Shah 
603fde0e16SJolly Shah /**
613fde0e16SJolly Shah  * struct zynqmp_clock - Clock
623fde0e16SJolly Shah  * @clk_name:		Clock name
633fde0e16SJolly Shah  * @valid:		Validity flag of clock
643fde0e16SJolly Shah  * @type:		Clock type (Output/External)
653fde0e16SJolly Shah  * @node:		Clock topology nodes
663fde0e16SJolly Shah  * @num_nodes:		Number of nodes present in topology
673fde0e16SJolly Shah  * @parent:		Parent of clock
683fde0e16SJolly Shah  * @num_parents:	Number of parents of clock
69d3e4ebc1SRajan Vaja  * @clk_id:		Clock id
703fde0e16SJolly Shah  */
713fde0e16SJolly Shah struct zynqmp_clock {
723fde0e16SJolly Shah 	char clk_name[MAX_NAME_LEN];
733fde0e16SJolly Shah 	u32 valid;
743fde0e16SJolly Shah 	enum clk_type type;
753fde0e16SJolly Shah 	struct clock_topology node[MAX_NODES];
763fde0e16SJolly Shah 	u32 num_nodes;
773fde0e16SJolly Shah 	struct clock_parent parent[MAX_PARENT];
783fde0e16SJolly Shah 	u32 num_parents;
79d3e4ebc1SRajan Vaja 	u32 clk_id;
803fde0e16SJolly Shah };
813fde0e16SJolly Shah 
825852b136SMichael Tretter struct name_resp {
835852b136SMichael Tretter 	char name[CLK_GET_NAME_RESP_LEN];
845852b136SMichael Tretter };
855852b136SMichael Tretter 
865852b136SMichael Tretter struct topology_resp {
875852b136SMichael Tretter #define CLK_TOPOLOGY_TYPE		GENMASK(3, 0)
88e605fa9cSRajan Vaja #define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS	GENMASK(7, 4)
895852b136SMichael Tretter #define CLK_TOPOLOGY_FLAGS		GENMASK(23, 8)
905852b136SMichael Tretter #define CLK_TOPOLOGY_TYPE_FLAGS		GENMASK(31, 24)
915852b136SMichael Tretter 	u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS];
925852b136SMichael Tretter };
935852b136SMichael Tretter 
945852b136SMichael Tretter struct parents_resp {
955852b136SMichael Tretter #define NA_PARENT			0xFFFFFFFF
965852b136SMichael Tretter #define DUMMY_PARENT			0xFFFFFFFE
975852b136SMichael Tretter #define CLK_PARENTS_ID			GENMASK(15, 0)
985852b136SMichael Tretter #define CLK_PARENTS_FLAGS		GENMASK(31, 16)
995852b136SMichael Tretter 	u32 parents[CLK_GET_PARENTS_RESP_WORDS];
1005852b136SMichael Tretter };
1015852b136SMichael Tretter 
1025852b136SMichael Tretter struct attr_resp {
1035852b136SMichael Tretter #define CLK_ATTR_VALID			BIT(0)
1045852b136SMichael Tretter #define CLK_ATTR_TYPE			BIT(2)
1055852b136SMichael Tretter #define CLK_ATTR_NODE_INDEX		GENMASK(13, 0)
1065852b136SMichael Tretter #define CLK_ATTR_NODE_TYPE		GENMASK(19, 14)
1075852b136SMichael Tretter #define CLK_ATTR_NODE_SUBCLASS		GENMASK(25, 20)
1085852b136SMichael Tretter #define CLK_ATTR_NODE_CLASS		GENMASK(31, 26)
1095852b136SMichael Tretter 	u32 attr[CLK_GET_ATTR_RESP_WORDS];
1105852b136SMichael Tretter };
1115852b136SMichael Tretter 
1123fde0e16SJolly Shah static const char clk_type_postfix[][10] = {
1133fde0e16SJolly Shah 	[TYPE_INVALID] = "",
1143fde0e16SJolly Shah 	[TYPE_MUX] = "_mux",
1153fde0e16SJolly Shah 	[TYPE_GATE] = "",
1163fde0e16SJolly Shah 	[TYPE_DIV1] = "_div1",
1173fde0e16SJolly Shah 	[TYPE_DIV2] = "_div2",
1183fde0e16SJolly Shah 	[TYPE_FIXEDFACTOR] = "_ff",
1193fde0e16SJolly Shah 	[TYPE_PLL] = ""
1203fde0e16SJolly Shah };
1213fde0e16SJolly Shah 
1223fde0e16SJolly Shah static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id,
1233fde0e16SJolly Shah 					const char * const *parents,
1243fde0e16SJolly Shah 					u8 num_parents,
1253fde0e16SJolly Shah 					const struct clock_topology *nodes)
1263fde0e16SJolly Shah 					= {
1273fde0e16SJolly Shah 	[TYPE_INVALID] = NULL,
1283fde0e16SJolly Shah 	[TYPE_MUX] = zynqmp_clk_register_mux,
1293fde0e16SJolly Shah 	[TYPE_PLL] = zynqmp_clk_register_pll,
1303fde0e16SJolly Shah 	[TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor,
1313fde0e16SJolly Shah 	[TYPE_DIV1] = zynqmp_clk_register_divider,
1323fde0e16SJolly Shah 	[TYPE_DIV2] = zynqmp_clk_register_divider,
1333fde0e16SJolly Shah 	[TYPE_GATE] = zynqmp_clk_register_gate
1343fde0e16SJolly Shah };
1353fde0e16SJolly Shah 
1363fde0e16SJolly Shah static struct zynqmp_clock *clock;
1373fde0e16SJolly Shah static struct clk_hw_onecell_data *zynqmp_data;
1383fde0e16SJolly Shah static unsigned int clock_max_idx;
1393fde0e16SJolly Shah 
1403fde0e16SJolly Shah /**
1413fde0e16SJolly Shah  * zynqmp_is_valid_clock() - Check whether clock is valid or not
1423fde0e16SJolly Shah  * @clk_id:	Clock index
1433fde0e16SJolly Shah  *
1443fde0e16SJolly Shah  * Return: 1 if clock is valid, 0 if clock is invalid else error code
1453fde0e16SJolly Shah  */
zynqmp_is_valid_clock(u32 clk_id)1463fde0e16SJolly Shah static inline int zynqmp_is_valid_clock(u32 clk_id)
1473fde0e16SJolly Shah {
1489a43be9cSDan Carpenter 	if (clk_id >= clock_max_idx)
1493fde0e16SJolly Shah 		return -ENODEV;
1503fde0e16SJolly Shah 
1513fde0e16SJolly Shah 	return clock[clk_id].valid;
1523fde0e16SJolly Shah }
1533fde0e16SJolly Shah 
1543fde0e16SJolly Shah /**
1553fde0e16SJolly Shah  * zynqmp_get_clock_name() - Get name of clock from Clock index
1563fde0e16SJolly Shah  * @clk_id:	Clock index
1573fde0e16SJolly Shah  * @clk_name:	Name of clock
1583fde0e16SJolly Shah  *
1593fde0e16SJolly Shah  * Return: 0 on success else error code
1603fde0e16SJolly Shah  */
zynqmp_get_clock_name(u32 clk_id,char * clk_name)1613fde0e16SJolly Shah static int zynqmp_get_clock_name(u32 clk_id, char *clk_name)
1623fde0e16SJolly Shah {
1633fde0e16SJolly Shah 	int ret;
1643fde0e16SJolly Shah 
1653fde0e16SJolly Shah 	ret = zynqmp_is_valid_clock(clk_id);
1663fde0e16SJolly Shah 	if (ret == 1) {
167acc1c732SShubhrajyoti Datta 		strscpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);
1683fde0e16SJolly Shah 		return 0;
1693fde0e16SJolly Shah 	}
1703fde0e16SJolly Shah 
1713fde0e16SJolly Shah 	return ret == 0 ? -EINVAL : ret;
1723fde0e16SJolly Shah }
1733fde0e16SJolly Shah 
1743fde0e16SJolly Shah /**
1753fde0e16SJolly Shah  * zynqmp_get_clock_type() - Get type of clock
1763fde0e16SJolly Shah  * @clk_id:	Clock index
1773fde0e16SJolly Shah  * @type:	Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL
1783fde0e16SJolly Shah  *
1793fde0e16SJolly Shah  * Return: 0 on success else error code
1803fde0e16SJolly Shah  */
zynqmp_get_clock_type(u32 clk_id,u32 * type)1813fde0e16SJolly Shah static int zynqmp_get_clock_type(u32 clk_id, u32 *type)
1823fde0e16SJolly Shah {
1833fde0e16SJolly Shah 	int ret;
1843fde0e16SJolly Shah 
1853fde0e16SJolly Shah 	ret = zynqmp_is_valid_clock(clk_id);
1863fde0e16SJolly Shah 	if (ret == 1) {
1873fde0e16SJolly Shah 		*type = clock[clk_id].type;
1883fde0e16SJolly Shah 		return 0;
1893fde0e16SJolly Shah 	}
1903fde0e16SJolly Shah 
1913fde0e16SJolly Shah 	return ret == 0 ? -EINVAL : ret;
1923fde0e16SJolly Shah }
1933fde0e16SJolly Shah 
1943fde0e16SJolly Shah /**
1953fde0e16SJolly Shah  * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system
1963fde0e16SJolly Shah  * @nclocks:	Number of clocks in system/board.
1973fde0e16SJolly Shah  *
1983fde0e16SJolly Shah  * Call firmware API to get number of clocks.
1993fde0e16SJolly Shah  *
2003fde0e16SJolly Shah  * Return: 0 on success else error code.
2013fde0e16SJolly Shah  */
zynqmp_pm_clock_get_num_clocks(u32 * nclocks)2023fde0e16SJolly Shah static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks)
2033fde0e16SJolly Shah {
2043fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
2053fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
2063fde0e16SJolly Shah 	int ret;
2073fde0e16SJolly Shah 
2083fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS;
2093fde0e16SJolly Shah 
2106366c1baSRajan Vaja 	ret = zynqmp_pm_query_data(qdata, ret_payload);
2113fde0e16SJolly Shah 	*nclocks = ret_payload[1];
2123fde0e16SJolly Shah 
2133fde0e16SJolly Shah 	return ret;
2143fde0e16SJolly Shah }
2153fde0e16SJolly Shah 
2163fde0e16SJolly Shah /**
2173fde0e16SJolly Shah  * zynqmp_pm_clock_get_name() - Get the name of clock for given id
2183fde0e16SJolly Shah  * @clock_id:	ID of the clock to be queried
2195852b136SMichael Tretter  * @response:	Name of the clock with the given id
2203fde0e16SJolly Shah  *
2213fde0e16SJolly Shah  * This function is used to get name of clock specified by given
2223fde0e16SJolly Shah  * clock ID.
2233fde0e16SJolly Shah  *
2248bdb15cdSShubhrajyoti Datta  * Return: 0 on success else error+reason
2253fde0e16SJolly Shah  */
zynqmp_pm_clock_get_name(u32 clock_id,struct name_resp * response)2265852b136SMichael Tretter static int zynqmp_pm_clock_get_name(u32 clock_id,
2275852b136SMichael Tretter 				    struct name_resp *response)
2283fde0e16SJolly Shah {
2293fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
2303fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
2318bdb15cdSShubhrajyoti Datta 	int ret;
2323fde0e16SJolly Shah 
2333fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_NAME;
2343fde0e16SJolly Shah 	qdata.arg1 = clock_id;
2353fde0e16SJolly Shah 
2368bdb15cdSShubhrajyoti Datta 	ret = zynqmp_pm_query_data(qdata, ret_payload);
2378bdb15cdSShubhrajyoti Datta 	if (ret)
2388bdb15cdSShubhrajyoti Datta 		return ret;
2398bdb15cdSShubhrajyoti Datta 
2405852b136SMichael Tretter 	memcpy(response, ret_payload, sizeof(*response));
2413fde0e16SJolly Shah 
2423fde0e16SJolly Shah 	return 0;
2433fde0e16SJolly Shah }
2443fde0e16SJolly Shah 
2453fde0e16SJolly Shah /**
2463fde0e16SJolly Shah  * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id
2473fde0e16SJolly Shah  * @clock_id:	ID of the clock to be queried
2483fde0e16SJolly Shah  * @index:	Node index of clock topology
2495852b136SMichael Tretter  * @response:	Buffer used for the topology response
2503fde0e16SJolly Shah  *
2513fde0e16SJolly Shah  * This function is used to get topology information for the clock
2523fde0e16SJolly Shah  * specified by given clock ID.
2533fde0e16SJolly Shah  *
2543fde0e16SJolly Shah  * This API will return 3 node of topology with a single response. To get
2553fde0e16SJolly Shah  * other nodes, master should call same API in loop with new
2563fde0e16SJolly Shah  * index till error is returned. E.g First call should have
2573fde0e16SJolly Shah  * index 0 which will return nodes 0,1 and 2. Next call, index
2583fde0e16SJolly Shah  * should be 3 which will return nodes 3,4 and 5 and so on.
2593fde0e16SJolly Shah  *
2603fde0e16SJolly Shah  * Return: 0 on success else error+reason
2613fde0e16SJolly Shah  */
zynqmp_pm_clock_get_topology(u32 clock_id,u32 index,struct topology_resp * response)2625852b136SMichael Tretter static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index,
2635852b136SMichael Tretter 					struct topology_resp *response)
2643fde0e16SJolly Shah {
2653fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
2663fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
2673fde0e16SJolly Shah 	int ret;
2683fde0e16SJolly Shah 
2693fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;
2703fde0e16SJolly Shah 	qdata.arg1 = clock_id;
2713fde0e16SJolly Shah 	qdata.arg2 = index;
2723fde0e16SJolly Shah 
2736366c1baSRajan Vaja 	ret = zynqmp_pm_query_data(qdata, ret_payload);
2745852b136SMichael Tretter 	memcpy(response, &ret_payload[1], sizeof(*response));
2753fde0e16SJolly Shah 
2763fde0e16SJolly Shah 	return ret;
2773fde0e16SJolly Shah }
2783fde0e16SJolly Shah 
zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag)279610a5d83SRajan Vaja unsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag)
280610a5d83SRajan Vaja {
281610a5d83SRajan Vaja 	unsigned long ccf_flag = 0;
282610a5d83SRajan Vaja 
283610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_GATE)
284610a5d83SRajan Vaja 		ccf_flag |= CLK_SET_RATE_GATE;
285610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_SET_PARENT_GATE)
286610a5d83SRajan Vaja 		ccf_flag |= CLK_SET_PARENT_GATE;
287610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_PARENT)
288610a5d83SRajan Vaja 		ccf_flag |= CLK_SET_RATE_PARENT;
289610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_IGNORE_UNUSED)
290610a5d83SRajan Vaja 		ccf_flag |= CLK_IGNORE_UNUSED;
291610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_NO_REPARENT)
292610a5d83SRajan Vaja 		ccf_flag |= CLK_SET_RATE_NO_REPARENT;
293610a5d83SRajan Vaja 	if (zynqmp_flag & ZYNQMP_CLK_IS_CRITICAL)
294610a5d83SRajan Vaja 		ccf_flag |= CLK_IS_CRITICAL;
295610a5d83SRajan Vaja 
296610a5d83SRajan Vaja 	return ccf_flag;
297610a5d83SRajan Vaja }
298610a5d83SRajan Vaja 
2993fde0e16SJolly Shah /**
3003fde0e16SJolly Shah  * zynqmp_clk_register_fixed_factor() - Register fixed factor with the
3013fde0e16SJolly Shah  *					clock framework
3023fde0e16SJolly Shah  * @name:		Name of this clock
3033fde0e16SJolly Shah  * @clk_id:		Clock ID
3043fde0e16SJolly Shah  * @parents:		Name of this clock's parents
3053fde0e16SJolly Shah  * @num_parents:	Number of parents
3063fde0e16SJolly Shah  * @nodes:		Clock topology node
3073fde0e16SJolly Shah  *
3083fde0e16SJolly Shah  * Return: clock hardware to the registered clock
3093fde0e16SJolly Shah  */
zynqmp_clk_register_fixed_factor(const char * name,u32 clk_id,const char * const * parents,u8 num_parents,const struct clock_topology * nodes)3103fde0e16SJolly Shah struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
3113fde0e16SJolly Shah 					const char * const *parents,
3123fde0e16SJolly Shah 					u8 num_parents,
3133fde0e16SJolly Shah 					const struct clock_topology *nodes)
3143fde0e16SJolly Shah {
3153fde0e16SJolly Shah 	u32 mult, div;
3163fde0e16SJolly Shah 	struct clk_hw *hw;
3173fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
3183fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
3193fde0e16SJolly Shah 	int ret;
320610a5d83SRajan Vaja 	unsigned long flag;
3213fde0e16SJolly Shah 
3223fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
3233fde0e16SJolly Shah 	qdata.arg1 = clk_id;
3243fde0e16SJolly Shah 
3256366c1baSRajan Vaja 	ret = zynqmp_pm_query_data(qdata, ret_payload);
32627c0f2b0SRajan Vaja 	if (ret)
32727c0f2b0SRajan Vaja 		return ERR_PTR(ret);
32827c0f2b0SRajan Vaja 
3293fde0e16SJolly Shah 	mult = ret_payload[1];
3303fde0e16SJolly Shah 	div = ret_payload[2];
3313fde0e16SJolly Shah 
332610a5d83SRajan Vaja 	flag = zynqmp_clk_map_common_ccf_flags(nodes->flag);
333610a5d83SRajan Vaja 
3343fde0e16SJolly Shah 	hw = clk_hw_register_fixed_factor(NULL, name,
3353fde0e16SJolly Shah 					  parents[0],
336610a5d83SRajan Vaja 					  flag, mult,
3373fde0e16SJolly Shah 					  div);
3383fde0e16SJolly Shah 
3393fde0e16SJolly Shah 	return hw;
3403fde0e16SJolly Shah }
3413fde0e16SJolly Shah 
3423fde0e16SJolly Shah /**
3433fde0e16SJolly Shah  * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id
3443fde0e16SJolly Shah  * @clock_id:	Clock ID
3453fde0e16SJolly Shah  * @index:	Parent index
3465852b136SMichael Tretter  * @response:	Parents of the given clock
3473fde0e16SJolly Shah  *
3483fde0e16SJolly Shah  * This function is used to get 3 parents for the clock specified by
3493fde0e16SJolly Shah  * given clock ID.
3503fde0e16SJolly Shah  *
3513fde0e16SJolly Shah  * This API will return 3 parents with a single response. To get
3523fde0e16SJolly Shah  * other parents, master should call same API in loop with new
3533fde0e16SJolly Shah  * parent index till error is returned. E.g First call should have
3543fde0e16SJolly Shah  * index 0 which will return parents 0,1 and 2. Next call, index
3553fde0e16SJolly Shah  * should be 3 which will return parent 3,4 and 5 and so on.
3563fde0e16SJolly Shah  *
3573fde0e16SJolly Shah  * Return: 0 on success else error+reason
3583fde0e16SJolly Shah  */
zynqmp_pm_clock_get_parents(u32 clock_id,u32 index,struct parents_resp * response)3595852b136SMichael Tretter static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index,
3605852b136SMichael Tretter 				       struct parents_resp *response)
3613fde0e16SJolly Shah {
3623fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
3633fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
3643fde0e16SJolly Shah 	int ret;
3653fde0e16SJolly Shah 
3663fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_PARENTS;
3673fde0e16SJolly Shah 	qdata.arg1 = clock_id;
3683fde0e16SJolly Shah 	qdata.arg2 = index;
3693fde0e16SJolly Shah 
3706366c1baSRajan Vaja 	ret = zynqmp_pm_query_data(qdata, ret_payload);
3715852b136SMichael Tretter 	memcpy(response, &ret_payload[1], sizeof(*response));
3723fde0e16SJolly Shah 
3733fde0e16SJolly Shah 	return ret;
3743fde0e16SJolly Shah }
3753fde0e16SJolly Shah 
3763fde0e16SJolly Shah /**
3773fde0e16SJolly Shah  * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id
3783fde0e16SJolly Shah  * @clock_id:	Clock ID
3795852b136SMichael Tretter  * @response:	Clock attributes response
3803fde0e16SJolly Shah  *
3813fde0e16SJolly Shah  * This function is used to get clock's attributes(e.g. valid, clock type, etc).
3823fde0e16SJolly Shah  *
3833fde0e16SJolly Shah  * Return: 0 on success else error+reason
3843fde0e16SJolly Shah  */
zynqmp_pm_clock_get_attributes(u32 clock_id,struct attr_resp * response)3855852b136SMichael Tretter static int zynqmp_pm_clock_get_attributes(u32 clock_id,
3865852b136SMichael Tretter 					  struct attr_resp *response)
3873fde0e16SJolly Shah {
3883fde0e16SJolly Shah 	struct zynqmp_pm_query_data qdata = {0};
3893fde0e16SJolly Shah 	u32 ret_payload[PAYLOAD_ARG_CNT];
3903fde0e16SJolly Shah 	int ret;
3913fde0e16SJolly Shah 
3923fde0e16SJolly Shah 	qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;
3933fde0e16SJolly Shah 	qdata.arg1 = clock_id;
3943fde0e16SJolly Shah 
3956366c1baSRajan Vaja 	ret = zynqmp_pm_query_data(qdata, ret_payload);
3965852b136SMichael Tretter 	memcpy(response, &ret_payload[1], sizeof(*response));
3973fde0e16SJolly Shah 
3983fde0e16SJolly Shah 	return ret;
3993fde0e16SJolly Shah }
4003fde0e16SJolly Shah 
4013fde0e16SJolly Shah /**
4023fde0e16SJolly Shah  * __zynqmp_clock_get_topology() - Get topology data of clock from firmware
4033fde0e16SJolly Shah  *				   response data
4043fde0e16SJolly Shah  * @topology:		Clock topology
4055852b136SMichael Tretter  * @response:		Clock topology data received from firmware
4063fde0e16SJolly Shah  * @nnodes:		Number of nodes
4073fde0e16SJolly Shah  *
4083fde0e16SJolly Shah  * Return: 0 on success else error+reason
4093fde0e16SJolly Shah  */
__zynqmp_clock_get_topology(struct clock_topology * topology,struct topology_resp * response,u32 * nnodes)4103fde0e16SJolly Shah static int __zynqmp_clock_get_topology(struct clock_topology *topology,
4115852b136SMichael Tretter 				       struct topology_resp *response,
4125852b136SMichael Tretter 				       u32 *nnodes)
4133fde0e16SJolly Shah {
4143fde0e16SJolly Shah 	int i;
4155852b136SMichael Tretter 	u32 type;
4163fde0e16SJolly Shah 
4175852b136SMichael Tretter 	for (i = 0; i < ARRAY_SIZE(response->topology); i++) {
4185852b136SMichael Tretter 		type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]);
4195852b136SMichael Tretter 		if (type == TYPE_INVALID)
4203fde0e16SJolly Shah 			return END_OF_TOPOLOGY_NODE;
4215852b136SMichael Tretter 		topology[*nnodes].type = type;
4225852b136SMichael Tretter 		topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS,
4235852b136SMichael Tretter 						   response->topology[i]);
4243fde0e16SJolly Shah 		topology[*nnodes].type_flag =
4255852b136SMichael Tretter 				FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS,
4265852b136SMichael Tretter 					  response->topology[i]);
427e605fa9cSRajan Vaja 		topology[*nnodes].custom_type_flag =
428e605fa9cSRajan Vaja 			FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS,
429e605fa9cSRajan Vaja 				  response->topology[i]);
4303fde0e16SJolly Shah 		(*nnodes)++;
4313fde0e16SJolly Shah 	}
4323fde0e16SJolly Shah 
4333fde0e16SJolly Shah 	return 0;
4343fde0e16SJolly Shah }
4353fde0e16SJolly Shah 
4363fde0e16SJolly Shah /**
4373fde0e16SJolly Shah  * zynqmp_clock_get_topology() - Get topology of clock from firmware using
4383fde0e16SJolly Shah  *				 PM_API
4393fde0e16SJolly Shah  * @clk_id:		Clock index
4403fde0e16SJolly Shah  * @topology:		Clock topology
4413fde0e16SJolly Shah  * @num_nodes:		Number of nodes
4423fde0e16SJolly Shah  *
4433fde0e16SJolly Shah  * Return: 0 on success else error+reason
4443fde0e16SJolly Shah  */
zynqmp_clock_get_topology(u32 clk_id,struct clock_topology * topology,u32 * num_nodes)4453fde0e16SJolly Shah static int zynqmp_clock_get_topology(u32 clk_id,
4463fde0e16SJolly Shah 				     struct clock_topology *topology,
4473fde0e16SJolly Shah 				     u32 *num_nodes)
4483fde0e16SJolly Shah {
4493fde0e16SJolly Shah 	int j, ret;
4505852b136SMichael Tretter 	struct topology_resp response = { };
4513fde0e16SJolly Shah 
4523fde0e16SJolly Shah 	*num_nodes = 0;
4535852b136SMichael Tretter 	for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) {
454d3e4ebc1SRajan Vaja 		ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j,
4555852b136SMichael Tretter 						   &response);
4563fde0e16SJolly Shah 		if (ret)
4573fde0e16SJolly Shah 			return ret;
4585852b136SMichael Tretter 		ret = __zynqmp_clock_get_topology(topology, &response,
4595852b136SMichael Tretter 						  num_nodes);
4603fde0e16SJolly Shah 		if (ret == END_OF_TOPOLOGY_NODE)
4613fde0e16SJolly Shah 			return 0;
4623fde0e16SJolly Shah 	}
4633fde0e16SJolly Shah 
4643fde0e16SJolly Shah 	return 0;
4653fde0e16SJolly Shah }
4663fde0e16SJolly Shah 
4673fde0e16SJolly Shah /**
4685e088faeSMichael Tretter  * __zynqmp_clock_get_parents() - Get parents info of clock from firmware
4693fde0e16SJolly Shah  *				   response data
4703fde0e16SJolly Shah  * @parents:		Clock parents
4715852b136SMichael Tretter  * @response:		Clock parents data received from firmware
4723fde0e16SJolly Shah  * @nparent:		Number of parent
4733fde0e16SJolly Shah  *
4743fde0e16SJolly Shah  * Return: 0 on success else error+reason
4753fde0e16SJolly Shah  */
__zynqmp_clock_get_parents(struct clock_parent * parents,struct parents_resp * response,u32 * nparent)4765852b136SMichael Tretter static int __zynqmp_clock_get_parents(struct clock_parent *parents,
4775852b136SMichael Tretter 				      struct parents_resp *response,
4783fde0e16SJolly Shah 				      u32 *nparent)
4793fde0e16SJolly Shah {
4803fde0e16SJolly Shah 	int i;
4813fde0e16SJolly Shah 	struct clock_parent *parent;
4823fde0e16SJolly Shah 
4835852b136SMichael Tretter 	for (i = 0; i < ARRAY_SIZE(response->parents); i++) {
4845852b136SMichael Tretter 		if (response->parents[i] == NA_PARENT)
4853fde0e16SJolly Shah 			return END_OF_PARENTS;
4863fde0e16SJolly Shah 
4873fde0e16SJolly Shah 		parent = &parents[i];
4885852b136SMichael Tretter 		parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]);
4895852b136SMichael Tretter 		if (response->parents[i] == DUMMY_PARENT) {
4903fde0e16SJolly Shah 			strcpy(parent->name, "dummy_name");
4913fde0e16SJolly Shah 			parent->flag = 0;
4923fde0e16SJolly Shah 		} else {
4935852b136SMichael Tretter 			parent->flag = FIELD_GET(CLK_PARENTS_FLAGS,
4945852b136SMichael Tretter 						 response->parents[i]);
4953fde0e16SJolly Shah 			if (zynqmp_get_clock_name(parent->id, parent->name))
4963fde0e16SJolly Shah 				continue;
4973fde0e16SJolly Shah 		}
4983fde0e16SJolly Shah 		*nparent += 1;
4993fde0e16SJolly Shah 	}
5003fde0e16SJolly Shah 
5013fde0e16SJolly Shah 	return 0;
5023fde0e16SJolly Shah }
5033fde0e16SJolly Shah 
5043fde0e16SJolly Shah /**
5053fde0e16SJolly Shah  * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API
5063fde0e16SJolly Shah  * @clk_id:		Clock index
5073fde0e16SJolly Shah  * @parents:		Clock parents
5083fde0e16SJolly Shah  * @num_parents:	Total number of parents
5093fde0e16SJolly Shah  *
5103fde0e16SJolly Shah  * Return: 0 on success else error+reason
5113fde0e16SJolly Shah  */
zynqmp_clock_get_parents(u32 clk_id,struct clock_parent * parents,u32 * num_parents)5123fde0e16SJolly Shah static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents,
5133fde0e16SJolly Shah 				    u32 *num_parents)
5143fde0e16SJolly Shah {
5153fde0e16SJolly Shah 	int j = 0, ret;
5165852b136SMichael Tretter 	struct parents_resp response = { };
5173fde0e16SJolly Shah 
5183fde0e16SJolly Shah 	*num_parents = 0;
5193fde0e16SJolly Shah 	do {
5203fde0e16SJolly Shah 		/* Get parents from firmware */
521d3e4ebc1SRajan Vaja 		ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j,
5225852b136SMichael Tretter 						  &response);
5233fde0e16SJolly Shah 		if (ret)
5243fde0e16SJolly Shah 			return ret;
5253fde0e16SJolly Shah 
5265852b136SMichael Tretter 		ret = __zynqmp_clock_get_parents(&parents[j], &response,
5273fde0e16SJolly Shah 						 num_parents);
5283fde0e16SJolly Shah 		if (ret == END_OF_PARENTS)
5293fde0e16SJolly Shah 			return 0;
5305852b136SMichael Tretter 		j += ARRAY_SIZE(response.parents);
5313fde0e16SJolly Shah 	} while (*num_parents <= MAX_PARENT);
5323fde0e16SJolly Shah 
5333fde0e16SJolly Shah 	return 0;
5343fde0e16SJolly Shah }
5353fde0e16SJolly Shah 
5363fde0e16SJolly Shah /**
5373fde0e16SJolly Shah  * zynqmp_get_parent_list() - Create list of parents name
5383fde0e16SJolly Shah  * @np:			Device node
5393fde0e16SJolly Shah  * @clk_id:		Clock index
5403fde0e16SJolly Shah  * @parent_list:	List of parent's name
5413fde0e16SJolly Shah  * @num_parents:	Total number of parents
5423fde0e16SJolly Shah  *
5433fde0e16SJolly Shah  * Return: 0 on success else error+reason
5443fde0e16SJolly Shah  */
zynqmp_get_parent_list(struct device_node * np,u32 clk_id,const char ** parent_list,u32 * num_parents)5453fde0e16SJolly Shah static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id,
5463fde0e16SJolly Shah 				  const char **parent_list, u32 *num_parents)
5473fde0e16SJolly Shah {
5483fde0e16SJolly Shah 	int i = 0, ret;
5493fde0e16SJolly Shah 	u32 total_parents = clock[clk_id].num_parents;
5503fde0e16SJolly Shah 	struct clock_topology *clk_nodes;
5513fde0e16SJolly Shah 	struct clock_parent *parents;
5523fde0e16SJolly Shah 
5533fde0e16SJolly Shah 	clk_nodes = clock[clk_id].node;
5543fde0e16SJolly Shah 	parents = clock[clk_id].parent;
5553fde0e16SJolly Shah 
5563fde0e16SJolly Shah 	for (i = 0; i < total_parents; i++) {
5573fde0e16SJolly Shah 		if (!parents[i].flag) {
5583fde0e16SJolly Shah 			parent_list[i] = parents[i].name;
5593fde0e16SJolly Shah 		} else if (parents[i].flag == PARENT_CLK_EXTERNAL) {
5603fde0e16SJolly Shah 			ret = of_property_match_string(np, "clock-names",
5613fde0e16SJolly Shah 						       parents[i].name);
5623fde0e16SJolly Shah 			if (ret < 0)
5633fde0e16SJolly Shah 				strcpy(parents[i].name, "dummy_name");
5643fde0e16SJolly Shah 			parent_list[i] = parents[i].name;
5653fde0e16SJolly Shah 		} else {
5663fde0e16SJolly Shah 			strcat(parents[i].name,
5673fde0e16SJolly Shah 			       clk_type_postfix[clk_nodes[parents[i].flag - 1].
5683fde0e16SJolly Shah 			       type]);
5693fde0e16SJolly Shah 			parent_list[i] = parents[i].name;
5703fde0e16SJolly Shah 		}
5713fde0e16SJolly Shah 	}
5723fde0e16SJolly Shah 
5733fde0e16SJolly Shah 	*num_parents = total_parents;
5743fde0e16SJolly Shah 	return 0;
5753fde0e16SJolly Shah }
5763fde0e16SJolly Shah 
5773fde0e16SJolly Shah /**
5783fde0e16SJolly Shah  * zynqmp_register_clk_topology() - Register clock topology
5793fde0e16SJolly Shah  * @clk_id:		Clock index
5803fde0e16SJolly Shah  * @clk_name:		Clock Name
5813fde0e16SJolly Shah  * @num_parents:	Total number of parents
5823fde0e16SJolly Shah  * @parent_names:	List of parents name
5833fde0e16SJolly Shah  *
5843fde0e16SJolly Shah  * Return: Returns either clock hardware or error+reason
5853fde0e16SJolly Shah  */
zynqmp_register_clk_topology(int clk_id,char * clk_name,int num_parents,const char ** parent_names)5863fde0e16SJolly Shah static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
5873fde0e16SJolly Shah 						   int num_parents,
5883fde0e16SJolly Shah 						   const char **parent_names)
5893fde0e16SJolly Shah {
5903fde0e16SJolly Shah 	int j;
591d3e4ebc1SRajan Vaja 	u32 num_nodes, clk_dev_id;
59258b0fb86SQuanyang Wang 	char *clk_out[MAX_NODES];
5933fde0e16SJolly Shah 	struct clock_topology *nodes;
5943fde0e16SJolly Shah 	struct clk_hw *hw = NULL;
5953fde0e16SJolly Shah 
5963fde0e16SJolly Shah 	nodes = clock[clk_id].node;
5973fde0e16SJolly Shah 	num_nodes = clock[clk_id].num_nodes;
598d3e4ebc1SRajan Vaja 	clk_dev_id = clock[clk_id].clk_id;
5993fde0e16SJolly Shah 
6003fde0e16SJolly Shah 	for (j = 0; j < num_nodes; j++) {
6013fde0e16SJolly Shah 		/*
6023fde0e16SJolly Shah 		 * Clock name received from firmware is output clock name.
6033fde0e16SJolly Shah 		 * Intermediate clock names are postfixed with type of clock.
6043fde0e16SJolly Shah 		 */
6053fde0e16SJolly Shah 		if (j != (num_nodes - 1)) {
60658b0fb86SQuanyang Wang 			clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name,
6073fde0e16SJolly Shah 					    clk_type_postfix[nodes[j].type]);
6083fde0e16SJolly Shah 		} else {
60958b0fb86SQuanyang Wang 			clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name);
6103fde0e16SJolly Shah 		}
6113fde0e16SJolly Shah 
6123fde0e16SJolly Shah 		if (!clk_topology[nodes[j].type])
6133fde0e16SJolly Shah 			continue;
6143fde0e16SJolly Shah 
61558b0fb86SQuanyang Wang 		hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id,
6163fde0e16SJolly Shah 						    parent_names,
6173fde0e16SJolly Shah 						    num_parents,
6183fde0e16SJolly Shah 						    &nodes[j]);
6193fde0e16SJolly Shah 		if (IS_ERR(hw))
620d3e4ebc1SRajan Vaja 			pr_warn_once("%s() 0x%x: %s register fail with %ld\n",
621d3e4ebc1SRajan Vaja 				     __func__,  clk_dev_id, clk_name,
622d3e4ebc1SRajan Vaja 				     PTR_ERR(hw));
6233fde0e16SJolly Shah 
62458b0fb86SQuanyang Wang 		parent_names[0] = clk_out[j];
6253fde0e16SJolly Shah 	}
62658b0fb86SQuanyang Wang 
62758b0fb86SQuanyang Wang 	for (j = 0; j < num_nodes; j++)
62858b0fb86SQuanyang Wang 		kfree(clk_out[j]);
62958b0fb86SQuanyang Wang 
6303fde0e16SJolly Shah 	return hw;
6313fde0e16SJolly Shah }
6323fde0e16SJolly Shah 
6333fde0e16SJolly Shah /**
6343fde0e16SJolly Shah  * zynqmp_register_clocks() - Register clocks
6353fde0e16SJolly Shah  * @np:		Device node
6363fde0e16SJolly Shah  *
6373fde0e16SJolly Shah  * Return: 0 on success else error code
6383fde0e16SJolly Shah  */
zynqmp_register_clocks(struct device_node * np)6393fde0e16SJolly Shah static int zynqmp_register_clocks(struct device_node *np)
6403fde0e16SJolly Shah {
6413fde0e16SJolly Shah 	int ret;
6423fde0e16SJolly Shah 	u32 i, total_parents = 0, type = 0;
6433fde0e16SJolly Shah 	const char *parent_names[MAX_PARENT];
6443fde0e16SJolly Shah 
6453fde0e16SJolly Shah 	for (i = 0; i < clock_max_idx; i++) {
6463fde0e16SJolly Shah 		char clk_name[MAX_NAME_LEN];
6473fde0e16SJolly Shah 
6483fde0e16SJolly Shah 		/* get clock name, continue to next clock if name not found */
6493fde0e16SJolly Shah 		if (zynqmp_get_clock_name(i, clk_name))
6503fde0e16SJolly Shah 			continue;
6513fde0e16SJolly Shah 
6523fde0e16SJolly Shah 		/* Check if clock is valid and output clock.
6533fde0e16SJolly Shah 		 * Do not register invalid or external clock.
6543fde0e16SJolly Shah 		 */
6553fde0e16SJolly Shah 		ret = zynqmp_get_clock_type(i, &type);
6563fde0e16SJolly Shah 		if (ret || type != CLK_TYPE_OUTPUT)
6573fde0e16SJolly Shah 			continue;
6583fde0e16SJolly Shah 
6593fde0e16SJolly Shah 		/* Get parents of clock*/
6603fde0e16SJolly Shah 		if (zynqmp_get_parent_list(np, i, parent_names,
6613fde0e16SJolly Shah 					   &total_parents)) {
6623fde0e16SJolly Shah 			WARN_ONCE(1, "No parents found for %s\n",
6633fde0e16SJolly Shah 				  clock[i].clk_name);
6643fde0e16SJolly Shah 			continue;
6653fde0e16SJolly Shah 		}
6663fde0e16SJolly Shah 
6673fde0e16SJolly Shah 		zynqmp_data->hws[i] =
6683fde0e16SJolly Shah 			zynqmp_register_clk_topology(i, clk_name,
6693fde0e16SJolly Shah 						     total_parents,
6703fde0e16SJolly Shah 						     parent_names);
6713fde0e16SJolly Shah 	}
6723fde0e16SJolly Shah 
6733fde0e16SJolly Shah 	for (i = 0; i < clock_max_idx; i++) {
6743fde0e16SJolly Shah 		if (IS_ERR(zynqmp_data->hws[i])) {
6753fde0e16SJolly Shah 			pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",
6763fde0e16SJolly Shah 			       clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i]));
6773fde0e16SJolly Shah 			WARN_ON(1);
6783fde0e16SJolly Shah 		}
6793fde0e16SJolly Shah 	}
6803fde0e16SJolly Shah 	return 0;
6813fde0e16SJolly Shah }
6823fde0e16SJolly Shah 
6833fde0e16SJolly Shah /**
6843fde0e16SJolly Shah  * zynqmp_get_clock_info() - Get clock information from firmware using PM_API
6853fde0e16SJolly Shah  */
zynqmp_get_clock_info(void)6863fde0e16SJolly Shah static void zynqmp_get_clock_info(void)
6873fde0e16SJolly Shah {
6883fde0e16SJolly Shah 	int i, ret;
6895852b136SMichael Tretter 	u32 type = 0;
6905852b136SMichael Tretter 	u32 nodetype, subclass, class;
6915852b136SMichael Tretter 	struct attr_resp attr;
6925852b136SMichael Tretter 	struct name_resp name;
6933fde0e16SJolly Shah 
6943fde0e16SJolly Shah 	for (i = 0; i < clock_max_idx; i++) {
6953fde0e16SJolly Shah 		ret = zynqmp_pm_clock_get_attributes(i, &attr);
6963fde0e16SJolly Shah 		if (ret)
6973fde0e16SJolly Shah 			continue;
6983fde0e16SJolly Shah 
6995852b136SMichael Tretter 		clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]);
7005268aa1cSRajan Vaja 		/* skip query for Invalid clock */
7015268aa1cSRajan Vaja 		ret = zynqmp_is_valid_clock(i);
7025268aa1cSRajan Vaja 		if (ret != CLK_ATTR_VALID)
7035268aa1cSRajan Vaja 			continue;
7045268aa1cSRajan Vaja 
7055852b136SMichael Tretter 		clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ?
706d3e4ebc1SRajan Vaja 			CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT;
707d3e4ebc1SRajan Vaja 
7085852b136SMichael Tretter 		nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]);
7095852b136SMichael Tretter 		subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]);
7105852b136SMichael Tretter 		class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]);
711d3e4ebc1SRajan Vaja 
7125852b136SMichael Tretter 		clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) |
7135852b136SMichael Tretter 				  FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) |
7145852b136SMichael Tretter 				  FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) |
7155852b136SMichael Tretter 				  FIELD_PREP(CLK_ATTR_NODE_INDEX, i);
7165852b136SMichael Tretter 
7175852b136SMichael Tretter 		zynqmp_pm_clock_get_name(clock[i].clk_id, &name);
718dd80fb2dSIan Nam 
719dd80fb2dSIan Nam 		/*
720dd80fb2dSIan Nam 		 * Terminate with NULL character in case name provided by firmware
721dd80fb2dSIan Nam 		 * is longer and truncated due to size limit.
722dd80fb2dSIan Nam 		 */
723dd80fb2dSIan Nam 		name.name[sizeof(name.name) - 1] = '\0';
724dd80fb2dSIan Nam 
7255852b136SMichael Tretter 		if (!strcmp(name.name, RESERVED_CLK_NAME))
7265852b136SMichael Tretter 			continue;
727acc1c732SShubhrajyoti Datta 		strscpy(clock[i].clk_name, name.name, MAX_NAME_LEN);
7283fde0e16SJolly Shah 	}
7293fde0e16SJolly Shah 
7303fde0e16SJolly Shah 	/* Get topology of all clock */
7313fde0e16SJolly Shah 	for (i = 0; i < clock_max_idx; i++) {
7323fde0e16SJolly Shah 		ret = zynqmp_get_clock_type(i, &type);
7333fde0e16SJolly Shah 		if (ret || type != CLK_TYPE_OUTPUT)
7343fde0e16SJolly Shah 			continue;
7353fde0e16SJolly Shah 
7363fde0e16SJolly Shah 		ret = zynqmp_clock_get_topology(i, clock[i].node,
7373fde0e16SJolly Shah 						&clock[i].num_nodes);
7383fde0e16SJolly Shah 		if (ret)
7393fde0e16SJolly Shah 			continue;
7403fde0e16SJolly Shah 
7413fde0e16SJolly Shah 		ret = zynqmp_clock_get_parents(i, clock[i].parent,
7423fde0e16SJolly Shah 					       &clock[i].num_parents);
7433fde0e16SJolly Shah 		if (ret)
7443fde0e16SJolly Shah 			continue;
7453fde0e16SJolly Shah 	}
7463fde0e16SJolly Shah }
7473fde0e16SJolly Shah 
7483fde0e16SJolly Shah /**
7493fde0e16SJolly Shah  * zynqmp_clk_setup() - Setup the clock framework and register clocks
7503fde0e16SJolly Shah  * @np:		Device node
7513fde0e16SJolly Shah  *
7523fde0e16SJolly Shah  * Return: 0 on success else error code
7533fde0e16SJolly Shah  */
zynqmp_clk_setup(struct device_node * np)7543fde0e16SJolly Shah static int zynqmp_clk_setup(struct device_node *np)
7553fde0e16SJolly Shah {
7563fde0e16SJolly Shah 	int ret;
7573fde0e16SJolly Shah 
7583fde0e16SJolly Shah 	ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx);
7593fde0e16SJolly Shah 	if (ret)
7603fde0e16SJolly Shah 		return ret;
7613fde0e16SJolly Shah 
7624f340efcSGustavo A. R. Silva 	zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx),
7634f340efcSGustavo A. R. Silva 			      GFP_KERNEL);
7643fde0e16SJolly Shah 	if (!zynqmp_data)
7653fde0e16SJolly Shah 		return -ENOMEM;
7663fde0e16SJolly Shah 
7673fde0e16SJolly Shah 	clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL);
7683fde0e16SJolly Shah 	if (!clock) {
7693fde0e16SJolly Shah 		kfree(zynqmp_data);
7703fde0e16SJolly Shah 		return -ENOMEM;
7713fde0e16SJolly Shah 	}
7723fde0e16SJolly Shah 
7733fde0e16SJolly Shah 	zynqmp_get_clock_info();
7743fde0e16SJolly Shah 	zynqmp_register_clocks(np);
7753fde0e16SJolly Shah 
7763fde0e16SJolly Shah 	zynqmp_data->num = clock_max_idx;
77747d0fbd1SShubhrajyoti Datta 	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data);
7783fde0e16SJolly Shah }
7793fde0e16SJolly Shah 
zynqmp_clock_probe(struct platform_device * pdev)7803fde0e16SJolly Shah static int zynqmp_clock_probe(struct platform_device *pdev)
7813fde0e16SJolly Shah {
7823fde0e16SJolly Shah 	int ret;
7833fde0e16SJolly Shah 	struct device *dev = &pdev->dev;
7843fde0e16SJolly Shah 
7853fde0e16SJolly Shah 	ret = zynqmp_clk_setup(dev->of_node);
7863fde0e16SJolly Shah 
7873fde0e16SJolly Shah 	return ret;
7883fde0e16SJolly Shah }
7893fde0e16SJolly Shah 
7903fde0e16SJolly Shah static const struct of_device_id zynqmp_clock_of_match[] = {
7913fde0e16SJolly Shah 	{.compatible = "xlnx,zynqmp-clk"},
792c1e846b8SRajan Vaja 	{.compatible = "xlnx,versal-clk"},
7933fde0e16SJolly Shah 	{},
7943fde0e16SJolly Shah };
7953fde0e16SJolly Shah MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match);
7963fde0e16SJolly Shah 
7973fde0e16SJolly Shah static struct platform_driver zynqmp_clock_driver = {
7983fde0e16SJolly Shah 	.driver = {
7993fde0e16SJolly Shah 		.name = "zynqmp_clock",
8003fde0e16SJolly Shah 		.of_match_table = zynqmp_clock_of_match,
8013fde0e16SJolly Shah 	},
8023fde0e16SJolly Shah 	.probe = zynqmp_clock_probe,
8033fde0e16SJolly Shah };
8043fde0e16SJolly Shah module_platform_driver(zynqmp_clock_driver);
805