162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Zynq UltraScale+ MPSoC clock controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2016-2019 Xilinx
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Based on drivers/clk/zynq/clkc.c
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/clk-provider.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "clk-zynqmp.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define MAX_PARENT			100
2262306a36Sopenharmony_ci#define MAX_NODES			6
2362306a36Sopenharmony_ci#define MAX_NAME_LEN			50
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Flags for parents */
2662306a36Sopenharmony_ci#define PARENT_CLK_SELF			0
2762306a36Sopenharmony_ci#define PARENT_CLK_NODE1		1
2862306a36Sopenharmony_ci#define PARENT_CLK_NODE2		2
2962306a36Sopenharmony_ci#define PARENT_CLK_NODE3		3
3062306a36Sopenharmony_ci#define PARENT_CLK_NODE4		4
3162306a36Sopenharmony_ci#define PARENT_CLK_EXTERNAL		5
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define END_OF_CLK_NAME			"END_OF_CLK"
3462306a36Sopenharmony_ci#define END_OF_TOPOLOGY_NODE		1
3562306a36Sopenharmony_ci#define END_OF_PARENTS			1
3662306a36Sopenharmony_ci#define RESERVED_CLK_NAME		""
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define CLK_GET_NAME_RESP_LEN		16
3962306a36Sopenharmony_ci#define CLK_GET_TOPOLOGY_RESP_WORDS	3
4062306a36Sopenharmony_ci#define CLK_GET_PARENTS_RESP_WORDS	3
4162306a36Sopenharmony_ci#define CLK_GET_ATTR_RESP_WORDS		1
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cienum clk_type {
4462306a36Sopenharmony_ci	CLK_TYPE_OUTPUT,
4562306a36Sopenharmony_ci	CLK_TYPE_EXTERNAL,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/**
4962306a36Sopenharmony_ci * struct clock_parent - Clock parent
5062306a36Sopenharmony_ci * @name:	Parent name
5162306a36Sopenharmony_ci * @id:		Parent clock ID
5262306a36Sopenharmony_ci * @flag:	Parent flags
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistruct clock_parent {
5562306a36Sopenharmony_ci	char name[MAX_NAME_LEN];
5662306a36Sopenharmony_ci	int id;
5762306a36Sopenharmony_ci	u32 flag;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/**
6162306a36Sopenharmony_ci * struct zynqmp_clock - Clock
6262306a36Sopenharmony_ci * @clk_name:		Clock name
6362306a36Sopenharmony_ci * @valid:		Validity flag of clock
6462306a36Sopenharmony_ci * @type:		Clock type (Output/External)
6562306a36Sopenharmony_ci * @node:		Clock topology nodes
6662306a36Sopenharmony_ci * @num_nodes:		Number of nodes present in topology
6762306a36Sopenharmony_ci * @parent:		Parent of clock
6862306a36Sopenharmony_ci * @num_parents:	Number of parents of clock
6962306a36Sopenharmony_ci * @clk_id:		Clock id
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistruct zynqmp_clock {
7262306a36Sopenharmony_ci	char clk_name[MAX_NAME_LEN];
7362306a36Sopenharmony_ci	u32 valid;
7462306a36Sopenharmony_ci	enum clk_type type;
7562306a36Sopenharmony_ci	struct clock_topology node[MAX_NODES];
7662306a36Sopenharmony_ci	u32 num_nodes;
7762306a36Sopenharmony_ci	struct clock_parent parent[MAX_PARENT];
7862306a36Sopenharmony_ci	u32 num_parents;
7962306a36Sopenharmony_ci	u32 clk_id;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct name_resp {
8362306a36Sopenharmony_ci	char name[CLK_GET_NAME_RESP_LEN];
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct topology_resp {
8762306a36Sopenharmony_ci#define CLK_TOPOLOGY_TYPE		GENMASK(3, 0)
8862306a36Sopenharmony_ci#define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS	GENMASK(7, 4)
8962306a36Sopenharmony_ci#define CLK_TOPOLOGY_FLAGS		GENMASK(23, 8)
9062306a36Sopenharmony_ci#define CLK_TOPOLOGY_TYPE_FLAGS		GENMASK(31, 24)
9162306a36Sopenharmony_ci	u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS];
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct parents_resp {
9562306a36Sopenharmony_ci#define NA_PARENT			0xFFFFFFFF
9662306a36Sopenharmony_ci#define DUMMY_PARENT			0xFFFFFFFE
9762306a36Sopenharmony_ci#define CLK_PARENTS_ID			GENMASK(15, 0)
9862306a36Sopenharmony_ci#define CLK_PARENTS_FLAGS		GENMASK(31, 16)
9962306a36Sopenharmony_ci	u32 parents[CLK_GET_PARENTS_RESP_WORDS];
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct attr_resp {
10362306a36Sopenharmony_ci#define CLK_ATTR_VALID			BIT(0)
10462306a36Sopenharmony_ci#define CLK_ATTR_TYPE			BIT(2)
10562306a36Sopenharmony_ci#define CLK_ATTR_NODE_INDEX		GENMASK(13, 0)
10662306a36Sopenharmony_ci#define CLK_ATTR_NODE_TYPE		GENMASK(19, 14)
10762306a36Sopenharmony_ci#define CLK_ATTR_NODE_SUBCLASS		GENMASK(25, 20)
10862306a36Sopenharmony_ci#define CLK_ATTR_NODE_CLASS		GENMASK(31, 26)
10962306a36Sopenharmony_ci	u32 attr[CLK_GET_ATTR_RESP_WORDS];
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic const char clk_type_postfix[][10] = {
11362306a36Sopenharmony_ci	[TYPE_INVALID] = "",
11462306a36Sopenharmony_ci	[TYPE_MUX] = "_mux",
11562306a36Sopenharmony_ci	[TYPE_GATE] = "",
11662306a36Sopenharmony_ci	[TYPE_DIV1] = "_div1",
11762306a36Sopenharmony_ci	[TYPE_DIV2] = "_div2",
11862306a36Sopenharmony_ci	[TYPE_FIXEDFACTOR] = "_ff",
11962306a36Sopenharmony_ci	[TYPE_PLL] = ""
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id,
12362306a36Sopenharmony_ci					const char * const *parents,
12462306a36Sopenharmony_ci					u8 num_parents,
12562306a36Sopenharmony_ci					const struct clock_topology *nodes)
12662306a36Sopenharmony_ci					= {
12762306a36Sopenharmony_ci	[TYPE_INVALID] = NULL,
12862306a36Sopenharmony_ci	[TYPE_MUX] = zynqmp_clk_register_mux,
12962306a36Sopenharmony_ci	[TYPE_PLL] = zynqmp_clk_register_pll,
13062306a36Sopenharmony_ci	[TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor,
13162306a36Sopenharmony_ci	[TYPE_DIV1] = zynqmp_clk_register_divider,
13262306a36Sopenharmony_ci	[TYPE_DIV2] = zynqmp_clk_register_divider,
13362306a36Sopenharmony_ci	[TYPE_GATE] = zynqmp_clk_register_gate
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct zynqmp_clock *clock;
13762306a36Sopenharmony_cistatic struct clk_hw_onecell_data *zynqmp_data;
13862306a36Sopenharmony_cistatic unsigned int clock_max_idx;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/**
14162306a36Sopenharmony_ci * zynqmp_is_valid_clock() - Check whether clock is valid or not
14262306a36Sopenharmony_ci * @clk_id:	Clock index
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci * Return: 1 if clock is valid, 0 if clock is invalid else error code
14562306a36Sopenharmony_ci */
14662306a36Sopenharmony_cistatic inline int zynqmp_is_valid_clock(u32 clk_id)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	if (clk_id >= clock_max_idx)
14962306a36Sopenharmony_ci		return -ENODEV;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return clock[clk_id].valid;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * zynqmp_get_clock_name() - Get name of clock from Clock index
15662306a36Sopenharmony_ci * @clk_id:	Clock index
15762306a36Sopenharmony_ci * @clk_name:	Name of clock
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Return: 0 on success else error code
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic int zynqmp_get_clock_name(u32 clk_id, char *clk_name)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	int ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ret = zynqmp_is_valid_clock(clk_id);
16662306a36Sopenharmony_ci	if (ret == 1) {
16762306a36Sopenharmony_ci		strscpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);
16862306a36Sopenharmony_ci		return 0;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return ret == 0 ? -EINVAL : ret;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * zynqmp_get_clock_type() - Get type of clock
17662306a36Sopenharmony_ci * @clk_id:	Clock index
17762306a36Sopenharmony_ci * @type:	Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * Return: 0 on success else error code
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic int zynqmp_get_clock_type(u32 clk_id, u32 *type)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	int ret;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ret = zynqmp_is_valid_clock(clk_id);
18662306a36Sopenharmony_ci	if (ret == 1) {
18762306a36Sopenharmony_ci		*type = clock[clk_id].type;
18862306a36Sopenharmony_ci		return 0;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return ret == 0 ? -EINVAL : ret;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/**
19562306a36Sopenharmony_ci * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system
19662306a36Sopenharmony_ci * @nclocks:	Number of clocks in system/board.
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * Call firmware API to get number of clocks.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Return: 0 on success else error code.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic int zynqmp_pm_clock_get_num_clocks(u32 *nclocks)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
20562306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
20662306a36Sopenharmony_ci	int ret;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
21162306a36Sopenharmony_ci	*nclocks = ret_payload[1];
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return ret;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/**
21762306a36Sopenharmony_ci * zynqmp_pm_clock_get_name() - Get the name of clock for given id
21862306a36Sopenharmony_ci * @clock_id:	ID of the clock to be queried
21962306a36Sopenharmony_ci * @response:	Name of the clock with the given id
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * This function is used to get name of clock specified by given
22262306a36Sopenharmony_ci * clock ID.
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Return: 0 on success else error+reason
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_cistatic int zynqmp_pm_clock_get_name(u32 clock_id,
22762306a36Sopenharmony_ci				    struct name_resp *response)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
23062306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
23162306a36Sopenharmony_ci	int ret;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_NAME;
23462306a36Sopenharmony_ci	qdata.arg1 = clock_id;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
23762306a36Sopenharmony_ci	if (ret)
23862306a36Sopenharmony_ci		return ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	memcpy(response, ret_payload, sizeof(*response));
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return 0;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/**
24662306a36Sopenharmony_ci * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id
24762306a36Sopenharmony_ci * @clock_id:	ID of the clock to be queried
24862306a36Sopenharmony_ci * @index:	Node index of clock topology
24962306a36Sopenharmony_ci * @response:	Buffer used for the topology response
25062306a36Sopenharmony_ci *
25162306a36Sopenharmony_ci * This function is used to get topology information for the clock
25262306a36Sopenharmony_ci * specified by given clock ID.
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * This API will return 3 node of topology with a single response. To get
25562306a36Sopenharmony_ci * other nodes, master should call same API in loop with new
25662306a36Sopenharmony_ci * index till error is returned. E.g First call should have
25762306a36Sopenharmony_ci * index 0 which will return nodes 0,1 and 2. Next call, index
25862306a36Sopenharmony_ci * should be 3 which will return nodes 3,4 and 5 and so on.
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * Return: 0 on success else error+reason
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_cistatic int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index,
26362306a36Sopenharmony_ci					struct topology_resp *response)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
26662306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
26762306a36Sopenharmony_ci	int ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;
27062306a36Sopenharmony_ci	qdata.arg1 = clock_id;
27162306a36Sopenharmony_ci	qdata.arg2 = index;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
27462306a36Sopenharmony_ci	memcpy(response, &ret_payload[1], sizeof(*response));
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return ret;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciunsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	unsigned long ccf_flag = 0;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_GATE)
28462306a36Sopenharmony_ci		ccf_flag |= CLK_SET_RATE_GATE;
28562306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_SET_PARENT_GATE)
28662306a36Sopenharmony_ci		ccf_flag |= CLK_SET_PARENT_GATE;
28762306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_PARENT)
28862306a36Sopenharmony_ci		ccf_flag |= CLK_SET_RATE_PARENT;
28962306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_IGNORE_UNUSED)
29062306a36Sopenharmony_ci		ccf_flag |= CLK_IGNORE_UNUSED;
29162306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_NO_REPARENT)
29262306a36Sopenharmony_ci		ccf_flag |= CLK_SET_RATE_NO_REPARENT;
29362306a36Sopenharmony_ci	if (zynqmp_flag & ZYNQMP_CLK_IS_CRITICAL)
29462306a36Sopenharmony_ci		ccf_flag |= CLK_IS_CRITICAL;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return ccf_flag;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * zynqmp_clk_register_fixed_factor() - Register fixed factor with the
30162306a36Sopenharmony_ci *					clock framework
30262306a36Sopenharmony_ci * @name:		Name of this clock
30362306a36Sopenharmony_ci * @clk_id:		Clock ID
30462306a36Sopenharmony_ci * @parents:		Name of this clock's parents
30562306a36Sopenharmony_ci * @num_parents:	Number of parents
30662306a36Sopenharmony_ci * @nodes:		Clock topology node
30762306a36Sopenharmony_ci *
30862306a36Sopenharmony_ci * Return: clock hardware to the registered clock
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_cistruct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
31162306a36Sopenharmony_ci					const char * const *parents,
31262306a36Sopenharmony_ci					u8 num_parents,
31362306a36Sopenharmony_ci					const struct clock_topology *nodes)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	u32 mult, div;
31662306a36Sopenharmony_ci	struct clk_hw *hw;
31762306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
31862306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
31962306a36Sopenharmony_ci	int ret;
32062306a36Sopenharmony_ci	unsigned long flag;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
32362306a36Sopenharmony_ci	qdata.arg1 = clk_id;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
32662306a36Sopenharmony_ci	if (ret)
32762306a36Sopenharmony_ci		return ERR_PTR(ret);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	mult = ret_payload[1];
33062306a36Sopenharmony_ci	div = ret_payload[2];
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	flag = zynqmp_clk_map_common_ccf_flags(nodes->flag);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	hw = clk_hw_register_fixed_factor(NULL, name,
33562306a36Sopenharmony_ci					  parents[0],
33662306a36Sopenharmony_ci					  flag, mult,
33762306a36Sopenharmony_ci					  div);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return hw;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/**
34362306a36Sopenharmony_ci * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id
34462306a36Sopenharmony_ci * @clock_id:	Clock ID
34562306a36Sopenharmony_ci * @index:	Parent index
34662306a36Sopenharmony_ci * @response:	Parents of the given clock
34762306a36Sopenharmony_ci *
34862306a36Sopenharmony_ci * This function is used to get 3 parents for the clock specified by
34962306a36Sopenharmony_ci * given clock ID.
35062306a36Sopenharmony_ci *
35162306a36Sopenharmony_ci * This API will return 3 parents with a single response. To get
35262306a36Sopenharmony_ci * other parents, master should call same API in loop with new
35362306a36Sopenharmony_ci * parent index till error is returned. E.g First call should have
35462306a36Sopenharmony_ci * index 0 which will return parents 0,1 and 2. Next call, index
35562306a36Sopenharmony_ci * should be 3 which will return parent 3,4 and 5 and so on.
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * Return: 0 on success else error+reason
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_cistatic int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index,
36062306a36Sopenharmony_ci				       struct parents_resp *response)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
36362306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
36462306a36Sopenharmony_ci	int ret;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_PARENTS;
36762306a36Sopenharmony_ci	qdata.arg1 = clock_id;
36862306a36Sopenharmony_ci	qdata.arg2 = index;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
37162306a36Sopenharmony_ci	memcpy(response, &ret_payload[1], sizeof(*response));
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return ret;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id
37862306a36Sopenharmony_ci * @clock_id:	Clock ID
37962306a36Sopenharmony_ci * @response:	Clock attributes response
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * This function is used to get clock's attributes(e.g. valid, clock type, etc).
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * Return: 0 on success else error+reason
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_cistatic int zynqmp_pm_clock_get_attributes(u32 clock_id,
38662306a36Sopenharmony_ci					  struct attr_resp *response)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct zynqmp_pm_query_data qdata = {0};
38962306a36Sopenharmony_ci	u32 ret_payload[PAYLOAD_ARG_CNT];
39062306a36Sopenharmony_ci	int ret;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;
39362306a36Sopenharmony_ci	qdata.arg1 = clock_id;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	ret = zynqmp_pm_query_data(qdata, ret_payload);
39662306a36Sopenharmony_ci	memcpy(response, &ret_payload[1], sizeof(*response));
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return ret;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci/**
40262306a36Sopenharmony_ci * __zynqmp_clock_get_topology() - Get topology data of clock from firmware
40362306a36Sopenharmony_ci *				   response data
40462306a36Sopenharmony_ci * @topology:		Clock topology
40562306a36Sopenharmony_ci * @response:		Clock topology data received from firmware
40662306a36Sopenharmony_ci * @nnodes:		Number of nodes
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * Return: 0 on success else error+reason
40962306a36Sopenharmony_ci */
41062306a36Sopenharmony_cistatic int __zynqmp_clock_get_topology(struct clock_topology *topology,
41162306a36Sopenharmony_ci				       struct topology_resp *response,
41262306a36Sopenharmony_ci				       u32 *nnodes)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	int i;
41562306a36Sopenharmony_ci	u32 type;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(response->topology); i++) {
41862306a36Sopenharmony_ci		type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]);
41962306a36Sopenharmony_ci		if (type == TYPE_INVALID)
42062306a36Sopenharmony_ci			return END_OF_TOPOLOGY_NODE;
42162306a36Sopenharmony_ci		topology[*nnodes].type = type;
42262306a36Sopenharmony_ci		topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS,
42362306a36Sopenharmony_ci						   response->topology[i]);
42462306a36Sopenharmony_ci		topology[*nnodes].type_flag =
42562306a36Sopenharmony_ci				FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS,
42662306a36Sopenharmony_ci					  response->topology[i]);
42762306a36Sopenharmony_ci		topology[*nnodes].custom_type_flag =
42862306a36Sopenharmony_ci			FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS,
42962306a36Sopenharmony_ci				  response->topology[i]);
43062306a36Sopenharmony_ci		(*nnodes)++;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * zynqmp_clock_get_topology() - Get topology of clock from firmware using
43862306a36Sopenharmony_ci *				 PM_API
43962306a36Sopenharmony_ci * @clk_id:		Clock index
44062306a36Sopenharmony_ci * @topology:		Clock topology
44162306a36Sopenharmony_ci * @num_nodes:		Number of nodes
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * Return: 0 on success else error+reason
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_cistatic int zynqmp_clock_get_topology(u32 clk_id,
44662306a36Sopenharmony_ci				     struct clock_topology *topology,
44762306a36Sopenharmony_ci				     u32 *num_nodes)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	int j, ret;
45062306a36Sopenharmony_ci	struct topology_resp response = { };
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	*num_nodes = 0;
45362306a36Sopenharmony_ci	for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) {
45462306a36Sopenharmony_ci		ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j,
45562306a36Sopenharmony_ci						   &response);
45662306a36Sopenharmony_ci		if (ret)
45762306a36Sopenharmony_ci			return ret;
45862306a36Sopenharmony_ci		ret = __zynqmp_clock_get_topology(topology, &response,
45962306a36Sopenharmony_ci						  num_nodes);
46062306a36Sopenharmony_ci		if (ret == END_OF_TOPOLOGY_NODE)
46162306a36Sopenharmony_ci			return 0;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return 0;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/**
46862306a36Sopenharmony_ci * __zynqmp_clock_get_parents() - Get parents info of clock from firmware
46962306a36Sopenharmony_ci *				   response data
47062306a36Sopenharmony_ci * @parents:		Clock parents
47162306a36Sopenharmony_ci * @response:		Clock parents data received from firmware
47262306a36Sopenharmony_ci * @nparent:		Number of parent
47362306a36Sopenharmony_ci *
47462306a36Sopenharmony_ci * Return: 0 on success else error+reason
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_cistatic int __zynqmp_clock_get_parents(struct clock_parent *parents,
47762306a36Sopenharmony_ci				      struct parents_resp *response,
47862306a36Sopenharmony_ci				      u32 *nparent)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	int i;
48162306a36Sopenharmony_ci	struct clock_parent *parent;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(response->parents); i++) {
48462306a36Sopenharmony_ci		if (response->parents[i] == NA_PARENT)
48562306a36Sopenharmony_ci			return END_OF_PARENTS;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		parent = &parents[i];
48862306a36Sopenharmony_ci		parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]);
48962306a36Sopenharmony_ci		if (response->parents[i] == DUMMY_PARENT) {
49062306a36Sopenharmony_ci			strcpy(parent->name, "dummy_name");
49162306a36Sopenharmony_ci			parent->flag = 0;
49262306a36Sopenharmony_ci		} else {
49362306a36Sopenharmony_ci			parent->flag = FIELD_GET(CLK_PARENTS_FLAGS,
49462306a36Sopenharmony_ci						 response->parents[i]);
49562306a36Sopenharmony_ci			if (zynqmp_get_clock_name(parent->id, parent->name))
49662306a36Sopenharmony_ci				continue;
49762306a36Sopenharmony_ci		}
49862306a36Sopenharmony_ci		*nparent += 1;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API
50662306a36Sopenharmony_ci * @clk_id:		Clock index
50762306a36Sopenharmony_ci * @parents:		Clock parents
50862306a36Sopenharmony_ci * @num_parents:	Total number of parents
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci * Return: 0 on success else error+reason
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents,
51362306a36Sopenharmony_ci				    u32 *num_parents)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int j = 0, ret;
51662306a36Sopenharmony_ci	struct parents_resp response = { };
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	*num_parents = 0;
51962306a36Sopenharmony_ci	do {
52062306a36Sopenharmony_ci		/* Get parents from firmware */
52162306a36Sopenharmony_ci		ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j,
52262306a36Sopenharmony_ci						  &response);
52362306a36Sopenharmony_ci		if (ret)
52462306a36Sopenharmony_ci			return ret;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		ret = __zynqmp_clock_get_parents(&parents[j], &response,
52762306a36Sopenharmony_ci						 num_parents);
52862306a36Sopenharmony_ci		if (ret == END_OF_PARENTS)
52962306a36Sopenharmony_ci			return 0;
53062306a36Sopenharmony_ci		j += ARRAY_SIZE(response.parents);
53162306a36Sopenharmony_ci	} while (*num_parents <= MAX_PARENT);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return 0;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci/**
53762306a36Sopenharmony_ci * zynqmp_get_parent_list() - Create list of parents name
53862306a36Sopenharmony_ci * @np:			Device node
53962306a36Sopenharmony_ci * @clk_id:		Clock index
54062306a36Sopenharmony_ci * @parent_list:	List of parent's name
54162306a36Sopenharmony_ci * @num_parents:	Total number of parents
54262306a36Sopenharmony_ci *
54362306a36Sopenharmony_ci * Return: 0 on success else error+reason
54462306a36Sopenharmony_ci */
54562306a36Sopenharmony_cistatic int zynqmp_get_parent_list(struct device_node *np, u32 clk_id,
54662306a36Sopenharmony_ci				  const char **parent_list, u32 *num_parents)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	int i = 0, ret;
54962306a36Sopenharmony_ci	u32 total_parents = clock[clk_id].num_parents;
55062306a36Sopenharmony_ci	struct clock_topology *clk_nodes;
55162306a36Sopenharmony_ci	struct clock_parent *parents;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	clk_nodes = clock[clk_id].node;
55462306a36Sopenharmony_ci	parents = clock[clk_id].parent;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	for (i = 0; i < total_parents; i++) {
55762306a36Sopenharmony_ci		if (!parents[i].flag) {
55862306a36Sopenharmony_ci			parent_list[i] = parents[i].name;
55962306a36Sopenharmony_ci		} else if (parents[i].flag == PARENT_CLK_EXTERNAL) {
56062306a36Sopenharmony_ci			ret = of_property_match_string(np, "clock-names",
56162306a36Sopenharmony_ci						       parents[i].name);
56262306a36Sopenharmony_ci			if (ret < 0)
56362306a36Sopenharmony_ci				strcpy(parents[i].name, "dummy_name");
56462306a36Sopenharmony_ci			parent_list[i] = parents[i].name;
56562306a36Sopenharmony_ci		} else {
56662306a36Sopenharmony_ci			strcat(parents[i].name,
56762306a36Sopenharmony_ci			       clk_type_postfix[clk_nodes[parents[i].flag - 1].
56862306a36Sopenharmony_ci			       type]);
56962306a36Sopenharmony_ci			parent_list[i] = parents[i].name;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	*num_parents = total_parents;
57462306a36Sopenharmony_ci	return 0;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/**
57862306a36Sopenharmony_ci * zynqmp_register_clk_topology() - Register clock topology
57962306a36Sopenharmony_ci * @clk_id:		Clock index
58062306a36Sopenharmony_ci * @clk_name:		Clock Name
58162306a36Sopenharmony_ci * @num_parents:	Total number of parents
58262306a36Sopenharmony_ci * @parent_names:	List of parents name
58362306a36Sopenharmony_ci *
58462306a36Sopenharmony_ci * Return: Returns either clock hardware or error+reason
58562306a36Sopenharmony_ci */
58662306a36Sopenharmony_cistatic struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
58762306a36Sopenharmony_ci						   int num_parents,
58862306a36Sopenharmony_ci						   const char **parent_names)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	int j;
59162306a36Sopenharmony_ci	u32 num_nodes, clk_dev_id;
59262306a36Sopenharmony_ci	char *clk_out[MAX_NODES];
59362306a36Sopenharmony_ci	struct clock_topology *nodes;
59462306a36Sopenharmony_ci	struct clk_hw *hw = NULL;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	nodes = clock[clk_id].node;
59762306a36Sopenharmony_ci	num_nodes = clock[clk_id].num_nodes;
59862306a36Sopenharmony_ci	clk_dev_id = clock[clk_id].clk_id;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	for (j = 0; j < num_nodes; j++) {
60162306a36Sopenharmony_ci		/*
60262306a36Sopenharmony_ci		 * Clock name received from firmware is output clock name.
60362306a36Sopenharmony_ci		 * Intermediate clock names are postfixed with type of clock.
60462306a36Sopenharmony_ci		 */
60562306a36Sopenharmony_ci		if (j != (num_nodes - 1)) {
60662306a36Sopenharmony_ci			clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name,
60762306a36Sopenharmony_ci					    clk_type_postfix[nodes[j].type]);
60862306a36Sopenharmony_ci		} else {
60962306a36Sopenharmony_ci			clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name);
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		if (!clk_topology[nodes[j].type])
61362306a36Sopenharmony_ci			continue;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id,
61662306a36Sopenharmony_ci						    parent_names,
61762306a36Sopenharmony_ci						    num_parents,
61862306a36Sopenharmony_ci						    &nodes[j]);
61962306a36Sopenharmony_ci		if (IS_ERR(hw))
62062306a36Sopenharmony_ci			pr_warn_once("%s() 0x%x: %s register fail with %ld\n",
62162306a36Sopenharmony_ci				     __func__,  clk_dev_id, clk_name,
62262306a36Sopenharmony_ci				     PTR_ERR(hw));
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		parent_names[0] = clk_out[j];
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	for (j = 0; j < num_nodes; j++)
62862306a36Sopenharmony_ci		kfree(clk_out[j]);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return hw;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci/**
63462306a36Sopenharmony_ci * zynqmp_register_clocks() - Register clocks
63562306a36Sopenharmony_ci * @np:		Device node
63662306a36Sopenharmony_ci *
63762306a36Sopenharmony_ci * Return: 0 on success else error code
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cistatic int zynqmp_register_clocks(struct device_node *np)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	int ret;
64262306a36Sopenharmony_ci	u32 i, total_parents = 0, type = 0;
64362306a36Sopenharmony_ci	const char *parent_names[MAX_PARENT];
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	for (i = 0; i < clock_max_idx; i++) {
64662306a36Sopenharmony_ci		char clk_name[MAX_NAME_LEN];
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		/* get clock name, continue to next clock if name not found */
64962306a36Sopenharmony_ci		if (zynqmp_get_clock_name(i, clk_name))
65062306a36Sopenharmony_ci			continue;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		/* Check if clock is valid and output clock.
65362306a36Sopenharmony_ci		 * Do not register invalid or external clock.
65462306a36Sopenharmony_ci		 */
65562306a36Sopenharmony_ci		ret = zynqmp_get_clock_type(i, &type);
65662306a36Sopenharmony_ci		if (ret || type != CLK_TYPE_OUTPUT)
65762306a36Sopenharmony_ci			continue;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		/* Get parents of clock*/
66062306a36Sopenharmony_ci		if (zynqmp_get_parent_list(np, i, parent_names,
66162306a36Sopenharmony_ci					   &total_parents)) {
66262306a36Sopenharmony_ci			WARN_ONCE(1, "No parents found for %s\n",
66362306a36Sopenharmony_ci				  clock[i].clk_name);
66462306a36Sopenharmony_ci			continue;
66562306a36Sopenharmony_ci		}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		zynqmp_data->hws[i] =
66862306a36Sopenharmony_ci			zynqmp_register_clk_topology(i, clk_name,
66962306a36Sopenharmony_ci						     total_parents,
67062306a36Sopenharmony_ci						     parent_names);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	for (i = 0; i < clock_max_idx; i++) {
67462306a36Sopenharmony_ci		if (IS_ERR(zynqmp_data->hws[i])) {
67562306a36Sopenharmony_ci			pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",
67662306a36Sopenharmony_ci			       clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i]));
67762306a36Sopenharmony_ci			WARN_ON(1);
67862306a36Sopenharmony_ci		}
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci	return 0;
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci/**
68462306a36Sopenharmony_ci * zynqmp_get_clock_info() - Get clock information from firmware using PM_API
68562306a36Sopenharmony_ci */
68662306a36Sopenharmony_cistatic void zynqmp_get_clock_info(void)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	int i, ret;
68962306a36Sopenharmony_ci	u32 type = 0;
69062306a36Sopenharmony_ci	u32 nodetype, subclass, class;
69162306a36Sopenharmony_ci	struct attr_resp attr;
69262306a36Sopenharmony_ci	struct name_resp name;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	for (i = 0; i < clock_max_idx; i++) {
69562306a36Sopenharmony_ci		ret = zynqmp_pm_clock_get_attributes(i, &attr);
69662306a36Sopenharmony_ci		if (ret)
69762306a36Sopenharmony_ci			continue;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]);
70062306a36Sopenharmony_ci		/* skip query for Invalid clock */
70162306a36Sopenharmony_ci		ret = zynqmp_is_valid_clock(i);
70262306a36Sopenharmony_ci		if (ret != CLK_ATTR_VALID)
70362306a36Sopenharmony_ci			continue;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ?
70662306a36Sopenharmony_ci			CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]);
70962306a36Sopenharmony_ci		subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]);
71062306a36Sopenharmony_ci		class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) |
71362306a36Sopenharmony_ci				  FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) |
71462306a36Sopenharmony_ci				  FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) |
71562306a36Sopenharmony_ci				  FIELD_PREP(CLK_ATTR_NODE_INDEX, i);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		zynqmp_pm_clock_get_name(clock[i].clk_id, &name);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		/*
72062306a36Sopenharmony_ci		 * Terminate with NULL character in case name provided by firmware
72162306a36Sopenharmony_ci		 * is longer and truncated due to size limit.
72262306a36Sopenharmony_ci		 */
72362306a36Sopenharmony_ci		name.name[sizeof(name.name) - 1] = '\0';
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		if (!strcmp(name.name, RESERVED_CLK_NAME))
72662306a36Sopenharmony_ci			continue;
72762306a36Sopenharmony_ci		strscpy(clock[i].clk_name, name.name, MAX_NAME_LEN);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Get topology of all clock */
73162306a36Sopenharmony_ci	for (i = 0; i < clock_max_idx; i++) {
73262306a36Sopenharmony_ci		ret = zynqmp_get_clock_type(i, &type);
73362306a36Sopenharmony_ci		if (ret || type != CLK_TYPE_OUTPUT)
73462306a36Sopenharmony_ci			continue;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		ret = zynqmp_clock_get_topology(i, clock[i].node,
73762306a36Sopenharmony_ci						&clock[i].num_nodes);
73862306a36Sopenharmony_ci		if (ret)
73962306a36Sopenharmony_ci			continue;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		ret = zynqmp_clock_get_parents(i, clock[i].parent,
74262306a36Sopenharmony_ci					       &clock[i].num_parents);
74362306a36Sopenharmony_ci		if (ret)
74462306a36Sopenharmony_ci			continue;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/**
74962306a36Sopenharmony_ci * zynqmp_clk_setup() - Setup the clock framework and register clocks
75062306a36Sopenharmony_ci * @np:		Device node
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci * Return: 0 on success else error code
75362306a36Sopenharmony_ci */
75462306a36Sopenharmony_cistatic int zynqmp_clk_setup(struct device_node *np)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	int ret;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx);
75962306a36Sopenharmony_ci	if (ret)
76062306a36Sopenharmony_ci		return ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx),
76362306a36Sopenharmony_ci			      GFP_KERNEL);
76462306a36Sopenharmony_ci	if (!zynqmp_data)
76562306a36Sopenharmony_ci		return -ENOMEM;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL);
76862306a36Sopenharmony_ci	if (!clock) {
76962306a36Sopenharmony_ci		kfree(zynqmp_data);
77062306a36Sopenharmony_ci		return -ENOMEM;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	zynqmp_get_clock_info();
77462306a36Sopenharmony_ci	zynqmp_register_clocks(np);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	zynqmp_data->num = clock_max_idx;
77762306a36Sopenharmony_ci	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int zynqmp_clock_probe(struct platform_device *pdev)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	int ret;
78362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ret = zynqmp_clk_setup(dev->of_node);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	return ret;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic const struct of_device_id zynqmp_clock_of_match[] = {
79162306a36Sopenharmony_ci	{.compatible = "xlnx,zynqmp-clk"},
79262306a36Sopenharmony_ci	{.compatible = "xlnx,versal-clk"},
79362306a36Sopenharmony_ci	{},
79462306a36Sopenharmony_ci};
79562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, zynqmp_clock_of_match);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic struct platform_driver zynqmp_clock_driver = {
79862306a36Sopenharmony_ci	.driver = {
79962306a36Sopenharmony_ci		.name = "zynqmp_clock",
80062306a36Sopenharmony_ci		.of_match_table = zynqmp_clock_of_match,
80162306a36Sopenharmony_ci	},
80262306a36Sopenharmony_ci	.probe = zynqmp_clock_probe,
80362306a36Sopenharmony_ci};
80462306a36Sopenharmony_cimodule_platform_driver(zynqmp_clock_driver);
805