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