18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Zynq UltraScale+ MPSoC Divider support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2019 Xilinx 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Adjustable divider clock implementation 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include "clk-zynqmp.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * DOC: basic adjustable divider clock that cannot gate 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Traits of this clock: 198c2ecf20Sopenharmony_ci * prepare - clk_prepare only ensures that parents are prepared 208c2ecf20Sopenharmony_ci * enable - clk_enable only ensures that parents are enabled 218c2ecf20Sopenharmony_ci * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor) 228c2ecf20Sopenharmony_ci * parent - fixed parent. No clk_set_parent support 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define to_zynqmp_clk_divider(_hw) \ 268c2ecf20Sopenharmony_ci container_of(_hw, struct zynqmp_clk_divider, hw) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define CLK_FRAC BIT(13) /* has a fractional parent */ 298c2ecf20Sopenharmony_ci#define CUSTOM_FLAG_CLK_FRAC BIT(0) /* has a fractional parent in custom type flag */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * struct zynqmp_clk_divider - adjustable divider clock 338c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces 348c2ecf20Sopenharmony_ci * @flags: Hardware specific flags 358c2ecf20Sopenharmony_ci * @is_frac: The divider is a fractional divider 368c2ecf20Sopenharmony_ci * @clk_id: Id of clock 378c2ecf20Sopenharmony_ci * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2) 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistruct zynqmp_clk_divider { 408c2ecf20Sopenharmony_ci struct clk_hw hw; 418c2ecf20Sopenharmony_ci u8 flags; 428c2ecf20Sopenharmony_ci bool is_frac; 438c2ecf20Sopenharmony_ci u32 clk_id; 448c2ecf20Sopenharmony_ci u32 div_type; 458c2ecf20Sopenharmony_ci u16 max_div; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline int zynqmp_divider_get_val(unsigned long parent_rate, 498c2ecf20Sopenharmony_ci unsigned long rate, u16 flags) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int up, down; 528c2ecf20Sopenharmony_ci unsigned long up_rate, down_rate; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (flags & CLK_DIVIDER_POWER_OF_TWO) { 558c2ecf20Sopenharmony_ci up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); 568c2ecf20Sopenharmony_ci down = DIV_ROUND_DOWN_ULL((u64)parent_rate, rate); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci up = __roundup_pow_of_two(up); 598c2ecf20Sopenharmony_ci down = __rounddown_pow_of_two(down); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up); 628c2ecf20Sopenharmony_ci down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return (rate - up_rate) <= (down_rate - rate) ? up : down; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci } else { 678c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(parent_rate, rate); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/** 728c2ecf20Sopenharmony_ci * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock 738c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces 748c2ecf20Sopenharmony_ci * @parent_rate: rate of parent clock 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, 798c2ecf20Sopenharmony_ci unsigned long parent_rate) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 828c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 838c2ecf20Sopenharmony_ci u32 clk_id = divider->clk_id; 848c2ecf20Sopenharmony_ci u32 div_type = divider->div_type; 858c2ecf20Sopenharmony_ci u32 div, value; 868c2ecf20Sopenharmony_ci int ret; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_getdivider(clk_id, &div); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (ret) 918c2ecf20Sopenharmony_ci pr_warn_once("%s() get divider failed for %s, ret = %d\n", 928c2ecf20Sopenharmony_ci __func__, clk_name, ret); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (div_type == TYPE_DIV1) 958c2ecf20Sopenharmony_ci value = div & 0xFFFF; 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci value = div >> 16; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 1008c2ecf20Sopenharmony_ci value = 1 << value; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!value) { 1038c2ecf20Sopenharmony_ci WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), 1048c2ecf20Sopenharmony_ci "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", 1058c2ecf20Sopenharmony_ci clk_name); 1068c2ecf20Sopenharmony_ci return parent_rate; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return DIV_ROUND_UP_ULL(parent_rate, value); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/** 1138c2ecf20Sopenharmony_ci * zynqmp_clk_divider_round_rate() - Round rate of divider clock 1148c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces 1158c2ecf20Sopenharmony_ci * @rate: rate of clock to be set 1168c2ecf20Sopenharmony_ci * @prate: rate of parent clock 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic long zynqmp_clk_divider_round_rate(struct clk_hw *hw, 1218c2ecf20Sopenharmony_ci unsigned long rate, 1228c2ecf20Sopenharmony_ci unsigned long *prate) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 1258c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 1268c2ecf20Sopenharmony_ci u32 clk_id = divider->clk_id; 1278c2ecf20Sopenharmony_ci u32 div_type = divider->div_type; 1288c2ecf20Sopenharmony_ci u32 bestdiv; 1298c2ecf20Sopenharmony_ci int ret; 1308c2ecf20Sopenharmony_ci u8 width; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* if read only, just return current value */ 1338c2ecf20Sopenharmony_ci if (divider->flags & CLK_DIVIDER_READ_ONLY) { 1348c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_getdivider(clk_id, &bestdiv); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci pr_warn_once("%s() get divider failed for %s, ret = %d\n", 1388c2ecf20Sopenharmony_ci __func__, clk_name, ret); 1398c2ecf20Sopenharmony_ci if (div_type == TYPE_DIV1) 1408c2ecf20Sopenharmony_ci bestdiv = bestdiv & 0xFFFF; 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci bestdiv = bestdiv >> 16; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 1458c2ecf20Sopenharmony_ci bestdiv = 1 << bestdiv; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci width = fls(divider->max_div); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) 1558c2ecf20Sopenharmony_ci *prate = rate; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return rate; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * zynqmp_clk_divider_set_rate() - Set rate of divider clock 1628c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces 1638c2ecf20Sopenharmony_ci * @rate: rate of clock to be set 1648c2ecf20Sopenharmony_ci * @parent_rate: rate of parent clock 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * Return: 0 on success else error+reason 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistatic int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, 1698c2ecf20Sopenharmony_ci unsigned long parent_rate) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 1728c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 1738c2ecf20Sopenharmony_ci u32 clk_id = divider->clk_id; 1748c2ecf20Sopenharmony_ci u32 div_type = divider->div_type; 1758c2ecf20Sopenharmony_ci u32 value, div; 1768c2ecf20Sopenharmony_ci int ret; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci value = zynqmp_divider_get_val(parent_rate, rate, divider->flags); 1798c2ecf20Sopenharmony_ci if (div_type == TYPE_DIV1) { 1808c2ecf20Sopenharmony_ci div = value & 0xFFFF; 1818c2ecf20Sopenharmony_ci div |= 0xffff << 16; 1828c2ecf20Sopenharmony_ci } else { 1838c2ecf20Sopenharmony_ci div = 0xffff; 1848c2ecf20Sopenharmony_ci div |= value << 16; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 1888c2ecf20Sopenharmony_ci div = __ffs(div); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_setdivider(clk_id, div); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (ret) 1938c2ecf20Sopenharmony_ci pr_warn_once("%s() set divider failed for %s, ret = %d\n", 1948c2ecf20Sopenharmony_ci __func__, clk_name, ret); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const struct clk_ops zynqmp_clk_divider_ops = { 2008c2ecf20Sopenharmony_ci .recalc_rate = zynqmp_clk_divider_recalc_rate, 2018c2ecf20Sopenharmony_ci .round_rate = zynqmp_clk_divider_round_rate, 2028c2ecf20Sopenharmony_ci .set_rate = zynqmp_clk_divider_set_rate, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/** 2068c2ecf20Sopenharmony_ci * zynqmp_clk_get_max_divisor() - Get maximum supported divisor from firmware. 2078c2ecf20Sopenharmony_ci * @clk_id: Id of clock 2088c2ecf20Sopenharmony_ci * @type: Divider type 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Return: Maximum divisor of a clock if query data is successful 2118c2ecf20Sopenharmony_ci * U16_MAX in case of query data is not success 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct zynqmp_pm_query_data qdata = {0}; 2168c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 2178c2ecf20Sopenharmony_ci int ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci qdata.qid = PM_QID_CLOCK_GET_MAX_DIVISOR; 2208c2ecf20Sopenharmony_ci qdata.arg1 = clk_id; 2218c2ecf20Sopenharmony_ci qdata.arg2 = type; 2228c2ecf20Sopenharmony_ci ret = zynqmp_pm_query_data(qdata, ret_payload); 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * To maintain backward compatibility return maximum possible value 2258c2ecf20Sopenharmony_ci * (0xFFFF) if query for max divisor is not successful. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci if (ret) 2288c2ecf20Sopenharmony_ci return U16_MAX; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return ret_payload[1]; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * zynqmp_clk_register_divider() - Register a divider clock 2358c2ecf20Sopenharmony_ci * @name: Name of this clock 2368c2ecf20Sopenharmony_ci * @clk_id: Id of clock 2378c2ecf20Sopenharmony_ci * @parents: Name of this clock's parents 2388c2ecf20Sopenharmony_ci * @num_parents: Number of parents 2398c2ecf20Sopenharmony_ci * @nodes: Clock topology node 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Return: clock hardware to registered clock divider 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistruct clk_hw *zynqmp_clk_register_divider(const char *name, 2448c2ecf20Sopenharmony_ci u32 clk_id, 2458c2ecf20Sopenharmony_ci const char * const *parents, 2468c2ecf20Sopenharmony_ci u8 num_parents, 2478c2ecf20Sopenharmony_ci const struct clock_topology *nodes) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct zynqmp_clk_divider *div; 2508c2ecf20Sopenharmony_ci struct clk_hw *hw; 2518c2ecf20Sopenharmony_ci struct clk_init_data init; 2528c2ecf20Sopenharmony_ci int ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* allocate the divider */ 2558c2ecf20Sopenharmony_ci div = kzalloc(sizeof(*div), GFP_KERNEL); 2568c2ecf20Sopenharmony_ci if (!div) 2578c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci init.name = name; 2608c2ecf20Sopenharmony_ci init.ops = &zynqmp_clk_divider_ops; 2618c2ecf20Sopenharmony_ci /* CLK_FRAC is not defined in the common clk framework */ 2628c2ecf20Sopenharmony_ci init.flags = nodes->flag & ~CLK_FRAC; 2638c2ecf20Sopenharmony_ci init.parent_names = parents; 2648c2ecf20Sopenharmony_ci init.num_parents = 1; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* struct clk_divider assignments */ 2678c2ecf20Sopenharmony_ci div->is_frac = !!((nodes->flag & CLK_FRAC) | 2688c2ecf20Sopenharmony_ci (nodes->custom_type_flag & CUSTOM_FLAG_CLK_FRAC)); 2698c2ecf20Sopenharmony_ci div->flags = nodes->type_flag; 2708c2ecf20Sopenharmony_ci div->hw.init = &init; 2718c2ecf20Sopenharmony_ci div->clk_id = clk_id; 2728c2ecf20Sopenharmony_ci div->div_type = nodes->type; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * To achieve best possible rate, maximum limit of divider is required 2768c2ecf20Sopenharmony_ci * while computation. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci div->max_div = zynqmp_clk_get_max_divisor(clk_id, nodes->type); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci hw = &div->hw; 2818c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 2828c2ecf20Sopenharmony_ci if (ret) { 2838c2ecf20Sopenharmony_ci kfree(div); 2848c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return hw; 2888c2ecf20Sopenharmony_ci} 289