18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Zynq UltraScale+ MPSoC clock controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2019 Xilinx 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on drivers/clk/zynq/clkc.c 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "clk-zynqmp.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define MAX_PARENT 100 218c2ecf20Sopenharmony_ci#define MAX_NODES 6 228c2ecf20Sopenharmony_ci#define MAX_NAME_LEN 50 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Flags for parents */ 258c2ecf20Sopenharmony_ci#define PARENT_CLK_SELF 0 268c2ecf20Sopenharmony_ci#define PARENT_CLK_NODE1 1 278c2ecf20Sopenharmony_ci#define PARENT_CLK_NODE2 2 288c2ecf20Sopenharmony_ci#define PARENT_CLK_NODE3 3 298c2ecf20Sopenharmony_ci#define PARENT_CLK_NODE4 4 308c2ecf20Sopenharmony_ci#define PARENT_CLK_EXTERNAL 5 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define END_OF_CLK_NAME "END_OF_CLK" 338c2ecf20Sopenharmony_ci#define END_OF_TOPOLOGY_NODE 1 348c2ecf20Sopenharmony_ci#define END_OF_PARENTS 1 358c2ecf20Sopenharmony_ci#define RESERVED_CLK_NAME "" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define CLK_GET_NAME_RESP_LEN 16 388c2ecf20Sopenharmony_ci#define CLK_GET_TOPOLOGY_RESP_WORDS 3 398c2ecf20Sopenharmony_ci#define CLK_GET_PARENTS_RESP_WORDS 3 408c2ecf20Sopenharmony_ci#define CLK_GET_ATTR_RESP_WORDS 1 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum clk_type { 438c2ecf20Sopenharmony_ci CLK_TYPE_OUTPUT, 448c2ecf20Sopenharmony_ci CLK_TYPE_EXTERNAL, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * struct clock_parent - Clock parent 498c2ecf20Sopenharmony_ci * @name: Parent name 508c2ecf20Sopenharmony_ci * @id: Parent clock ID 518c2ecf20Sopenharmony_ci * @flag: Parent flags 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct clock_parent { 548c2ecf20Sopenharmony_ci char name[MAX_NAME_LEN]; 558c2ecf20Sopenharmony_ci int id; 568c2ecf20Sopenharmony_ci u32 flag; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/** 608c2ecf20Sopenharmony_ci * struct zynqmp_clock - Clock 618c2ecf20Sopenharmony_ci * @clk_name: Clock name 628c2ecf20Sopenharmony_ci * @valid: Validity flag of clock 638c2ecf20Sopenharmony_ci * @type: Clock type (Output/External) 648c2ecf20Sopenharmony_ci * @node: Clock topology nodes 658c2ecf20Sopenharmony_ci * @num_nodes: Number of nodes present in topology 668c2ecf20Sopenharmony_ci * @parent: Parent of clock 678c2ecf20Sopenharmony_ci * @num_parents: Number of parents of clock 688c2ecf20Sopenharmony_ci * @clk_id: Clock id 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistruct zynqmp_clock { 718c2ecf20Sopenharmony_ci char clk_name[MAX_NAME_LEN]; 728c2ecf20Sopenharmony_ci u32 valid; 738c2ecf20Sopenharmony_ci enum clk_type type; 748c2ecf20Sopenharmony_ci struct clock_topology node[MAX_NODES]; 758c2ecf20Sopenharmony_ci u32 num_nodes; 768c2ecf20Sopenharmony_ci struct clock_parent parent[MAX_PARENT]; 778c2ecf20Sopenharmony_ci u32 num_parents; 788c2ecf20Sopenharmony_ci u32 clk_id; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct name_resp { 828c2ecf20Sopenharmony_ci char name[CLK_GET_NAME_RESP_LEN]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct topology_resp { 868c2ecf20Sopenharmony_ci#define CLK_TOPOLOGY_TYPE GENMASK(3, 0) 878c2ecf20Sopenharmony_ci#define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS GENMASK(7, 4) 888c2ecf20Sopenharmony_ci#define CLK_TOPOLOGY_FLAGS GENMASK(23, 8) 898c2ecf20Sopenharmony_ci#define CLK_TOPOLOGY_TYPE_FLAGS GENMASK(31, 24) 908c2ecf20Sopenharmony_ci u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS]; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct parents_resp { 948c2ecf20Sopenharmony_ci#define NA_PARENT 0xFFFFFFFF 958c2ecf20Sopenharmony_ci#define DUMMY_PARENT 0xFFFFFFFE 968c2ecf20Sopenharmony_ci#define CLK_PARENTS_ID GENMASK(15, 0) 978c2ecf20Sopenharmony_ci#define CLK_PARENTS_FLAGS GENMASK(31, 16) 988c2ecf20Sopenharmony_ci u32 parents[CLK_GET_PARENTS_RESP_WORDS]; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct attr_resp { 1028c2ecf20Sopenharmony_ci#define CLK_ATTR_VALID BIT(0) 1038c2ecf20Sopenharmony_ci#define CLK_ATTR_TYPE BIT(2) 1048c2ecf20Sopenharmony_ci#define CLK_ATTR_NODE_INDEX GENMASK(13, 0) 1058c2ecf20Sopenharmony_ci#define CLK_ATTR_NODE_TYPE GENMASK(19, 14) 1068c2ecf20Sopenharmony_ci#define CLK_ATTR_NODE_SUBCLASS GENMASK(25, 20) 1078c2ecf20Sopenharmony_ci#define CLK_ATTR_NODE_CLASS GENMASK(31, 26) 1088c2ecf20Sopenharmony_ci u32 attr[CLK_GET_ATTR_RESP_WORDS]; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const char clk_type_postfix[][10] = { 1128c2ecf20Sopenharmony_ci [TYPE_INVALID] = "", 1138c2ecf20Sopenharmony_ci [TYPE_MUX] = "_mux", 1148c2ecf20Sopenharmony_ci [TYPE_GATE] = "", 1158c2ecf20Sopenharmony_ci [TYPE_DIV1] = "_div1", 1168c2ecf20Sopenharmony_ci [TYPE_DIV2] = "_div2", 1178c2ecf20Sopenharmony_ci [TYPE_FIXEDFACTOR] = "_ff", 1188c2ecf20Sopenharmony_ci [TYPE_PLL] = "" 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id, 1228c2ecf20Sopenharmony_ci const char * const *parents, 1238c2ecf20Sopenharmony_ci u8 num_parents, 1248c2ecf20Sopenharmony_ci const struct clock_topology *nodes) 1258c2ecf20Sopenharmony_ci = { 1268c2ecf20Sopenharmony_ci [TYPE_INVALID] = NULL, 1278c2ecf20Sopenharmony_ci [TYPE_MUX] = zynqmp_clk_register_mux, 1288c2ecf20Sopenharmony_ci [TYPE_PLL] = zynqmp_clk_register_pll, 1298c2ecf20Sopenharmony_ci [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor, 1308c2ecf20Sopenharmony_ci [TYPE_DIV1] = zynqmp_clk_register_divider, 1318c2ecf20Sopenharmony_ci [TYPE_DIV2] = zynqmp_clk_register_divider, 1328c2ecf20Sopenharmony_ci [TYPE_GATE] = zynqmp_clk_register_gate 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct zynqmp_clock *clock; 1368c2ecf20Sopenharmony_cistatic struct clk_hw_onecell_data *zynqmp_data; 1378c2ecf20Sopenharmony_cistatic unsigned int clock_max_idx; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * zynqmp_is_valid_clock() - Check whether clock is valid or not 1418c2ecf20Sopenharmony_ci * @clk_id: Clock index 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Return: 1 if clock is valid, 0 if clock is invalid else error code 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic inline int zynqmp_is_valid_clock(u32 clk_id) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci if (clk_id >= clock_max_idx) 1488c2ecf20Sopenharmony_ci return -ENODEV; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return clock[clk_id].valid; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/** 1548c2ecf20Sopenharmony_ci * zynqmp_get_clock_name() - Get name of clock from Clock index 1558c2ecf20Sopenharmony_ci * @clk_id: Clock index 1568c2ecf20Sopenharmony_ci * @clk_name: Name of clock 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * Return: 0 on success else error code 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic int zynqmp_get_clock_name(u32 clk_id, char *clk_name) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci int ret; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ret = zynqmp_is_valid_clock(clk_id); 1658c2ecf20Sopenharmony_ci if (ret == 1) { 1668c2ecf20Sopenharmony_ci strncpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN); 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return ret == 0 ? -EINVAL : ret; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * zynqmp_get_clock_type() - Get type of clock 1758c2ecf20Sopenharmony_ci * @clk_id: Clock index 1768c2ecf20Sopenharmony_ci * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Return: 0 on success else error code 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_cistatic int zynqmp_get_clock_type(u32 clk_id, u32 *type) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci int ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = zynqmp_is_valid_clock(clk_id); 1858c2ecf20Sopenharmony_ci if (ret == 1) { 1868c2ecf20Sopenharmony_ci *type = clock[clk_id].type; 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return ret == 0 ? -EINVAL : ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/** 1948c2ecf20Sopenharmony_ci * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system 1958c2ecf20Sopenharmony_ci * @nclocks: Number of clocks in system/board. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Call firmware API to get number of clocks. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * Return: 0 on success else error code. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistatic int zynqmp_pm_clock_get_num_clocks(u32 *nclocks) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 2048c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 2108c2ecf20Sopenharmony_ci *nclocks = ret_payload[1]; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/** 2168c2ecf20Sopenharmony_ci * zynqmp_pm_clock_get_name() - Get the name of clock for given id 2178c2ecf20Sopenharmony_ci * @clock_id: ID of the clock to be queried 2188c2ecf20Sopenharmony_ci * @response: Name of the clock with the given id 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * This function is used to get name of clock specified by given 2218c2ecf20Sopenharmony_ci * clock ID. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Return: Returns 0 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistatic int zynqmp_pm_clock_get_name(u32 clock_id, 2268c2ecf20Sopenharmony_ci struct name_resp *response) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 2298c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_NAME; 2328c2ecf20Sopenharmony_ci qdata.arg1 = clock_id; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci zynqmp_pm_query_data(qdata, ret_payload); 2358c2ecf20Sopenharmony_ci memcpy(response, ret_payload, sizeof(*response)); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/** 2418c2ecf20Sopenharmony_ci * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id 2428c2ecf20Sopenharmony_ci * @clock_id: ID of the clock to be queried 2438c2ecf20Sopenharmony_ci * @index: Node index of clock topology 2448c2ecf20Sopenharmony_ci * @response: Buffer used for the topology response 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * This function is used to get topology information for the clock 2478c2ecf20Sopenharmony_ci * specified by given clock ID. 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * This API will return 3 node of topology with a single response. To get 2508c2ecf20Sopenharmony_ci * other nodes, master should call same API in loop with new 2518c2ecf20Sopenharmony_ci * index till error is returned. E.g First call should have 2528c2ecf20Sopenharmony_ci * index 0 which will return nodes 0,1 and 2. Next call, index 2538c2ecf20Sopenharmony_ci * should be 3 which will return nodes 3,4 and 5 and so on. 2548c2ecf20Sopenharmony_ci * 2558c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, 2588c2ecf20Sopenharmony_ci struct topology_resp *response) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 2618c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 2628c2ecf20Sopenharmony_ci int ret; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY; 2658c2ecf20Sopenharmony_ci qdata.arg1 = clock_id; 2668c2ecf20Sopenharmony_ci qdata.arg2 = index; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 2698c2ecf20Sopenharmony_ci memcpy(response, &ret_payload[1], sizeof(*response)); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * zynqmp_clk_register_fixed_factor() - Register fixed factor with the 2768c2ecf20Sopenharmony_ci * clock framework 2778c2ecf20Sopenharmony_ci * @name: Name of this clock 2788c2ecf20Sopenharmony_ci * @clk_id: Clock ID 2798c2ecf20Sopenharmony_ci * @parents: Name of this clock's parents 2808c2ecf20Sopenharmony_ci * @num_parents: Number of parents 2818c2ecf20Sopenharmony_ci * @nodes: Clock topology node 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Return: clock hardware to the registered clock 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistruct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id, 2868c2ecf20Sopenharmony_ci const char * const *parents, 2878c2ecf20Sopenharmony_ci u8 num_parents, 2888c2ecf20Sopenharmony_ci const struct clock_topology *nodes) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci u32 mult, div; 2918c2ecf20Sopenharmony_ci struct clk_hw *hw; 2928c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 2938c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 2948c2ecf20Sopenharmony_ci int ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS; 2978c2ecf20Sopenharmony_ci qdata.arg1 = clk_id; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 3008c2ecf20Sopenharmony_ci if (ret) 3018c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mult = ret_payload[1]; 3048c2ecf20Sopenharmony_ci div = ret_payload[2]; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_factor(NULL, name, 3078c2ecf20Sopenharmony_ci parents[0], 3088c2ecf20Sopenharmony_ci nodes->flag, mult, 3098c2ecf20Sopenharmony_ci div); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return hw; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/** 3158c2ecf20Sopenharmony_ci * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id 3168c2ecf20Sopenharmony_ci * @clock_id: Clock ID 3178c2ecf20Sopenharmony_ci * @index: Parent index 3188c2ecf20Sopenharmony_ci * @response: Parents of the given clock 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * This function is used to get 3 parents for the clock specified by 3218c2ecf20Sopenharmony_ci * given clock ID. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * This API will return 3 parents with a single response. To get 3248c2ecf20Sopenharmony_ci * other parents, master should call same API in loop with new 3258c2ecf20Sopenharmony_ci * parent index till error is returned. E.g First call should have 3268c2ecf20Sopenharmony_ci * index 0 which will return parents 0,1 and 2. Next call, index 3278c2ecf20Sopenharmony_ci * should be 3 which will return parent 3,4 and 5 and so on. 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_cistatic int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, 3328c2ecf20Sopenharmony_ci struct parents_resp *response) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 3358c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_PARENTS; 3398c2ecf20Sopenharmony_ci qdata.arg1 = clock_id; 3408c2ecf20Sopenharmony_ci qdata.arg2 = index; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 3438c2ecf20Sopenharmony_ci memcpy(response, &ret_payload[1], sizeof(*response)); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/** 3498c2ecf20Sopenharmony_ci * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id 3508c2ecf20Sopenharmony_ci * @clock_id: Clock ID 3518c2ecf20Sopenharmony_ci * @response: Clock attributes response 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * This function is used to get clock's attributes(e.g. valid, clock type, etc). 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_cistatic int zynqmp_pm_clock_get_attributes(u32 clock_id, 3588c2ecf20Sopenharmony_ci struct attr_resp *response) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 3618c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 3628c2ecf20Sopenharmony_ci int ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES; 3658c2ecf20Sopenharmony_ci qdata.arg1 = clock_id; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 3688c2ecf20Sopenharmony_ci memcpy(response, &ret_payload[1], sizeof(*response)); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/** 3748c2ecf20Sopenharmony_ci * __zynqmp_clock_get_topology() - Get topology data of clock from firmware 3758c2ecf20Sopenharmony_ci * response data 3768c2ecf20Sopenharmony_ci * @topology: Clock topology 3778c2ecf20Sopenharmony_ci * @response: Clock topology data received from firmware 3788c2ecf20Sopenharmony_ci * @nnodes: Number of nodes 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistatic int __zynqmp_clock_get_topology(struct clock_topology *topology, 3838c2ecf20Sopenharmony_ci struct topology_resp *response, 3848c2ecf20Sopenharmony_ci u32 *nnodes) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci int i; 3878c2ecf20Sopenharmony_ci u32 type; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(response->topology); i++) { 3908c2ecf20Sopenharmony_ci type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]); 3918c2ecf20Sopenharmony_ci if (type == TYPE_INVALID) 3928c2ecf20Sopenharmony_ci return END_OF_TOPOLOGY_NODE; 3938c2ecf20Sopenharmony_ci topology[*nnodes].type = type; 3948c2ecf20Sopenharmony_ci topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS, 3958c2ecf20Sopenharmony_ci response->topology[i]); 3968c2ecf20Sopenharmony_ci topology[*nnodes].type_flag = 3978c2ecf20Sopenharmony_ci FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS, 3988c2ecf20Sopenharmony_ci response->topology[i]); 3998c2ecf20Sopenharmony_ci topology[*nnodes].custom_type_flag = 4008c2ecf20Sopenharmony_ci FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS, 4018c2ecf20Sopenharmony_ci response->topology[i]); 4028c2ecf20Sopenharmony_ci (*nnodes)++; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/** 4098c2ecf20Sopenharmony_ci * zynqmp_clock_get_topology() - Get topology of clock from firmware using 4108c2ecf20Sopenharmony_ci * PM_API 4118c2ecf20Sopenharmony_ci * @clk_id: Clock index 4128c2ecf20Sopenharmony_ci * @topology: Clock topology 4138c2ecf20Sopenharmony_ci * @num_nodes: Number of nodes 4148c2ecf20Sopenharmony_ci * 4158c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_cistatic int zynqmp_clock_get_topology(u32 clk_id, 4188c2ecf20Sopenharmony_ci struct clock_topology *topology, 4198c2ecf20Sopenharmony_ci u32 *num_nodes) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci int j, ret; 4228c2ecf20Sopenharmony_ci struct topology_resp response = { }; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci *num_nodes = 0; 4258c2ecf20Sopenharmony_ci for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) { 4268c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j, 4278c2ecf20Sopenharmony_ci &response); 4288c2ecf20Sopenharmony_ci if (ret) 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci ret = __zynqmp_clock_get_topology(topology, &response, 4318c2ecf20Sopenharmony_ci num_nodes); 4328c2ecf20Sopenharmony_ci if (ret == END_OF_TOPOLOGY_NODE) 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/** 4408c2ecf20Sopenharmony_ci * __zynqmp_clock_get_parents() - Get parents info of clock from firmware 4418c2ecf20Sopenharmony_ci * response data 4428c2ecf20Sopenharmony_ci * @parents: Clock parents 4438c2ecf20Sopenharmony_ci * @response: Clock parents data received from firmware 4448c2ecf20Sopenharmony_ci * @nparent: Number of parent 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistatic int __zynqmp_clock_get_parents(struct clock_parent *parents, 4498c2ecf20Sopenharmony_ci struct parents_resp *response, 4508c2ecf20Sopenharmony_ci u32 *nparent) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci int i; 4538c2ecf20Sopenharmony_ci struct clock_parent *parent; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(response->parents); i++) { 4568c2ecf20Sopenharmony_ci if (response->parents[i] == NA_PARENT) 4578c2ecf20Sopenharmony_ci return END_OF_PARENTS; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci parent = &parents[i]; 4608c2ecf20Sopenharmony_ci parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]); 4618c2ecf20Sopenharmony_ci if (response->parents[i] == DUMMY_PARENT) { 4628c2ecf20Sopenharmony_ci strcpy(parent->name, "dummy_name"); 4638c2ecf20Sopenharmony_ci parent->flag = 0; 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci parent->flag = FIELD_GET(CLK_PARENTS_FLAGS, 4668c2ecf20Sopenharmony_ci response->parents[i]); 4678c2ecf20Sopenharmony_ci if (zynqmp_get_clock_name(parent->id, parent->name)) 4688c2ecf20Sopenharmony_ci continue; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci *nparent += 1; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return 0; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API 4788c2ecf20Sopenharmony_ci * @clk_id: Clock index 4798c2ecf20Sopenharmony_ci * @parents: Clock parents 4808c2ecf20Sopenharmony_ci * @num_parents: Total number of parents 4818c2ecf20Sopenharmony_ci * 4828c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents, 4858c2ecf20Sopenharmony_ci u32 *num_parents) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int j = 0, ret; 4888c2ecf20Sopenharmony_ci struct parents_resp response = { }; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci *num_parents = 0; 4918c2ecf20Sopenharmony_ci do { 4928c2ecf20Sopenharmony_ci /* Get parents from firmware */ 4938c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j, 4948c2ecf20Sopenharmony_ci &response); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = __zynqmp_clock_get_parents(&parents[j], &response, 4998c2ecf20Sopenharmony_ci num_parents); 5008c2ecf20Sopenharmony_ci if (ret == END_OF_PARENTS) 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci j += ARRAY_SIZE(response.parents); 5038c2ecf20Sopenharmony_ci } while (*num_parents <= MAX_PARENT); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/** 5098c2ecf20Sopenharmony_ci * zynqmp_get_parent_list() - Create list of parents name 5108c2ecf20Sopenharmony_ci * @np: Device node 5118c2ecf20Sopenharmony_ci * @clk_id: Clock index 5128c2ecf20Sopenharmony_ci * @parent_list: List of parent's name 5138c2ecf20Sopenharmony_ci * @num_parents: Total number of parents 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_cistatic int zynqmp_get_parent_list(struct device_node *np, u32 clk_id, 5188c2ecf20Sopenharmony_ci const char **parent_list, u32 *num_parents) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci int i = 0, ret; 5218c2ecf20Sopenharmony_ci u32 total_parents = clock[clk_id].num_parents; 5228c2ecf20Sopenharmony_ci struct clock_topology *clk_nodes; 5238c2ecf20Sopenharmony_ci struct clock_parent *parents; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci clk_nodes = clock[clk_id].node; 5268c2ecf20Sopenharmony_ci parents = clock[clk_id].parent; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci for (i = 0; i < total_parents; i++) { 5298c2ecf20Sopenharmony_ci if (!parents[i].flag) { 5308c2ecf20Sopenharmony_ci parent_list[i] = parents[i].name; 5318c2ecf20Sopenharmony_ci } else if (parents[i].flag == PARENT_CLK_EXTERNAL) { 5328c2ecf20Sopenharmony_ci ret = of_property_match_string(np, "clock-names", 5338c2ecf20Sopenharmony_ci parents[i].name); 5348c2ecf20Sopenharmony_ci if (ret < 0) 5358c2ecf20Sopenharmony_ci strcpy(parents[i].name, "dummy_name"); 5368c2ecf20Sopenharmony_ci parent_list[i] = parents[i].name; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci strcat(parents[i].name, 5398c2ecf20Sopenharmony_ci clk_type_postfix[clk_nodes[parents[i].flag - 1]. 5408c2ecf20Sopenharmony_ci type]); 5418c2ecf20Sopenharmony_ci parent_list[i] = parents[i].name; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci *num_parents = total_parents; 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/** 5508c2ecf20Sopenharmony_ci * zynqmp_register_clk_topology() - Register clock topology 5518c2ecf20Sopenharmony_ci * @clk_id: Clock index 5528c2ecf20Sopenharmony_ci * @clk_name: Clock Name 5538c2ecf20Sopenharmony_ci * @num_parents: Total number of parents 5548c2ecf20Sopenharmony_ci * @parent_names: List of parents name 5558c2ecf20Sopenharmony_ci * 5568c2ecf20Sopenharmony_ci * Return: Returns either clock hardware or error+reason 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_cistatic struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name, 5598c2ecf20Sopenharmony_ci int num_parents, 5608c2ecf20Sopenharmony_ci const char **parent_names) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci int j; 5638c2ecf20Sopenharmony_ci u32 num_nodes, clk_dev_id; 5648c2ecf20Sopenharmony_ci char *clk_out[MAX_NODES]; 5658c2ecf20Sopenharmony_ci struct clock_topology *nodes; 5668c2ecf20Sopenharmony_ci struct clk_hw *hw = NULL; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci nodes = clock[clk_id].node; 5698c2ecf20Sopenharmony_ci num_nodes = clock[clk_id].num_nodes; 5708c2ecf20Sopenharmony_ci clk_dev_id = clock[clk_id].clk_id; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci for (j = 0; j < num_nodes; j++) { 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * Clock name received from firmware is output clock name. 5758c2ecf20Sopenharmony_ci * Intermediate clock names are postfixed with type of clock. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci if (j != (num_nodes - 1)) { 5788c2ecf20Sopenharmony_ci clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name, 5798c2ecf20Sopenharmony_ci clk_type_postfix[nodes[j].type]); 5808c2ecf20Sopenharmony_ci } else { 5818c2ecf20Sopenharmony_ci clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!clk_topology[nodes[j].type]) 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id, 5888c2ecf20Sopenharmony_ci parent_names, 5898c2ecf20Sopenharmony_ci num_parents, 5908c2ecf20Sopenharmony_ci &nodes[j]); 5918c2ecf20Sopenharmony_ci if (IS_ERR(hw)) 5928c2ecf20Sopenharmony_ci pr_warn_once("%s() 0x%x: %s register fail with %ld\n", 5938c2ecf20Sopenharmony_ci __func__, clk_dev_id, clk_name, 5948c2ecf20Sopenharmony_ci PTR_ERR(hw)); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci parent_names[0] = clk_out[j]; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci for (j = 0; j < num_nodes; j++) 6008c2ecf20Sopenharmony_ci kfree(clk_out[j]); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return hw; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci/** 6068c2ecf20Sopenharmony_ci * zynqmp_register_clocks() - Register clocks 6078c2ecf20Sopenharmony_ci * @np: Device node 6088c2ecf20Sopenharmony_ci * 6098c2ecf20Sopenharmony_ci * Return: 0 on success else error code 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_cistatic int zynqmp_register_clocks(struct device_node *np) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int ret; 6148c2ecf20Sopenharmony_ci u32 i, total_parents = 0, type = 0; 6158c2ecf20Sopenharmony_ci const char *parent_names[MAX_PARENT]; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci for (i = 0; i < clock_max_idx; i++) { 6188c2ecf20Sopenharmony_ci char clk_name[MAX_NAME_LEN]; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* get clock name, continue to next clock if name not found */ 6218c2ecf20Sopenharmony_ci if (zynqmp_get_clock_name(i, clk_name)) 6228c2ecf20Sopenharmony_ci continue; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Check if clock is valid and output clock. 6258c2ecf20Sopenharmony_ci * Do not register invalid or external clock. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci ret = zynqmp_get_clock_type(i, &type); 6288c2ecf20Sopenharmony_ci if (ret || type != CLK_TYPE_OUTPUT) 6298c2ecf20Sopenharmony_ci continue; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* Get parents of clock*/ 6328c2ecf20Sopenharmony_ci if (zynqmp_get_parent_list(np, i, parent_names, 6338c2ecf20Sopenharmony_ci &total_parents)) { 6348c2ecf20Sopenharmony_ci WARN_ONCE(1, "No parents found for %s\n", 6358c2ecf20Sopenharmony_ci clock[i].clk_name); 6368c2ecf20Sopenharmony_ci continue; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci zynqmp_data->hws[i] = 6408c2ecf20Sopenharmony_ci zynqmp_register_clk_topology(i, clk_name, 6418c2ecf20Sopenharmony_ci total_parents, 6428c2ecf20Sopenharmony_ci parent_names); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci for (i = 0; i < clock_max_idx; i++) { 6468c2ecf20Sopenharmony_ci if (IS_ERR(zynqmp_data->hws[i])) { 6478c2ecf20Sopenharmony_ci pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n", 6488c2ecf20Sopenharmony_ci clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i])); 6498c2ecf20Sopenharmony_ci WARN_ON(1); 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/** 6568c2ecf20Sopenharmony_ci * zynqmp_get_clock_info() - Get clock information from firmware using PM_API 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic void zynqmp_get_clock_info(void) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci int i, ret; 6618c2ecf20Sopenharmony_ci u32 type = 0; 6628c2ecf20Sopenharmony_ci u32 nodetype, subclass, class; 6638c2ecf20Sopenharmony_ci struct attr_resp attr; 6648c2ecf20Sopenharmony_ci struct name_resp name; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci for (i = 0; i < clock_max_idx; i++) { 6678c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_get_attributes(i, &attr); 6688c2ecf20Sopenharmony_ci if (ret) 6698c2ecf20Sopenharmony_ci continue; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]); 6728c2ecf20Sopenharmony_ci /* skip query for Invalid clock */ 6738c2ecf20Sopenharmony_ci ret = zynqmp_is_valid_clock(i); 6748c2ecf20Sopenharmony_ci if (ret != CLK_ATTR_VALID) 6758c2ecf20Sopenharmony_ci continue; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ? 6788c2ecf20Sopenharmony_ci CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]); 6818c2ecf20Sopenharmony_ci subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]); 6828c2ecf20Sopenharmony_ci class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) | 6858c2ecf20Sopenharmony_ci FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) | 6868c2ecf20Sopenharmony_ci FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) | 6878c2ecf20Sopenharmony_ci FIELD_PREP(CLK_ATTR_NODE_INDEX, i); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci zynqmp_pm_clock_get_name(clock[i].clk_id, &name); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* 6928c2ecf20Sopenharmony_ci * Terminate with NULL character in case name provided by firmware 6938c2ecf20Sopenharmony_ci * is longer and truncated due to size limit. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci name.name[sizeof(name.name) - 1] = '\0'; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!strcmp(name.name, RESERVED_CLK_NAME)) 6988c2ecf20Sopenharmony_ci continue; 6998c2ecf20Sopenharmony_ci strncpy(clock[i].clk_name, name.name, MAX_NAME_LEN); 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* Get topology of all clock */ 7038c2ecf20Sopenharmony_ci for (i = 0; i < clock_max_idx; i++) { 7048c2ecf20Sopenharmony_ci ret = zynqmp_get_clock_type(i, &type); 7058c2ecf20Sopenharmony_ci if (ret || type != CLK_TYPE_OUTPUT) 7068c2ecf20Sopenharmony_ci continue; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci ret = zynqmp_clock_get_topology(i, clock[i].node, 7098c2ecf20Sopenharmony_ci &clock[i].num_nodes); 7108c2ecf20Sopenharmony_ci if (ret) 7118c2ecf20Sopenharmony_ci continue; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci ret = zynqmp_clock_get_parents(i, clock[i].parent, 7148c2ecf20Sopenharmony_ci &clock[i].num_parents); 7158c2ecf20Sopenharmony_ci if (ret) 7168c2ecf20Sopenharmony_ci continue; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci/** 7218c2ecf20Sopenharmony_ci * zynqmp_clk_setup() - Setup the clock framework and register clocks 7228c2ecf20Sopenharmony_ci * @np: Device node 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci * Return: 0 on success else error code 7258c2ecf20Sopenharmony_ci */ 7268c2ecf20Sopenharmony_cistatic int zynqmp_clk_setup(struct device_node *np) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci int ret; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx); 7318c2ecf20Sopenharmony_ci if (ret) 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx), 7358c2ecf20Sopenharmony_ci GFP_KERNEL); 7368c2ecf20Sopenharmony_ci if (!zynqmp_data) 7378c2ecf20Sopenharmony_ci return -ENOMEM; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL); 7408c2ecf20Sopenharmony_ci if (!clock) { 7418c2ecf20Sopenharmony_ci kfree(zynqmp_data); 7428c2ecf20Sopenharmony_ci return -ENOMEM; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci zynqmp_get_clock_info(); 7468c2ecf20Sopenharmony_ci zynqmp_register_clocks(np); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci zynqmp_data->num = clock_max_idx; 7498c2ecf20Sopenharmony_ci of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int zynqmp_clock_probe(struct platform_device *pdev) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci int ret; 7578c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci ret = zynqmp_clk_setup(dev->of_node); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic const struct of_device_id zynqmp_clock_of_match[] = { 7658c2ecf20Sopenharmony_ci {.compatible = "xlnx,zynqmp-clk"}, 7668c2ecf20Sopenharmony_ci {.compatible = "xlnx,versal-clk"}, 7678c2ecf20Sopenharmony_ci {}, 7688c2ecf20Sopenharmony_ci}; 7698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zynqmp_clock_of_match); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic struct platform_driver zynqmp_clock_driver = { 7728c2ecf20Sopenharmony_ci .driver = { 7738c2ecf20Sopenharmony_ci .name = "zynqmp_clock", 7748c2ecf20Sopenharmony_ci .of_match_table = zynqmp_clock_of_match, 7758c2ecf20Sopenharmony_ci }, 7768c2ecf20Sopenharmony_ci .probe = zynqmp_clock_probe, 7778c2ecf20Sopenharmony_ci}; 7788c2ecf20Sopenharmony_cimodule_platform_driver(zynqmp_clock_driver); 779