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