1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2015 Freescale Semiconductor, Inc.
4  */
5 
6 #include <common.h>
7 #include <linux/compiler.h>
8 #include <asm/io.h>
9 #include <asm/processor.h>
10 #include <asm/arch/clock.h>
11 #include <asm/arch/soc.h>
12 #include <fsl_ifc.h>
13 #include "cpu.h"
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 #ifndef CONFIG_SYS_FSL_NUM_CC_PLLS
18 #define CONFIG_SYS_FSL_NUM_CC_PLLS      2
19 #endif
20 
21 void get_sys_info(struct sys_info *sys_info)
22 {
23 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
24 #if (defined(CONFIG_FSL_ESDHC) &&\
25 	defined(CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK)) ||\
26 	defined(CONFIG_SYS_DPAA_FMAN)
27 
28 	u32 rcw_tmp;
29 #endif
30 	struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_CLK_ADDR);
31 	unsigned int cpu;
32 	const u8 core_cplx_pll[8] = {
33 		[0] = 0,	/* CC1 PPL / 1 */
34 		[1] = 0,	/* CC1 PPL / 2 */
35 		[4] = 1,	/* CC2 PPL / 1 */
36 		[5] = 1,	/* CC2 PPL / 2 */
37 	};
38 
39 	const u8 core_cplx_pll_div[8] = {
40 		[0] = 1,	/* CC1 PPL / 1 */
41 		[1] = 2,	/* CC1 PPL / 2 */
42 		[4] = 1,	/* CC2 PPL / 1 */
43 		[5] = 2,	/* CC2 PPL / 2 */
44 	};
45 
46 	uint i, cluster;
47 	uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
48 	uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
49 	unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
50 	unsigned long cluster_clk;
51 
52 	sys_info->freq_systembus = sysclk;
53 #ifndef CONFIG_CLUSTER_CLK_FREQ
54 #define CONFIG_CLUSTER_CLK_FREQ	CONFIG_SYS_CLK_FREQ
55 #endif
56 	cluster_clk = CONFIG_CLUSTER_CLK_FREQ;
57 
58 #ifdef CONFIG_DDR_CLK_FREQ
59 	sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
60 #else
61 	sys_info->freq_ddrbus = sysclk;
62 #endif
63 
64 	/* The freq_systembus is used to record frequency of platform PLL */
65 	sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
66 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
67 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
68 
69 #ifdef CONFIG_ARCH_LS1012A
70 	sys_info->freq_ddrbus = 2 * sys_info->freq_systembus;
71 #else
72 	sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
73 			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) &
74 			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK;
75 #endif
76 
77 	for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
78 		ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0xff;
79 		if (ratio[i] > 4)
80 			freq_c_pll[i] = cluster_clk * ratio[i];
81 		else
82 			freq_c_pll[i] = sys_info->freq_systembus * ratio[i];
83 	}
84 
85 	for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) {
86 		cluster = fsl_qoriq_core_to_cluster(cpu);
87 		u32 c_pll_sel = (in_be32(&clk->clkcsr[cluster].clkcncsr) >> 27)
88 				& 0xf;
89 		u32 cplx_pll = core_cplx_pll[c_pll_sel];
90 
91 		sys_info->freq_processor[cpu] =
92 			freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel];
93 	}
94 
95 #define HWA_CGA_M1_CLK_SEL	0xe0000000
96 #define HWA_CGA_M1_CLK_SHIFT	29
97 #ifdef CONFIG_SYS_DPAA_FMAN
98 	rcw_tmp = in_be32(&gur->rcwsr[7]);
99 	switch ((rcw_tmp & HWA_CGA_M1_CLK_SEL) >> HWA_CGA_M1_CLK_SHIFT) {
100 	case 2:
101 		sys_info->freq_fman[0] = freq_c_pll[0] / 2;
102 		break;
103 	case 3:
104 		sys_info->freq_fman[0] = freq_c_pll[0] / 3;
105 		break;
106 	case 4:
107 		sys_info->freq_fman[0] = freq_c_pll[0] / 4;
108 		break;
109 	case 5:
110 		sys_info->freq_fman[0] = sys_info->freq_systembus;
111 		break;
112 	case 6:
113 		sys_info->freq_fman[0] = freq_c_pll[1] / 2;
114 		break;
115 	case 7:
116 		sys_info->freq_fman[0] = freq_c_pll[1] / 3;
117 		break;
118 	default:
119 		printf("Error: Unknown FMan1 clock select!\n");
120 		break;
121 	}
122 #endif
123 
124 #define HWA_CGA_M2_CLK_SEL	0x00000007
125 #define HWA_CGA_M2_CLK_SHIFT	0
126 #ifdef CONFIG_FSL_ESDHC
127 #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
128 	rcw_tmp = in_be32(&gur->rcwsr[15]);
129 	switch ((rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT) {
130 	case 1:
131 		sys_info->freq_sdhc = freq_c_pll[1];
132 		break;
133 	case 2:
134 		sys_info->freq_sdhc = freq_c_pll[1] / 2;
135 		break;
136 	case 3:
137 		sys_info->freq_sdhc = freq_c_pll[1] / 3;
138 		break;
139 	case 6:
140 		sys_info->freq_sdhc = freq_c_pll[0] / 2;
141 		break;
142 	default:
143 		printf("Error: Unknown ESDHC clock select!\n");
144 		break;
145 	}
146 #else
147 	sys_info->freq_sdhc = (sys_info->freq_systembus /
148 				CONFIG_SYS_FSL_PCLK_DIV) /
149 				CONFIG_SYS_FSL_SDHC_CLK_DIV;
150 #endif
151 #endif
152 
153 #if defined(CONFIG_FSL_IFC)
154 	sys_info->freq_localbus = sys_info->freq_systembus /
155 						CONFIG_SYS_FSL_IFC_CLK_DIV;
156 #endif
157 #ifdef CONFIG_SYS_DPAA_QBMAN
158 	sys_info->freq_qman = (sys_info->freq_systembus /
159 				CONFIG_SYS_FSL_PCLK_DIV) /
160 				CONFIG_SYS_FSL_QMAN_CLK_DIV;
161 #endif
162 }
163 
164 #ifdef CONFIG_SYS_DPAA_QBMAN
165 unsigned long get_qman_freq(void)
166 {
167 	struct sys_info sys_info;
168 
169 	get_sys_info(&sys_info);
170 
171 	return sys_info.freq_qman;
172 }
173 #endif
174 
175 int get_clocks(void)
176 {
177 	struct sys_info sys_info;
178 
179 	get_sys_info(&sys_info);
180 	gd->cpu_clk = sys_info.freq_processor[0];
181 	gd->bus_clk = sys_info.freq_systembus / CONFIG_SYS_FSL_PCLK_DIV;
182 	gd->mem_clk = sys_info.freq_ddrbus;
183 
184 #ifdef CONFIG_FSL_ESDHC
185 	gd->arch.sdhc_clk = sys_info.freq_sdhc;
186 #endif
187 
188 	if (gd->cpu_clk != 0)
189 		return 0;
190 	else
191 		return 1;
192 }
193 
194 /********************************************
195  * get_bus_freq
196  * return platform clock in Hz
197  *********************************************/
198 ulong get_bus_freq(ulong dummy)
199 {
200 	if (!gd->bus_clk)
201 		get_clocks();
202 
203 	return gd->bus_clk;
204 }
205 
206 ulong get_ddr_freq(ulong dummy)
207 {
208 	if (!gd->mem_clk)
209 		get_clocks();
210 
211 	return gd->mem_clk;
212 }
213 
214 #ifdef CONFIG_FSL_ESDHC
215 int get_sdhc_freq(ulong dummy)
216 {
217 	if (!gd->arch.sdhc_clk)
218 		get_clocks();
219 
220 	return gd->arch.sdhc_clk;
221 }
222 #endif
223 
224 int get_serial_clock(void)
225 {
226 	return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV;
227 }
228 
229 int get_i2c_freq(ulong dummy)
230 {
231 	return get_bus_freq(0) / CONFIG_SYS_FSL_I2C_CLK_DIV;
232 }
233 
234 int get_dspi_freq(ulong dummy)
235 {
236 	return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV;
237 }
238 
239 #ifdef CONFIG_FSL_LPUART
240 int get_uart_freq(ulong dummy)
241 {
242 	return get_bus_freq(0) / CONFIG_SYS_FSL_LPUART_CLK_DIV;
243 }
244 #endif
245 
246 unsigned int mxc_get_clock(enum mxc_clock clk)
247 {
248 	switch (clk) {
249 	case MXC_I2C_CLK:
250 		return get_i2c_freq(0);
251 #if defined(CONFIG_FSL_ESDHC)
252 	case MXC_ESDHC_CLK:
253 		return get_sdhc_freq(0);
254 #endif
255 	case MXC_DSPI_CLK:
256 		return get_dspi_freq(0);
257 #ifdef CONFIG_FSL_LPUART
258 	case MXC_UART_CLK:
259 		return get_uart_freq(0);
260 #endif
261 	default:
262 		printf("Unsupported clock\n");
263 	}
264 	return 0;
265 }
266