xref: /OK3568_Linux_fs/kernel/drivers/clk/berlin/berlin2-avpll.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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