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 #endif
160 }
161 
162 #ifdef CONFIG_SYS_DPAA_QBMAN
163 unsigned long get_qman_freq(void)
164 {
165 	struct sys_info sys_info;
166 
167 	get_sys_info(&sys_info);
168 
169 	return sys_info.freq_qman;
170 }
171 #endif
172 
173 int get_clocks(void)
174 {
175 	struct sys_info sys_info;
176 
177 	get_sys_info(&sys_info);
178 	gd->cpu_clk = sys_info.freq_processor[0];
179 	gd->bus_clk = sys_info.freq_systembus / CONFIG_SYS_FSL_PCLK_DIV;
180 	gd->mem_clk = sys_info.freq_ddrbus;
181 
182 #ifdef CONFIG_FSL_ESDHC
183 	gd->arch.sdhc_clk = sys_info.freq_sdhc;
184 #endif
185 
186 	if (gd->cpu_clk != 0)
187 		return 0;
188 	else
189 		return 1;
190 }
191 
192 /********************************************
193  * get_bus_freq
194  * return platform clock in Hz
195  *********************************************/
196 ulong get_bus_freq(ulong dummy)
197 {
198 	if (!gd->bus_clk)
199 		get_clocks();
200 
201 	return gd->bus_clk;
202 }
203 
204 ulong get_ddr_freq(ulong dummy)
205 {
206 	if (!gd->mem_clk)
207 		get_clocks();
208 
209 	return gd->mem_clk;
210 }
211 
212 #ifdef CONFIG_FSL_ESDHC
213 int get_sdhc_freq(ulong dummy)
214 {
215 	if (!gd->arch.sdhc_clk)
216 		get_clocks();
217 
218 	return gd->arch.sdhc_clk;
219 }
220 #endif
221 
222 int get_serial_clock(void)
223 {
224 	return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV;
225 }
226 
227 int get_i2c_freq(ulong dummy)
228 {
229 	return get_bus_freq(0) / CONFIG_SYS_FSL_I2C_CLK_DIV;
230 }
231 
232 int get_dspi_freq(ulong dummy)
233 {
234 	return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV;
235 }
236 
237 #ifdef CONFIG_FSL_LPUART
238 int get_uart_freq(ulong dummy)
239 {
240 	return get_bus_freq(0) / CONFIG_SYS_FSL_LPUART_CLK_DIV;
241 }
242 #endif
243 
244 unsigned int mxc_get_clock(enum mxc_clock clk)
245 {
246 	switch (clk) {
247 	case MXC_I2C_CLK:
248 		return get_i2c_freq(0);
249 #if defined(CONFIG_FSL_ESDHC)
250 	case MXC_ESDHC_CLK:
251 		return get_sdhc_freq(0);
252 #endif
253 	case MXC_DSPI_CLK:
254 		return get_dspi_freq(0);
255 #ifdef CONFIG_FSL_LPUART
256 	case MXC_UART_CLK:
257 		return get_uart_freq(0);
258 #endif
259 	default:
260 		printf("Unsupported clock\n");
261 	}
262 	return 0;
263 }
264