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 
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 #ifdef CONFIG_FSL_IFC
25 	struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL};
26 	u32 ccr;
27 #endif
28 #if (defined(CONFIG_FSL_ESDHC) &&\
29 	defined(CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK)) ||\
30 	defined(CONFIG_SYS_DPAA_FMAN)
31 
32 	u32 rcw_tmp;
33 #endif
34 	struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_CLK_ADDR);
35 	unsigned int cpu;
36 	const u8 core_cplx_pll[8] = {
37 		[0] = 0,	/* CC1 PPL / 1 */
38 		[1] = 0,	/* CC1 PPL / 2 */
39 		[4] = 1,	/* CC2 PPL / 1 */
40 		[5] = 1,	/* CC2 PPL / 2 */
41 	};
42 
43 	const u8 core_cplx_pll_div[8] = {
44 		[0] = 1,	/* CC1 PPL / 1 */
45 		[1] = 2,	/* CC1 PPL / 2 */
46 		[4] = 1,	/* CC2 PPL / 1 */
47 		[5] = 2,	/* CC2 PPL / 2 */
48 	};
49 
50 	uint i;
51 	uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
52 	uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
53 	unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
54 
55 	sys_info->freq_systembus = sysclk;
56 #ifdef CONFIG_DDR_CLK_FREQ
57 	sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
58 #else
59 	sys_info->freq_ddrbus = sysclk;
60 #endif
61 
62 #ifdef CONFIG_LS1012A
63 	sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
64 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
65 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
66 #else
67 	sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
68 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
69 			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
70 	sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
71 			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) &
72 			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK;
73 #endif
74 
75 	for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
76 		ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0xff;
77 		if (ratio[i] > 4)
78 			freq_c_pll[i] = sysclk * ratio[i];
79 		else
80 			freq_c_pll[i] = sys_info->freq_systembus * ratio[i];
81 	}
82 
83 	for (cpu = 0; cpu < CONFIG_MAX_CPUS; cpu++) {
84 		u32 c_pll_sel = (in_be32(&clk->clkcsr[cpu].clkcncsr) >> 27)
85 				& 0xf;
86 		u32 cplx_pll = core_cplx_pll[c_pll_sel];
87 
88 		sys_info->freq_processor[cpu] =
89 			freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel];
90 	}
91 
92 #ifdef CONFIG_LS1012A
93 	sys_info->freq_systembus = sys_info->freq_ddrbus / 2;
94 	sys_info->freq_ddrbus *= 2;
95 #endif
96 
97 #define HWA_CGA_M1_CLK_SEL	0xe0000000
98 #define HWA_CGA_M1_CLK_SHIFT	29
99 #ifdef CONFIG_SYS_DPAA_FMAN
100 	rcw_tmp = in_be32(&gur->rcwsr[7]);
101 	switch ((rcw_tmp & HWA_CGA_M1_CLK_SEL) >> HWA_CGA_M1_CLK_SHIFT) {
102 	case 2:
103 		sys_info->freq_fman[0] = freq_c_pll[0] / 2;
104 		break;
105 	case 3:
106 		sys_info->freq_fman[0] = freq_c_pll[0] / 3;
107 		break;
108 	case 6:
109 		sys_info->freq_fman[0] = freq_c_pll[1] / 2;
110 		break;
111 	case 7:
112 		sys_info->freq_fman[0] = freq_c_pll[1] / 3;
113 		break;
114 	default:
115 		printf("Error: Unknown FMan1 clock select!\n");
116 		break;
117 	}
118 #endif
119 
120 #define HWA_CGA_M2_CLK_SEL	0x00000007
121 #define HWA_CGA_M2_CLK_SHIFT	0
122 #ifdef CONFIG_FSL_ESDHC
123 #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
124 	rcw_tmp = in_be32(&gur->rcwsr[15]);
125 	rcw_tmp = (rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT;
126 	sys_info->freq_sdhc = freq_c_pll[1] / rcw_tmp;
127 #else
128 	sys_info->freq_sdhc = sys_info->freq_systembus;
129 #endif
130 #endif
131 
132 #if defined(CONFIG_FSL_IFC)
133 	ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr);
134 	ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
135 
136 	sys_info->freq_localbus = sys_info->freq_systembus / ccr;
137 #endif
138 }
139 
140 int get_clocks(void)
141 {
142 	struct sys_info sys_info;
143 
144 	get_sys_info(&sys_info);
145 	gd->cpu_clk = sys_info.freq_processor[0];
146 	gd->bus_clk = sys_info.freq_systembus;
147 	gd->mem_clk = sys_info.freq_ddrbus;
148 
149 #ifdef CONFIG_FSL_ESDHC
150 	gd->arch.sdhc_clk = sys_info.freq_sdhc;
151 #endif
152 
153 	if (gd->cpu_clk != 0)
154 		return 0;
155 	else
156 		return 1;
157 }
158 
159 ulong get_bus_freq(ulong dummy)
160 {
161 	return gd->bus_clk;
162 }
163 
164 ulong get_ddr_freq(ulong dummy)
165 {
166 	return gd->mem_clk;
167 }
168 
169 #ifdef CONFIG_FSL_ESDHC
170 int get_sdhc_freq(ulong dummy)
171 {
172 	return gd->arch.sdhc_clk;
173 }
174 #endif
175 
176 int get_serial_clock(void)
177 {
178 	return gd->bus_clk;
179 }
180 
181 unsigned int mxc_get_clock(enum mxc_clock clk)
182 {
183 	switch (clk) {
184 	case MXC_I2C_CLK:
185 		return get_bus_freq(0);
186 #if defined(CONFIG_FSL_ESDHC)
187 	case MXC_ESDHC_CLK:
188 		return get_sdhc_freq(0);
189 #endif
190 	case MXC_DSPI_CLK:
191 		return get_bus_freq(0);
192 	case MXC_UART_CLK:
193 		return get_bus_freq(0);
194 	default:
195 		printf("Unsupported clock\n");
196 	}
197 	return 0;
198 }
199