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