]>
Commit | Line | Data |
---|---|---|
2f78eae5 YS |
1 | /* |
2 | * Copyright 2014, Freescale Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | * | |
6 | * Derived from arch/power/cpu/mpc85xx/speed.c | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <linux/compiler.h> | |
11 | #include <fsl_ifc.h> | |
12 | #include <asm/processor.h> | |
13 | #include <asm/io.h> | |
14 | #include <asm/arch-fsl-lsch3/immap_lsch3.h> | |
15 | #include <asm/arch/clock.h> | |
16 | #include "cpu.h" | |
17 | ||
18 | DECLARE_GLOBAL_DATA_PTR; | |
19 | ||
20 | #ifndef CONFIG_SYS_FSL_NUM_CC_PLLS | |
21 | #define CONFIG_SYS_FSL_NUM_CC_PLLS 6 | |
22 | #endif | |
23 | ||
24 | ||
25 | void get_sys_info(struct sys_info *sys_info) | |
26 | { | |
27 | struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); | |
28 | #ifdef CONFIG_FSL_IFC | |
29 | struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR; | |
30 | u32 ccr; | |
31 | #endif | |
32 | struct ccsr_clk_cluster_group __iomem *clk_grp[2] = { | |
33 | (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR), | |
34 | (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR) | |
35 | }; | |
36 | struct ccsr_clk_ctrl __iomem *clk_ctrl = | |
37 | (void *)(CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR); | |
38 | unsigned int cpu; | |
39 | const u8 core_cplx_pll[16] = { | |
40 | [0] = 0, /* CC1 PPL / 1 */ | |
41 | [1] = 0, /* CC1 PPL / 2 */ | |
42 | [2] = 0, /* CC1 PPL / 4 */ | |
43 | [4] = 1, /* CC2 PPL / 1 */ | |
44 | [5] = 1, /* CC2 PPL / 2 */ | |
45 | [6] = 1, /* CC2 PPL / 4 */ | |
46 | [8] = 2, /* CC3 PPL / 1 */ | |
47 | [9] = 2, /* CC3 PPL / 2 */ | |
48 | [10] = 2, /* CC3 PPL / 4 */ | |
49 | [12] = 3, /* CC4 PPL / 1 */ | |
50 | [13] = 3, /* CC4 PPL / 2 */ | |
51 | [14] = 3, /* CC4 PPL / 4 */ | |
52 | }; | |
53 | ||
54 | const u8 core_cplx_pll_div[16] = { | |
55 | [0] = 1, /* CC1 PPL / 1 */ | |
56 | [1] = 2, /* CC1 PPL / 2 */ | |
57 | [2] = 4, /* CC1 PPL / 4 */ | |
58 | [4] = 1, /* CC2 PPL / 1 */ | |
59 | [5] = 2, /* CC2 PPL / 2 */ | |
60 | [6] = 4, /* CC2 PPL / 4 */ | |
61 | [8] = 1, /* CC3 PPL / 1 */ | |
62 | [9] = 2, /* CC3 PPL / 2 */ | |
63 | [10] = 4, /* CC3 PPL / 4 */ | |
64 | [12] = 1, /* CC4 PPL / 1 */ | |
65 | [13] = 2, /* CC4 PPL / 2 */ | |
66 | [14] = 4, /* CC4 PPL / 4 */ | |
67 | }; | |
68 | ||
69 | uint i, cluster; | |
70 | uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS]; | |
71 | uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS]; | |
72 | unsigned long sysclk = CONFIG_SYS_CLK_FREQ; | |
73 | int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS; | |
74 | u32 c_pll_sel, cplx_pll; | |
75 | void *offset; | |
76 | ||
77 | sys_info->freq_systembus = sysclk; | |
78 | #ifdef CONFIG_DDR_CLK_FREQ | |
79 | sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ; | |
b87e6f88 | 80 | sys_info->freq_ddrbus2 = CONFIG_DDR_CLK_FREQ; |
2f78eae5 YS |
81 | #else |
82 | sys_info->freq_ddrbus = sysclk; | |
b87e6f88 | 83 | sys_info->freq_ddrbus2 = sysclk; |
2f78eae5 YS |
84 | #endif |
85 | ||
86 | sys_info->freq_systembus *= (in_le32(&gur->rcwsr[0]) >> | |
87 | FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) & | |
88 | FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK; | |
89 | sys_info->freq_ddrbus *= (in_le32(&gur->rcwsr[0]) >> | |
90 | FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) & | |
91 | FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK; | |
b87e6f88 YS |
92 | sys_info->freq_ddrbus2 *= (in_le32(&gur->rcwsr[0]) >> |
93 | FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_SHIFT) & | |
94 | FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_MASK; | |
2f78eae5 YS |
95 | |
96 | for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) { | |
97 | /* | |
98 | * fixme: prefer to combine the following into one line, but | |
99 | * cannot pass compiling without warning about in_le32. | |
100 | */ | |
101 | offset = (void *)((size_t)clk_grp[i/3] + | |
102 | offsetof(struct ccsr_clk_cluster_group, | |
103 | pllngsr[i%3].gsr)); | |
104 | ratio[i] = (in_le32(offset) >> 1) & 0x3f; | |
105 | if (ratio[i] > 4) | |
106 | freq_c_pll[i] = sysclk * ratio[i]; | |
107 | else | |
108 | freq_c_pll[i] = sys_info->freq_systembus * ratio[i]; | |
109 | } | |
110 | ||
111 | for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) { | |
112 | cluster = fsl_qoriq_core_to_cluster(cpu); | |
113 | c_pll_sel = (in_le32(&clk_ctrl->clkcncsr[cluster].csr) >> 27) | |
114 | & 0xf; | |
115 | cplx_pll = core_cplx_pll[c_pll_sel]; | |
116 | cplx_pll += cc_group[cluster] - 1; | |
117 | sys_info->freq_processor[cpu] = | |
118 | freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel]; | |
119 | } | |
120 | ||
121 | #if defined(CONFIG_FSL_IFC) | |
122 | ccr = in_le32(&ifc_regs->ifc_ccr); | |
123 | ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; | |
124 | ||
125 | sys_info->freq_localbus = sys_info->freq_systembus / ccr; | |
126 | #endif | |
127 | } | |
128 | ||
129 | ||
130 | int get_clocks(void) | |
131 | { | |
132 | struct sys_info sys_info; | |
133 | get_sys_info(&sys_info); | |
134 | gd->cpu_clk = sys_info.freq_processor[0]; | |
135 | gd->bus_clk = sys_info.freq_systembus; | |
136 | gd->mem_clk = sys_info.freq_ddrbus; | |
b87e6f88 | 137 | gd->arch.mem2_clk = sys_info.freq_ddrbus2; |
2f78eae5 YS |
138 | #if defined(CONFIG_FSL_ESDHC) |
139 | gd->arch.sdhc_clk = gd->bus_clk / 2; | |
140 | #endif /* defined(CONFIG_FSL_ESDHC) */ | |
141 | ||
142 | if (gd->cpu_clk != 0) | |
143 | return 0; | |
144 | else | |
145 | return 1; | |
146 | } | |
147 | ||
148 | /******************************************** | |
149 | * get_bus_freq | |
150 | * return system bus freq in Hz | |
151 | *********************************************/ | |
152 | ulong get_bus_freq(ulong dummy) | |
153 | { | |
154 | if (!gd->bus_clk) | |
155 | get_clocks(); | |
156 | ||
157 | return gd->bus_clk; | |
158 | } | |
159 | ||
160 | /******************************************** | |
161 | * get_ddr_freq | |
162 | * return ddr bus freq in Hz | |
163 | *********************************************/ | |
b87e6f88 | 164 | ulong get_ddr_freq(ulong ctrl_num) |
2f78eae5 YS |
165 | { |
166 | if (!gd->mem_clk) | |
167 | get_clocks(); | |
168 | ||
b87e6f88 YS |
169 | /* |
170 | * DDR controller 0 & 1 are on memory complex 0 | |
171 | * DDR controler 2 is on memory complext 1 | |
172 | */ | |
173 | if (ctrl_num >= 2) | |
174 | return gd->arch.mem2_clk; | |
175 | ||
2f78eae5 YS |
176 | return gd->mem_clk; |
177 | } | |
178 | ||
179 | unsigned int mxc_get_clock(enum mxc_clock clk) | |
180 | { | |
181 | switch (clk) { | |
182 | case MXC_I2C_CLK: | |
183 | return get_bus_freq(0) / 2; | |
184 | default: | |
185 | printf("Unsupported clock\n"); | |
186 | } | |
187 | return 0; | |
188 | } |