1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2014 Marvell Technology Group Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
6*4882a593Smuzhiyun * Alexandre Belloni <alexandre.belloni@free-electrons.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/io.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_address.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "berlin2-avpll.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun * Berlin2 SoCs comprise up to two PLLs called AVPLL built upon a
19*4882a593Smuzhiyun * VCO with 8 channels each, channel 8 is the odd-one-out and does
20*4882a593Smuzhiyun * not provide mul/div.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * Unfortunately, its registers are not named but just numbered. To
23*4882a593Smuzhiyun * get in at least some kind of structure, we split each AVPLL into
24*4882a593Smuzhiyun * the VCOs and each channel into separate clock drivers.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * Also, here and there the VCO registers are a bit different with
27*4882a593Smuzhiyun * respect to bit shifts. Make sure to add a comment for those.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun #define NUM_CHANNELS 8
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define AVPLL_CTRL(x) ((x) * 0x4)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define VCO_CTRL0 AVPLL_CTRL(0)
34*4882a593Smuzhiyun /* BG2/BG2CDs VCO_B has an additional shift of 4 for its VCO_CTRL0 reg */
35*4882a593Smuzhiyun #define VCO_RESET BIT(0)
36*4882a593Smuzhiyun #define VCO_POWERUP BIT(1)
37*4882a593Smuzhiyun #define VCO_INTERPOL_SHIFT 2
38*4882a593Smuzhiyun #define VCO_INTERPOL_MASK (0xf << VCO_INTERPOL_SHIFT)
39*4882a593Smuzhiyun #define VCO_REG1V45_SEL_SHIFT 6
40*4882a593Smuzhiyun #define VCO_REG1V45_SEL(x) ((x) << VCO_REG1V45_SEL_SHIFT)
41*4882a593Smuzhiyun #define VCO_REG1V45_SEL_1V40 VCO_REG1V45_SEL(0)
42*4882a593Smuzhiyun #define VCO_REG1V45_SEL_1V45 VCO_REG1V45_SEL(1)
43*4882a593Smuzhiyun #define VCO_REG1V45_SEL_1V50 VCO_REG1V45_SEL(2)
44*4882a593Smuzhiyun #define VCO_REG1V45_SEL_1V55 VCO_REG1V45_SEL(3)
45*4882a593Smuzhiyun #define VCO_REG1V45_SEL_MASK VCO_REG1V45_SEL(3)
46*4882a593Smuzhiyun #define VCO_REG0V9_SEL_SHIFT 8
47*4882a593Smuzhiyun #define VCO_REG0V9_SEL_MASK (0xf << VCO_REG0V9_SEL_SHIFT)
48*4882a593Smuzhiyun #define VCO_VTHCAL_SHIFT 12
49*4882a593Smuzhiyun #define VCO_VTHCAL(x) ((x) << VCO_VTHCAL_SHIFT)
50*4882a593Smuzhiyun #define VCO_VTHCAL_0V90 VCO_VTHCAL(0)
51*4882a593Smuzhiyun #define VCO_VTHCAL_0V95 VCO_VTHCAL(1)
52*4882a593Smuzhiyun #define VCO_VTHCAL_1V00 VCO_VTHCAL(2)
53*4882a593Smuzhiyun #define VCO_VTHCAL_1V05 VCO_VTHCAL(3)
54*4882a593Smuzhiyun #define VCO_VTHCAL_MASK VCO_VTHCAL(3)
55*4882a593Smuzhiyun #define VCO_KVCOEXT_SHIFT 14
56*4882a593Smuzhiyun #define VCO_KVCOEXT_MASK (0x3 << VCO_KVCOEXT_SHIFT)
57*4882a593Smuzhiyun #define VCO_KVCOEXT_ENABLE BIT(17)
58*4882a593Smuzhiyun #define VCO_V2IEXT_SHIFT 18
59*4882a593Smuzhiyun #define VCO_V2IEXT_MASK (0xf << VCO_V2IEXT_SHIFT)
60*4882a593Smuzhiyun #define VCO_V2IEXT_ENABLE BIT(22)
61*4882a593Smuzhiyun #define VCO_SPEED_SHIFT 23
62*4882a593Smuzhiyun #define VCO_SPEED(x) ((x) << VCO_SPEED_SHIFT)
63*4882a593Smuzhiyun #define VCO_SPEED_1G08_1G21 VCO_SPEED(0)
64*4882a593Smuzhiyun #define VCO_SPEED_1G21_1G40 VCO_SPEED(1)
65*4882a593Smuzhiyun #define VCO_SPEED_1G40_1G61 VCO_SPEED(2)
66*4882a593Smuzhiyun #define VCO_SPEED_1G61_1G86 VCO_SPEED(3)
67*4882a593Smuzhiyun #define VCO_SPEED_1G86_2G00 VCO_SPEED(4)
68*4882a593Smuzhiyun #define VCO_SPEED_2G00_2G22 VCO_SPEED(5)
69*4882a593Smuzhiyun #define VCO_SPEED_2G22 VCO_SPEED(6)
70*4882a593Smuzhiyun #define VCO_SPEED_MASK VCO_SPEED(0x7)
71*4882a593Smuzhiyun #define VCO_CLKDET_ENABLE BIT(26)
72*4882a593Smuzhiyun #define VCO_CTRL1 AVPLL_CTRL(1)
73*4882a593Smuzhiyun #define VCO_REFDIV_SHIFT 0
74*4882a593Smuzhiyun #define VCO_REFDIV(x) ((x) << VCO_REFDIV_SHIFT)
75*4882a593Smuzhiyun #define VCO_REFDIV_1 VCO_REFDIV(0)
76*4882a593Smuzhiyun #define VCO_REFDIV_2 VCO_REFDIV(1)
77*4882a593Smuzhiyun #define VCO_REFDIV_4 VCO_REFDIV(2)
78*4882a593Smuzhiyun #define VCO_REFDIV_3 VCO_REFDIV(3)
79*4882a593Smuzhiyun #define VCO_REFDIV_MASK VCO_REFDIV(0x3f)
80*4882a593Smuzhiyun #define VCO_FBDIV_SHIFT 6
81*4882a593Smuzhiyun #define VCO_FBDIV(x) ((x) << VCO_FBDIV_SHIFT)
82*4882a593Smuzhiyun #define VCO_FBDIV_MASK VCO_FBDIV(0xff)
83*4882a593Smuzhiyun #define VCO_ICP_SHIFT 14
84*4882a593Smuzhiyun /* PLL Charge Pump Current = 10uA * (x + 1) */
85*4882a593Smuzhiyun #define VCO_ICP(x) ((x) << VCO_ICP_SHIFT)
86*4882a593Smuzhiyun #define VCO_ICP_MASK VCO_ICP(0xf)
87*4882a593Smuzhiyun #define VCO_LOAD_CAP BIT(18)
88*4882a593Smuzhiyun #define VCO_CALIBRATION_START BIT(19)
89*4882a593Smuzhiyun #define VCO_FREQOFFSETn(x) AVPLL_CTRL(3 + (x))
90*4882a593Smuzhiyun #define VCO_FREQOFFSET_MASK 0x7ffff
91*4882a593Smuzhiyun #define VCO_CTRL10 AVPLL_CTRL(10)
92*4882a593Smuzhiyun #define VCO_POWERUP_CH1 BIT(20)
93*4882a593Smuzhiyun #define VCO_CTRL11 AVPLL_CTRL(11)
94*4882a593Smuzhiyun #define VCO_CTRL12 AVPLL_CTRL(12)
95*4882a593Smuzhiyun #define VCO_CTRL13 AVPLL_CTRL(13)
96*4882a593Smuzhiyun #define VCO_CTRL14 AVPLL_CTRL(14)
97*4882a593Smuzhiyun #define VCO_CTRL15 AVPLL_CTRL(15)
98*4882a593Smuzhiyun #define VCO_SYNC1n(x) AVPLL_CTRL(15 + (x))
99*4882a593Smuzhiyun #define VCO_SYNC1_MASK 0x1ffff
100*4882a593Smuzhiyun #define VCO_SYNC2n(x) AVPLL_CTRL(23 + (x))
101*4882a593Smuzhiyun #define VCO_SYNC2_MASK 0x1ffff
102*4882a593Smuzhiyun #define VCO_CTRL30 AVPLL_CTRL(30)
103*4882a593Smuzhiyun #define VCO_DPLL_CH1_ENABLE BIT(17)
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun struct berlin2_avpll_vco {
106*4882a593Smuzhiyun struct clk_hw hw;
107*4882a593Smuzhiyun void __iomem *base;
108*4882a593Smuzhiyun u8 flags;
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun #define to_avpll_vco(hw) container_of(hw, struct berlin2_avpll_vco, hw)
112*4882a593Smuzhiyun
berlin2_avpll_vco_is_enabled(struct clk_hw * hw)113*4882a593Smuzhiyun static int berlin2_avpll_vco_is_enabled(struct clk_hw *hw)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
116*4882a593Smuzhiyun u32 reg;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun reg = readl_relaxed(vco->base + VCO_CTRL0);
119*4882a593Smuzhiyun if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
120*4882a593Smuzhiyun reg >>= 4;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun return !!(reg & VCO_POWERUP);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
berlin2_avpll_vco_enable(struct clk_hw * hw)125*4882a593Smuzhiyun static int berlin2_avpll_vco_enable(struct clk_hw *hw)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
128*4882a593Smuzhiyun u32 reg;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun reg = readl_relaxed(vco->base + VCO_CTRL0);
131*4882a593Smuzhiyun if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
132*4882a593Smuzhiyun reg |= VCO_POWERUP << 4;
133*4882a593Smuzhiyun else
134*4882a593Smuzhiyun reg |= VCO_POWERUP;
135*4882a593Smuzhiyun writel_relaxed(reg, vco->base + VCO_CTRL0);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun return 0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
berlin2_avpll_vco_disable(struct clk_hw * hw)140*4882a593Smuzhiyun static void berlin2_avpll_vco_disable(struct clk_hw *hw)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
143*4882a593Smuzhiyun u32 reg;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun reg = readl_relaxed(vco->base + VCO_CTRL0);
146*4882a593Smuzhiyun if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
147*4882a593Smuzhiyun reg &= ~(VCO_POWERUP << 4);
148*4882a593Smuzhiyun else
149*4882a593Smuzhiyun reg &= ~VCO_POWERUP;
150*4882a593Smuzhiyun writel_relaxed(reg, vco->base + VCO_CTRL0);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun static u8 vco_refdiv[] = { 1, 2, 4, 3 };
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static unsigned long
berlin2_avpll_vco_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)156*4882a593Smuzhiyun berlin2_avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
159*4882a593Smuzhiyun u32 reg, refdiv, fbdiv;
160*4882a593Smuzhiyun u64 freq = parent_rate;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /* AVPLL VCO frequency: Fvco = (Fref / refdiv) * fbdiv */
163*4882a593Smuzhiyun reg = readl_relaxed(vco->base + VCO_CTRL1);
164*4882a593Smuzhiyun refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT;
165*4882a593Smuzhiyun refdiv = vco_refdiv[refdiv];
166*4882a593Smuzhiyun fbdiv = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT;
167*4882a593Smuzhiyun freq *= fbdiv;
168*4882a593Smuzhiyun do_div(freq, refdiv);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return (unsigned long)freq;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun static const struct clk_ops berlin2_avpll_vco_ops = {
174*4882a593Smuzhiyun .is_enabled = berlin2_avpll_vco_is_enabled,
175*4882a593Smuzhiyun .enable = berlin2_avpll_vco_enable,
176*4882a593Smuzhiyun .disable = berlin2_avpll_vco_disable,
177*4882a593Smuzhiyun .recalc_rate = berlin2_avpll_vco_recalc_rate,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun
berlin2_avpll_vco_register(void __iomem * base,const char * name,const char * parent_name,u8 vco_flags,unsigned long flags)180*4882a593Smuzhiyun int __init berlin2_avpll_vco_register(void __iomem *base,
181*4882a593Smuzhiyun const char *name, const char *parent_name,
182*4882a593Smuzhiyun u8 vco_flags, unsigned long flags)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun struct berlin2_avpll_vco *vco;
185*4882a593Smuzhiyun struct clk_init_data init;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun vco = kzalloc(sizeof(*vco), GFP_KERNEL);
188*4882a593Smuzhiyun if (!vco)
189*4882a593Smuzhiyun return -ENOMEM;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun vco->base = base;
192*4882a593Smuzhiyun vco->flags = vco_flags;
193*4882a593Smuzhiyun vco->hw.init = &init;
194*4882a593Smuzhiyun init.name = name;
195*4882a593Smuzhiyun init.ops = &berlin2_avpll_vco_ops;
196*4882a593Smuzhiyun init.parent_names = &parent_name;
197*4882a593Smuzhiyun init.num_parents = 1;
198*4882a593Smuzhiyun init.flags = flags;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun return clk_hw_register(NULL, &vco->hw);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun struct berlin2_avpll_channel {
204*4882a593Smuzhiyun struct clk_hw hw;
205*4882a593Smuzhiyun void __iomem *base;
206*4882a593Smuzhiyun u8 flags;
207*4882a593Smuzhiyun u8 index;
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun #define to_avpll_channel(hw) container_of(hw, struct berlin2_avpll_channel, hw)
211*4882a593Smuzhiyun
berlin2_avpll_channel_is_enabled(struct clk_hw * hw)212*4882a593Smuzhiyun static int berlin2_avpll_channel_is_enabled(struct clk_hw *hw)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
215*4882a593Smuzhiyun u32 reg;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (ch->index == 7)
218*4882a593Smuzhiyun return 1;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL10);
221*4882a593Smuzhiyun reg &= VCO_POWERUP_CH1 << ch->index;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun return !!reg;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
berlin2_avpll_channel_enable(struct clk_hw * hw)226*4882a593Smuzhiyun static int berlin2_avpll_channel_enable(struct clk_hw *hw)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
229*4882a593Smuzhiyun u32 reg;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL10);
232*4882a593Smuzhiyun reg |= VCO_POWERUP_CH1 << ch->index;
233*4882a593Smuzhiyun writel_relaxed(reg, ch->base + VCO_CTRL10);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
berlin2_avpll_channel_disable(struct clk_hw * hw)238*4882a593Smuzhiyun static void berlin2_avpll_channel_disable(struct clk_hw *hw)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
241*4882a593Smuzhiyun u32 reg;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL10);
244*4882a593Smuzhiyun reg &= ~(VCO_POWERUP_CH1 << ch->index);
245*4882a593Smuzhiyun writel_relaxed(reg, ch->base + VCO_CTRL10);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun static const u8 div_hdmi[] = { 1, 2, 4, 6 };
249*4882a593Smuzhiyun static const u8 div_av1[] = { 1, 2, 5, 5 };
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun static unsigned long
berlin2_avpll_channel_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)252*4882a593Smuzhiyun berlin2_avpll_channel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
255*4882a593Smuzhiyun u32 reg, div_av2, div_av3, divider = 1;
256*4882a593Smuzhiyun u64 freq = parent_rate;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL30);
259*4882a593Smuzhiyun if ((reg & (VCO_DPLL_CH1_ENABLE << ch->index)) == 0)
260*4882a593Smuzhiyun goto skip_div;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Fch = (Fref * sync2) /
264*4882a593Smuzhiyun * (sync1 * div_hdmi * div_av1 * div_av2 * div_av3)
265*4882a593Smuzhiyun */
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_SYNC1n(ch->index));
268*4882a593Smuzhiyun /* BG2/BG2CDs SYNC1 reg on AVPLL_B channel 1 is shifted by 4 */
269*4882a593Smuzhiyun if (ch->flags & BERLIN2_AVPLL_BIT_QUIRK && ch->index == 0)
270*4882a593Smuzhiyun reg >>= 4;
271*4882a593Smuzhiyun divider = reg & VCO_SYNC1_MASK;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_SYNC2n(ch->index));
274*4882a593Smuzhiyun freq *= reg & VCO_SYNC2_MASK;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Channel 8 has no dividers */
277*4882a593Smuzhiyun if (ch->index == 7)
278*4882a593Smuzhiyun goto skip_div;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /*
281*4882a593Smuzhiyun * HDMI divider start at VCO_CTRL11, bit 7; MSB is enable, lower 2 bit
282*4882a593Smuzhiyun * determine divider.
283*4882a593Smuzhiyun */
284*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL11) >> 7;
285*4882a593Smuzhiyun reg = (reg >> (ch->index * 3));
286*4882a593Smuzhiyun if (reg & BIT(2))
287*4882a593Smuzhiyun divider *= div_hdmi[reg & 0x3];
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /*
290*4882a593Smuzhiyun * AV1 divider start at VCO_CTRL11, bit 28; MSB is enable, lower 2 bit
291*4882a593Smuzhiyun * determine divider.
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun if (ch->index == 0) {
294*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL11);
295*4882a593Smuzhiyun reg >>= 28;
296*4882a593Smuzhiyun } else {
297*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL12);
298*4882a593Smuzhiyun reg >>= (ch->index-1) * 3;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun if (reg & BIT(2))
301*4882a593Smuzhiyun divider *= div_av1[reg & 0x3];
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun * AV2 divider start at VCO_CTRL12, bit 18; each 7 bits wide,
305*4882a593Smuzhiyun * zero is not a valid value.
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun if (ch->index < 2) {
308*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL12);
309*4882a593Smuzhiyun reg >>= 18 + (ch->index * 7);
310*4882a593Smuzhiyun } else if (ch->index < 7) {
311*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL13);
312*4882a593Smuzhiyun reg >>= (ch->index - 2) * 7;
313*4882a593Smuzhiyun } else {
314*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL14);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun div_av2 = reg & 0x7f;
317*4882a593Smuzhiyun if (div_av2)
318*4882a593Smuzhiyun divider *= div_av2;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /*
321*4882a593Smuzhiyun * AV3 divider start at VCO_CTRL14, bit 7; each 4 bits wide.
322*4882a593Smuzhiyun * AV2/AV3 form a fractional divider, where only specfic values for AV3
323*4882a593Smuzhiyun * are allowed. AV3 != 0 divides by AV2/2, AV3=0 is bypass.
324*4882a593Smuzhiyun */
325*4882a593Smuzhiyun if (ch->index < 6) {
326*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL14);
327*4882a593Smuzhiyun reg >>= 7 + (ch->index * 4);
328*4882a593Smuzhiyun } else {
329*4882a593Smuzhiyun reg = readl_relaxed(ch->base + VCO_CTRL15);
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun div_av3 = reg & 0xf;
332*4882a593Smuzhiyun if (div_av2 && div_av3)
333*4882a593Smuzhiyun freq *= 2;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun skip_div:
336*4882a593Smuzhiyun do_div(freq, divider);
337*4882a593Smuzhiyun return (unsigned long)freq;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun static const struct clk_ops berlin2_avpll_channel_ops = {
341*4882a593Smuzhiyun .is_enabled = berlin2_avpll_channel_is_enabled,
342*4882a593Smuzhiyun .enable = berlin2_avpll_channel_enable,
343*4882a593Smuzhiyun .disable = berlin2_avpll_channel_disable,
344*4882a593Smuzhiyun .recalc_rate = berlin2_avpll_channel_recalc_rate,
345*4882a593Smuzhiyun };
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /*
348*4882a593Smuzhiyun * Another nice quirk:
349*4882a593Smuzhiyun * On some production SoCs, AVPLL channels are scrambled with respect
350*4882a593Smuzhiyun * to the channel numbering in the registers but still referenced by
351*4882a593Smuzhiyun * their original channel numbers. We deal with it by having a flag
352*4882a593Smuzhiyun * and a translation table for the index.
353*4882a593Smuzhiyun */
354*4882a593Smuzhiyun static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 };
355*4882a593Smuzhiyun
berlin2_avpll_channel_register(void __iomem * base,const char * name,u8 index,const char * parent_name,u8 ch_flags,unsigned long flags)356*4882a593Smuzhiyun int __init berlin2_avpll_channel_register(void __iomem *base,
357*4882a593Smuzhiyun const char *name, u8 index, const char *parent_name,
358*4882a593Smuzhiyun u8 ch_flags, unsigned long flags)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct berlin2_avpll_channel *ch;
361*4882a593Smuzhiyun struct clk_init_data init;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun ch = kzalloc(sizeof(*ch), GFP_KERNEL);
364*4882a593Smuzhiyun if (!ch)
365*4882a593Smuzhiyun return -ENOMEM;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun ch->base = base;
368*4882a593Smuzhiyun if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK)
369*4882a593Smuzhiyun ch->index = quirk_index[index];
370*4882a593Smuzhiyun else
371*4882a593Smuzhiyun ch->index = index;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun ch->flags = ch_flags;
374*4882a593Smuzhiyun ch->hw.init = &init;
375*4882a593Smuzhiyun init.name = name;
376*4882a593Smuzhiyun init.ops = &berlin2_avpll_channel_ops;
377*4882a593Smuzhiyun init.parent_names = &parent_name;
378*4882a593Smuzhiyun init.num_parents = 1;
379*4882a593Smuzhiyun init.flags = flags;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return clk_hw_register(NULL, &ch->hw);
382*4882a593Smuzhiyun }
383