1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 NXP
4  */
5 
6 #include <common.h>
7 #include <div64.h>
8 #include <asm/io.h>
9 #include <errno.h>
10 #include <asm/arch/imx-regs.h>
11 #include <asm/arch/pcc.h>
12 #include <asm/arch/cgc.h>
13 #include <asm/arch/sys_proto.h>
14 
15 #define cgc1_clk_TYPES 2
16 #define cgc1_clk_NUM 8
17 
18 static enum cgc1_clk pcc3_clksrc[][8] = {
19 	{
20 	},
21 	{	DUMMY0_CLK,
22 		LPOSC,
23 		SOSC_DIV2,
24 		FRO_DIV2,
25 		XBAR_BUSCLK,
26 		PLL3_PFD1_DIV1,
27 		PLL3_PFD0_DIV2,
28 		PLL3_PFD0_DIV1
29 	}
30 };
31 
32 static enum cgc1_clk pcc4_clksrc[][8] = {
33 	{
34 		DUMMY0_CLK,
35 		SOSC_DIV1,
36 		FRO_DIV1,
37 		PLL3_PFD3_DIV2,
38 		PLL3_PFD3_DIV1,
39 		PLL3_PFD2_DIV2,
40 		PLL3_PFD2_DIV1,
41 		PLL3_PFD1_DIV2
42 	},
43 	{
44 		DUMMY0_CLK,
45 		DUMMY1_CLK,
46 		LPOSC,
47 		SOSC_DIV2,
48 		FRO_DIV2,
49 		XBAR_BUSCLK,
50 		PLL3_VCODIV,
51 		PLL3_PFD0_DIV1
52 	}
53 };
54 
55 static struct pcc_entry pcc3_arrays[] = {
56 	{PCC3_RBASE, DMA1_MP_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
57 	{PCC3_RBASE, DMA1_CH0_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
58 	{PCC3_RBASE, DMA1_CH1_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
59 	{PCC3_RBASE, DMA1_CH2_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
60 	{PCC3_RBASE, DMA1_CH3_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
61 	{PCC3_RBASE, DMA1_CH4_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
62 	{PCC3_RBASE, DMA1_CH5_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
63 	{PCC3_RBASE, DMA1_CH6_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
64 	{PCC3_RBASE, DMA1_CH7_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
65 	{PCC3_RBASE, DMA1_CH8_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
66 	{PCC3_RBASE, DMA1_CH9_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
67 	{PCC3_RBASE, DMA1_CH10_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
68 	{PCC3_RBASE, DMA1_CH11_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
69 	{PCC3_RBASE, DMA1_CH12_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
70 	{PCC3_RBASE, DMA1_CH13_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
71 	{PCC3_RBASE, DMA1_CH14_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
72 	{PCC3_RBASE, DMA1_CH15_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
73 	{PCC3_RBASE, DMA1_CH16_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
74 	{PCC3_RBASE, DMA1_CH17_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
75 	{PCC3_RBASE, DMA1_CH18_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
76 	{PCC3_RBASE, DMA1_CH19_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
77 	{PCC3_RBASE, DMA1_CH20_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
78 	{PCC3_RBASE, DMA1_CH21_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
79 	{PCC3_RBASE, DMA1_CH22_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
80 	{PCC3_RBASE, DMA1_CH23_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
81 	{PCC3_RBASE, DMA1_CH24_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
82 	{PCC3_RBASE, DMA1_CH25_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
83 	{PCC3_RBASE, DMA1_CH26_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
84 	{PCC3_RBASE, DMA1_CH27_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
85 	{PCC3_RBASE, DMA1_CH28_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
86 	{PCC3_RBASE, DMA1_CH29_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
87 	{PCC3_RBASE, DMA1_CH30_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
88 	{PCC3_RBASE, DMA1_CH31_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
89 	{PCC3_RBASE, MU0_B_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
90 	{PCC3_RBASE, MU3_A_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
91 	{PCC3_RBASE, LLWU1_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
92 	{PCC3_RBASE, UPOWER_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
93 	{PCC3_RBASE, WDOG3_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
94 	{PCC3_RBASE, WDOG4_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
95 	{PCC3_RBASE, XRDC_MGR_PCC3_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
96 	{PCC3_RBASE, SEMA42_1_PCC3_SLOT,	CLKSRC_PER_BUS, PCC_NO_DIV, PCC_NO_RST_B},
97 	{PCC3_RBASE, ROMCP1_PCC3_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B},
98 	{PCC3_RBASE, LPIT1_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
99 	{PCC3_RBASE, TPM4_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
100 	{PCC3_RBASE, TPM5_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
101 	{PCC3_RBASE, FLEXIO1_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
102 	{PCC3_RBASE, I3C2_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
103 	{PCC3_RBASE, LPI2C4_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
104 	{PCC3_RBASE, LPI2C5_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
105 	{PCC3_RBASE, LPUART4_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
106 	{PCC3_RBASE, LPUART5_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
107 	{PCC3_RBASE, LPSPI4_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
108 	{PCC3_RBASE, LPSPI5_PCC3_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B},
109 	{}
110 };
111 
112 static struct pcc_entry pcc4_arrays[] = {
113 	{PCC4_RBASE, FLEXSPI2_PCC4_SLOT,	CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B },
114 	{PCC4_RBASE, TPM6_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
115 	{PCC4_RBASE, TPM7_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
116 	{PCC4_RBASE, LPI2C6_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
117 	{PCC4_RBASE, LPI2C7_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
118 	{PCC4_RBASE, LPUART6_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
119 	{PCC4_RBASE, LPUART7_PCC4_SLOT,		CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B },
120 	{PCC4_RBASE, SAI4_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
121 	{PCC4_RBASE, SAI5_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
122 	{PCC4_RBASE, PCTLE_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
123 	{PCC4_RBASE, PCTLF_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
124 	{PCC4_RBASE, SDHC0_PCC4_SLOT,		CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B },
125 	{PCC4_RBASE, SDHC1_PCC4_SLOT,		CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B },
126 	{PCC4_RBASE, SDHC2_PCC4_SLOT,		CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B },
127 	{PCC4_RBASE, USB0_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
128 	{PCC4_RBASE, USBPHY_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
129 	{PCC4_RBASE, USB1_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
130 	{PCC4_RBASE, USB1PHY_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
131 	{PCC4_RBASE, USB_XBAR_PCC4_SLOT,	CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
132 	{PCC4_RBASE, ENET_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B },
133 	{PCC4_RBASE, SFA1_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
134 	{PCC4_RBASE, RGPIOE_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
135 	{PCC4_RBASE, RGPIOF_PCC4_SLOT,		CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B },
136 	{}
137 };
138 
find_pcc_entry(int pcc_controller,int pcc_clk_slot,struct pcc_entry ** out)139 static int find_pcc_entry(int pcc_controller, int pcc_clk_slot, struct pcc_entry **out)
140 {
141 	struct pcc_entry *pcc_array;
142 	int index = 0;
143 
144 	switch (pcc_controller) {
145 	case 3:
146 		pcc_array = pcc3_arrays;
147 		*out = &pcc3_arrays[0];
148 		break;
149 	case 4:
150 		pcc_array = pcc4_arrays;
151 		*out = &pcc4_arrays[0];
152 		break;
153 	default:
154 		printf("Not supported pcc_controller: %d\n", pcc_controller);
155 		return -EINVAL;
156 	}
157 
158 	while (pcc_array->pcc_base) {
159 		if (pcc_array->pcc_slot == pcc_clk_slot)
160 			return index;
161 
162 		pcc_array++;
163 		index++;
164 	}
165 
166 	return -ENOENT;
167 }
168 
pcc_clock_enable(int pcc_controller,int pcc_clk_slot,bool enable)169 int pcc_clock_enable(int pcc_controller, int pcc_clk_slot, bool enable)
170 {
171 	u32 val;
172 	void __iomem *reg;
173 	int clk;
174 	struct pcc_entry *pcc_array;
175 
176 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
177 	if (clk < 0)
178 		return -EINVAL;
179 
180 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
181 
182 	val = readl(reg);
183 
184 	debug("%s: clk %d, reg 0x%p, val 0x%x, enable %d\n", __func__, clk, reg, val, enable);
185 
186 	if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK))
187 		return -EPERM;
188 
189 	if (enable)
190 		val |= PCC_CGC_MASK;
191 	else
192 		val &= ~PCC_CGC_MASK;
193 
194 	writel(val, reg);
195 
196 	debug("%s: val 0x%x\n", __func__, val);
197 
198 	return 0;
199 }
200 
201 /* The clock source select needs clock is disabled */
pcc_clock_sel(int pcc_controller,int pcc_clk_slot,enum cgc1_clk src)202 int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc1_clk src)
203 {
204 	u32 val, i, clksrc_type;
205 	void __iomem *reg;
206 	struct pcc_entry *pcc_array;
207 	enum cgc1_clk *cgc1_clk_array;
208 	int clk;
209 
210 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
211 	if (clk < 0)
212 		return -EINVAL;
213 
214 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
215 
216 	clksrc_type = pcc_array[clk].clksrc;
217 	if (clksrc_type >= CLKSRC_NO_PCS) {
218 		printf("No PCS field for the PCC %d, clksrc type %d\n",
219 		       clk, clksrc_type);
220 		return -EPERM;
221 	}
222 
223 	if (pcc_controller == 3)
224 		cgc1_clk_array = pcc3_clksrc[clksrc_type];
225 	else
226 		cgc1_clk_array = pcc4_clksrc[clksrc_type];
227 
228 	for (i = 0; i < cgc1_clk_NUM; i++) {
229 		if (cgc1_clk_array[i] == src) {
230 			/* Find the clock src, then set it to PCS */
231 			break;
232 		}
233 	}
234 
235 	if (i == cgc1_clk_NUM) {
236 		printf("No parent in PCS of PCC %d, invalid scg_clk %d\n", clk, src);
237 		return -EINVAL;
238 	}
239 
240 	val = readl(reg);
241 
242 	debug("%s: clk %d, reg 0x%p, val 0x%x, clksrc_type %d\n",
243 	      __func__, clk, reg, val, clksrc_type);
244 
245 	if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK) ||
246 	    (val & PCC_CGC_MASK)) {
247 		printf("Not permit to select clock source val = 0x%x\n", val);
248 		return -EPERM;
249 	}
250 
251 	val &= ~PCC_PCS_MASK;
252 	val |= i << PCC_PCS_OFFSET;
253 
254 	writel(val, reg);
255 
256 	debug("%s: val 0x%x\n", __func__, val);
257 
258 	return 0;
259 }
260 
pcc_clock_div_config(int pcc_controller,int pcc_clk_slot,bool frac,u8 div)261 int pcc_clock_div_config(int pcc_controller, int pcc_clk_slot, bool frac, u8 div)
262 {
263 	u32 val;
264 	void __iomem *reg;
265 	struct pcc_entry *pcc_array;
266 	int clk;
267 
268 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
269 	if (clk < 0)
270 		return -EINVAL;
271 
272 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
273 
274 	if (div > 8 || (div == 1 && frac != 0))
275 		return -EINVAL;
276 
277 	if (pcc_array[clk].div >= PCC_NO_DIV) {
278 		printf("No DIV/FRAC field for the PCC %d\n", clk);
279 		return -EPERM;
280 	}
281 
282 	val = readl(reg);
283 
284 	if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK) ||
285 	    (val & PCC_CGC_MASK)) {
286 		printf("Not permit to set div/frac val = 0x%x\n", val);
287 		return -EPERM;
288 	}
289 
290 	if (frac)
291 		val |= PCC_FRAC_MASK;
292 	else
293 		val &= ~PCC_FRAC_MASK;
294 
295 	val &= ~PCC_PCD_MASK;
296 	val |= (div - 1) & PCC_PCD_MASK;
297 
298 	writel(val, reg);
299 
300 	return 0;
301 }
302 
pcc_clock_is_enable(int pcc_controller,int pcc_clk_slot)303 bool pcc_clock_is_enable(int pcc_controller, int pcc_clk_slot)
304 {
305 	u32 val;
306 	void __iomem *reg;
307 	struct pcc_entry *pcc_array;
308 	int clk;
309 
310 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
311 	if (clk < 0)
312 		return -EINVAL;
313 
314 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
315 	val = readl(reg);
316 
317 	if ((val & PCC_INUSE_MASK) || (val & PCC_CGC_MASK))
318 		return true;
319 
320 	return false;
321 }
322 
pcc_clock_get_clksrc(int pcc_controller,int pcc_clk_slot,enum cgc1_clk * src)323 int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc1_clk *src)
324 {
325 	u32 val, clksrc_type;
326 	void __iomem *reg;
327 	struct pcc_entry *pcc_array;
328 	int clk;
329 	enum cgc1_clk *cgc1_clk_array;
330 
331 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
332 	if (clk < 0)
333 		return -EINVAL;
334 
335 	clksrc_type = pcc_array[clk].clksrc;
336 	if (clksrc_type >= CLKSRC_NO_PCS) {
337 		printf("No PCS field for the PCC %d, clksrc type %d\n",
338 		       pcc_clk_slot, clksrc_type);
339 		return -EPERM;
340 	}
341 
342 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
343 
344 	val = readl(reg);
345 
346 	debug("%s: clk %d, reg 0x%p, val 0x%x, type %d\n",
347 	      __func__, pcc_clk_slot, reg, val, clksrc_type);
348 
349 	if (!(val & PCC_PR_MASK)) {
350 		printf("This pcc slot is not present = 0x%x\n", val);
351 		return -EPERM;
352 	}
353 
354 	val &= PCC_PCS_MASK;
355 	val = (val >> PCC_PCS_OFFSET);
356 
357 	if (!val) {
358 		printf("Clock source is off\n");
359 		return -EIO;
360 	}
361 
362 	if (pcc_controller == 3)
363 		cgc1_clk_array = pcc3_clksrc[clksrc_type];
364 	else
365 		cgc1_clk_array = pcc4_clksrc[clksrc_type];
366 
367 	*src = cgc1_clk_array[val];
368 
369 	debug("%s: parent cgc1 clk %d\n", __func__, *src);
370 
371 	return 0;
372 }
373 
pcc_reset_peripheral(int pcc_controller,int pcc_clk_slot,bool reset)374 int pcc_reset_peripheral(int pcc_controller, int pcc_clk_slot, bool reset)
375 {
376 	u32 val;
377 	void __iomem *reg;
378 	struct pcc_entry *pcc_array;
379 	int clk;
380 
381 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
382 	if (clk < 0)
383 		return -EINVAL;
384 
385 	if (pcc_array[clk].rst_b == PCC_NO_RST_B)
386 		return 0;
387 
388 	reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4);
389 
390 	val = readl(reg);
391 
392 	debug("%s: clk %d, reg 0x%p, val 0x%x\n", __func__, pcc_clk_slot, reg, val);
393 
394 	if (!(val & PCC_PR_MASK)) {
395 		printf("This pcc slot is not present = 0x%x\n", val);
396 		return -EPERM;
397 	}
398 
399 	if (reset)
400 		val &= ~BIT(28);
401 	else
402 		val |= BIT(28);
403 
404 	writel(val, reg);
405 
406 	debug("%s: clk %d, reg 0x%p, val 0x%x\n", __func__, pcc_clk_slot, reg, val);
407 
408 	return 0;
409 }
410 
pcc_clock_get_rate(int pcc_controller,int pcc_clk_slot)411 u32 pcc_clock_get_rate(int pcc_controller, int pcc_clk_slot)
412 {
413 	u32 val, rate, frac, div;
414 	void __iomem *reg;
415 	enum cgc1_clk parent;
416 	int ret;
417 	int clk;
418 	struct pcc_entry *pcc_array;
419 
420 	clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array);
421 	if (clk < 0)
422 		return -EINVAL;
423 
424 	ret = pcc_clock_get_clksrc(pcc_controller, pcc_clk_slot, &parent);
425 	if (ret)
426 		return 0;
427 
428 	rate = cgc1_clk_get_rate(parent);
429 
430 	debug("%s: parent rate %u\n", __func__, rate);
431 
432 	if (pcc_array[clk].div == PCC_HAS_DIV) {
433 		reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base +
434 						  pcc_array[clk].pcc_slot * 4);
435 		val = readl(reg);
436 
437 		frac = (val & PCC_FRAC_MASK) >> PCC_FRAC_OFFSET;
438 		div = (val & PCC_PCD_MASK) >> PCC_PCD_OFFSET;
439 
440 		/*
441 		 * Theoretically don't have overflow in the calc,
442 		 * the rate won't exceed 2G
443 		 */
444 		rate = rate * (frac + 1) / (div + 1);
445 	}
446 
447 	debug("%s: rate %u\n", __func__, rate);
448 	return rate;
449 }
450