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