1*3fde0e16SJolly Shah // SPDX-License-Identifier: GPL-2.0 2*3fde0e16SJolly Shah /* 3*3fde0e16SJolly Shah * Zynq UltraScale+ MPSoC Divider support 4*3fde0e16SJolly Shah * 5*3fde0e16SJolly Shah * Copyright (C) 2016-2018 Xilinx 6*3fde0e16SJolly Shah * 7*3fde0e16SJolly Shah * Adjustable divider clock implementation 8*3fde0e16SJolly Shah */ 9*3fde0e16SJolly Shah 10*3fde0e16SJolly Shah #include <linux/clk.h> 11*3fde0e16SJolly Shah #include <linux/clk-provider.h> 12*3fde0e16SJolly Shah #include <linux/slab.h> 13*3fde0e16SJolly Shah #include "clk-zynqmp.h" 14*3fde0e16SJolly Shah 15*3fde0e16SJolly Shah /* 16*3fde0e16SJolly Shah * DOC: basic adjustable divider clock that cannot gate 17*3fde0e16SJolly Shah * 18*3fde0e16SJolly Shah * Traits of this clock: 19*3fde0e16SJolly Shah * prepare - clk_prepare only ensures that parents are prepared 20*3fde0e16SJolly Shah * enable - clk_enable only ensures that parents are enabled 21*3fde0e16SJolly Shah * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor) 22*3fde0e16SJolly Shah * parent - fixed parent. No clk_set_parent support 23*3fde0e16SJolly Shah */ 24*3fde0e16SJolly Shah 25*3fde0e16SJolly Shah #define to_zynqmp_clk_divider(_hw) \ 26*3fde0e16SJolly Shah container_of(_hw, struct zynqmp_clk_divider, hw) 27*3fde0e16SJolly Shah 28*3fde0e16SJolly Shah #define CLK_FRAC BIT(13) /* has a fractional parent */ 29*3fde0e16SJolly Shah 30*3fde0e16SJolly Shah /** 31*3fde0e16SJolly Shah * struct zynqmp_clk_divider - adjustable divider clock 32*3fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces 33*3fde0e16SJolly Shah * @flags: Hardware specific flags 34*3fde0e16SJolly Shah * @clk_id: Id of clock 35*3fde0e16SJolly Shah * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2) 36*3fde0e16SJolly Shah */ 37*3fde0e16SJolly Shah struct zynqmp_clk_divider { 38*3fde0e16SJolly Shah struct clk_hw hw; 39*3fde0e16SJolly Shah u8 flags; 40*3fde0e16SJolly Shah u32 clk_id; 41*3fde0e16SJolly Shah u32 div_type; 42*3fde0e16SJolly Shah }; 43*3fde0e16SJolly Shah 44*3fde0e16SJolly Shah static inline int zynqmp_divider_get_val(unsigned long parent_rate, 45*3fde0e16SJolly Shah unsigned long rate) 46*3fde0e16SJolly Shah { 47*3fde0e16SJolly Shah return DIV_ROUND_CLOSEST(parent_rate, rate); 48*3fde0e16SJolly Shah } 49*3fde0e16SJolly Shah 50*3fde0e16SJolly Shah /** 51*3fde0e16SJolly Shah * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock 52*3fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces 53*3fde0e16SJolly Shah * @parent_rate: rate of parent clock 54*3fde0e16SJolly Shah * 55*3fde0e16SJolly Shah * Return: 0 on success else error+reason 56*3fde0e16SJolly Shah */ 57*3fde0e16SJolly Shah static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, 58*3fde0e16SJolly Shah unsigned long parent_rate) 59*3fde0e16SJolly Shah { 60*3fde0e16SJolly Shah struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 61*3fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw); 62*3fde0e16SJolly Shah u32 clk_id = divider->clk_id; 63*3fde0e16SJolly Shah u32 div_type = divider->div_type; 64*3fde0e16SJolly Shah u32 div, value; 65*3fde0e16SJolly Shah int ret; 66*3fde0e16SJolly Shah const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 67*3fde0e16SJolly Shah 68*3fde0e16SJolly Shah ret = eemi_ops->clock_getdivider(clk_id, &div); 69*3fde0e16SJolly Shah 70*3fde0e16SJolly Shah if (ret) 71*3fde0e16SJolly Shah pr_warn_once("%s() get divider failed for %s, ret = %d\n", 72*3fde0e16SJolly Shah __func__, clk_name, ret); 73*3fde0e16SJolly Shah 74*3fde0e16SJolly Shah if (div_type == TYPE_DIV1) 75*3fde0e16SJolly Shah value = div & 0xFFFF; 76*3fde0e16SJolly Shah else 77*3fde0e16SJolly Shah value = div >> 16; 78*3fde0e16SJolly Shah 79*3fde0e16SJolly Shah return DIV_ROUND_UP_ULL(parent_rate, value); 80*3fde0e16SJolly Shah } 81*3fde0e16SJolly Shah 82*3fde0e16SJolly Shah /** 83*3fde0e16SJolly Shah * zynqmp_clk_divider_round_rate() - Round rate of divider clock 84*3fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces 85*3fde0e16SJolly Shah * @rate: rate of clock to be set 86*3fde0e16SJolly Shah * @prate: rate of parent clock 87*3fde0e16SJolly Shah * 88*3fde0e16SJolly Shah * Return: 0 on success else error+reason 89*3fde0e16SJolly Shah */ 90*3fde0e16SJolly Shah static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, 91*3fde0e16SJolly Shah unsigned long rate, 92*3fde0e16SJolly Shah unsigned long *prate) 93*3fde0e16SJolly Shah { 94*3fde0e16SJolly Shah struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 95*3fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw); 96*3fde0e16SJolly Shah u32 clk_id = divider->clk_id; 97*3fde0e16SJolly Shah u32 div_type = divider->div_type; 98*3fde0e16SJolly Shah u32 bestdiv; 99*3fde0e16SJolly Shah int ret; 100*3fde0e16SJolly Shah const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 101*3fde0e16SJolly Shah 102*3fde0e16SJolly Shah /* if read only, just return current value */ 103*3fde0e16SJolly Shah if (divider->flags & CLK_DIVIDER_READ_ONLY) { 104*3fde0e16SJolly Shah ret = eemi_ops->clock_getdivider(clk_id, &bestdiv); 105*3fde0e16SJolly Shah 106*3fde0e16SJolly Shah if (ret) 107*3fde0e16SJolly Shah pr_warn_once("%s() get divider failed for %s, ret = %d\n", 108*3fde0e16SJolly Shah __func__, clk_name, ret); 109*3fde0e16SJolly Shah if (div_type == TYPE_DIV1) 110*3fde0e16SJolly Shah bestdiv = bestdiv & 0xFFFF; 111*3fde0e16SJolly Shah else 112*3fde0e16SJolly Shah bestdiv = bestdiv >> 16; 113*3fde0e16SJolly Shah 114*3fde0e16SJolly Shah return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); 115*3fde0e16SJolly Shah } 116*3fde0e16SJolly Shah 117*3fde0e16SJolly Shah bestdiv = zynqmp_divider_get_val(*prate, rate); 118*3fde0e16SJolly Shah 119*3fde0e16SJolly Shah if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && 120*3fde0e16SJolly Shah (divider->flags & CLK_FRAC)) 121*3fde0e16SJolly Shah bestdiv = rate % *prate ? 1 : bestdiv; 122*3fde0e16SJolly Shah *prate = rate * bestdiv; 123*3fde0e16SJolly Shah 124*3fde0e16SJolly Shah return rate; 125*3fde0e16SJolly Shah } 126*3fde0e16SJolly Shah 127*3fde0e16SJolly Shah /** 128*3fde0e16SJolly Shah * zynqmp_clk_divider_set_rate() - Set rate of divider clock 129*3fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces 130*3fde0e16SJolly Shah * @rate: rate of clock to be set 131*3fde0e16SJolly Shah * @parent_rate: rate of parent clock 132*3fde0e16SJolly Shah * 133*3fde0e16SJolly Shah * Return: 0 on success else error+reason 134*3fde0e16SJolly Shah */ 135*3fde0e16SJolly Shah static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, 136*3fde0e16SJolly Shah unsigned long parent_rate) 137*3fde0e16SJolly Shah { 138*3fde0e16SJolly Shah struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 139*3fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw); 140*3fde0e16SJolly Shah u32 clk_id = divider->clk_id; 141*3fde0e16SJolly Shah u32 div_type = divider->div_type; 142*3fde0e16SJolly Shah u32 value, div; 143*3fde0e16SJolly Shah int ret; 144*3fde0e16SJolly Shah const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 145*3fde0e16SJolly Shah 146*3fde0e16SJolly Shah value = zynqmp_divider_get_val(parent_rate, rate); 147*3fde0e16SJolly Shah if (div_type == TYPE_DIV1) { 148*3fde0e16SJolly Shah div = value & 0xFFFF; 149*3fde0e16SJolly Shah div |= 0xffff << 16; 150*3fde0e16SJolly Shah } else { 151*3fde0e16SJolly Shah div = 0xffff; 152*3fde0e16SJolly Shah div |= value << 16; 153*3fde0e16SJolly Shah } 154*3fde0e16SJolly Shah 155*3fde0e16SJolly Shah ret = eemi_ops->clock_setdivider(clk_id, div); 156*3fde0e16SJolly Shah 157*3fde0e16SJolly Shah if (ret) 158*3fde0e16SJolly Shah pr_warn_once("%s() set divider failed for %s, ret = %d\n", 159*3fde0e16SJolly Shah __func__, clk_name, ret); 160*3fde0e16SJolly Shah 161*3fde0e16SJolly Shah return ret; 162*3fde0e16SJolly Shah } 163*3fde0e16SJolly Shah 164*3fde0e16SJolly Shah static const struct clk_ops zynqmp_clk_divider_ops = { 165*3fde0e16SJolly Shah .recalc_rate = zynqmp_clk_divider_recalc_rate, 166*3fde0e16SJolly Shah .round_rate = zynqmp_clk_divider_round_rate, 167*3fde0e16SJolly Shah .set_rate = zynqmp_clk_divider_set_rate, 168*3fde0e16SJolly Shah }; 169*3fde0e16SJolly Shah 170*3fde0e16SJolly Shah /** 171*3fde0e16SJolly Shah * zynqmp_clk_register_divider() - Register a divider clock 172*3fde0e16SJolly Shah * @name: Name of this clock 173*3fde0e16SJolly Shah * @clk_id: Id of clock 174*3fde0e16SJolly Shah * @parents: Name of this clock's parents 175*3fde0e16SJolly Shah * @num_parents: Number of parents 176*3fde0e16SJolly Shah * @nodes: Clock topology node 177*3fde0e16SJolly Shah * 178*3fde0e16SJolly Shah * Return: clock hardware to registered clock divider 179*3fde0e16SJolly Shah */ 180*3fde0e16SJolly Shah struct clk_hw *zynqmp_clk_register_divider(const char *name, 181*3fde0e16SJolly Shah u32 clk_id, 182*3fde0e16SJolly Shah const char * const *parents, 183*3fde0e16SJolly Shah u8 num_parents, 184*3fde0e16SJolly Shah const struct clock_topology *nodes) 185*3fde0e16SJolly Shah { 186*3fde0e16SJolly Shah struct zynqmp_clk_divider *div; 187*3fde0e16SJolly Shah struct clk_hw *hw; 188*3fde0e16SJolly Shah struct clk_init_data init; 189*3fde0e16SJolly Shah int ret; 190*3fde0e16SJolly Shah 191*3fde0e16SJolly Shah /* allocate the divider */ 192*3fde0e16SJolly Shah div = kzalloc(sizeof(*div), GFP_KERNEL); 193*3fde0e16SJolly Shah if (!div) 194*3fde0e16SJolly Shah return ERR_PTR(-ENOMEM); 195*3fde0e16SJolly Shah 196*3fde0e16SJolly Shah init.name = name; 197*3fde0e16SJolly Shah init.ops = &zynqmp_clk_divider_ops; 198*3fde0e16SJolly Shah init.flags = nodes->flag; 199*3fde0e16SJolly Shah init.parent_names = parents; 200*3fde0e16SJolly Shah init.num_parents = 1; 201*3fde0e16SJolly Shah 202*3fde0e16SJolly Shah /* struct clk_divider assignments */ 203*3fde0e16SJolly Shah div->flags = nodes->type_flag; 204*3fde0e16SJolly Shah div->hw.init = &init; 205*3fde0e16SJolly Shah div->clk_id = clk_id; 206*3fde0e16SJolly Shah div->div_type = nodes->type; 207*3fde0e16SJolly Shah 208*3fde0e16SJolly Shah hw = &div->hw; 209*3fde0e16SJolly Shah ret = clk_hw_register(NULL, hw); 210*3fde0e16SJolly Shah if (ret) { 211*3fde0e16SJolly Shah kfree(div); 212*3fde0e16SJolly Shah hw = ERR_PTR(ret); 213*3fde0e16SJolly Shah } 214*3fde0e16SJolly Shah 215*3fde0e16SJolly Shah return hw; 216*3fde0e16SJolly Shah } 217*3fde0e16SJolly Shah EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider); 218