blob: 98e66735eb9eb546bbb3bbe20c54489589293e89 [file] [log] [blame]
Chris Packhameaab4612022-11-05 17:23:59 +13001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Marvell International Ltd.
4 */
5
Chris Packhameaab4612022-11-05 17:23:59 +13006#include <asm/arch-armada8k/cache_llc.h>
7#include <asm/io.h>
8#include <asm/arch/cpu.h>
9#include <asm/arch/soc.h>
10#include <dm/device.h>
11
12#define DEVICE_ID_REG 0x7F90004C
13#define DEVICE_ID_MASK 0xffff0
14#define REV_ID_MASK 0xf
15#define DEVICE_ID_OFFSET 4
16#define REV_ID_OFFSET 0
17
18#define DEVICE_SAR_REG 0x944F8204
19
20#define DEVICE_ID_SUB_REV (MVEBU_REGISTER(0x2400230))
21#define DEVICE_ID_SUB_REV_OFFSET 7
22#define DEVICE_ID_SUB_REV_MASK (0xffff << DEVICE_ID_SUB_REV_OFFSET)
23
24#define AC5X_DEV_ID 0x9800
25
26struct soc_info {
27 u32 dev_id;
28 u32 rev_id;
29 char *soc_name;
30};
31
32static struct soc_info soc_info_table[] = {
33 /* Two reserved entries for unidentified devices - don't change */
34 { 0xB4FF, 0x0, "Unidentified Alleycat5"},
35 { 0x98FF, 0x0, "Unidentified Alleycat5x"},
36
37 { 0xB400, 0x2, "Alleycat5-plus 98DX2538-A2"},
38 { 0xB401, 0x2, "Alleycat5-plus 98DX2535-A2"},
39 { 0xB402, 0x2, "Alleycat5-plus 98DX2532-A2"},
40 { 0xB403, 0x2, "Alleycat5-plus 98DX2531-A2"},
41 { 0xB408, 0x2, "Alleycat5 98DX2528-A2"},
42 { 0xB409, 0x2, "Alleycat5 98DX2525-A2"},
43 { 0xB40A, 0x2, "Alleycat5 98DX2522-A2"},
44 { 0xB40B, 0x2, "Alleycat5 98DX2521-A2"},
45 { 0xB410, 0x2, "Alleycat5-lite 98DX2518-A2"},
46 { 0xB411, 0x2, "Alleycat5-lite 98DX2515-A2"},
47 { 0xB412, 0x2, "Alleycat5-lite 98DX2512-A2"},
48 { 0xB413, 0x2, "Alleycat5-lite 98DX2511-A2"},
49
50 { 0xB400, 0x1, "Alleycat5-plus 98DX2538-A1"},
51 { 0xB401, 0x1, "Alleycat5-plus 98DX2535-A1"},
52 { 0xB402, 0x1, "Alleycat5-plus 98DX2532-A1"},
53 { 0xB403, 0x1, "Alleycat5-plus 98DX2531-A1"},
54 { 0xB408, 0x1, "Alleycat5 98DX2528-A1"},
55 { 0xB409, 0x1, "Alleycat5 98DX2525-A1"},
56 { 0xB40A, 0x1, "Alleycat5 98DX2522-A1"},
57 { 0xB40B, 0x1, "Alleycat5 98DX2521-A1"},
58 { 0xB410, 0x1, "Alleycat5-lite 98DX2518-A1"},
59 { 0xB411, 0x1, "Alleycat5-lite 98DX2515-A1"},
60 { 0xB412, 0x1, "Alleycat5-lite 98DX2512-A1"},
61 { 0xB413, 0x1, "Alleycat5-lite 98DX2511-A1"},
62 { 0x9800, 0x1, "Alleycat5X 98DX3500M-A1"},
63 { 0x9806, 0x1, "Alleycat5X 98DX3501M-A1"},
64 { 0x9801, 0x1, "Alleycat5X 98DX3510M-A1"},
65 { 0x9802, 0x1, "Alleycat5X 98DX3520M-A1"},
66 { 0x9803, 0x1, "Alleycat5X 98DX3530M-A1"},
67 { 0x9804, 0x1, "Alleycat5X 98DX3540M-A1"},
68 { 0x9805, 0x1, "Alleycat5X 98DX3550M-A1"},
69 { 0x9820, 0x1, "Alleycat5X 98DX3500-A1"},
70 { 0x9826, 0x1, "Alleycat5X 98DX3501-A1"},
71 { 0x9821, 0x1, "Alleycat5X 98DX3510-A1"},
72 { 0x9861, 0x1, "Alleycat5X 98DX3510H-A1"},
73 { 0x9841, 0x1, "Alleycat5X 98DX3510MH-A1"},
74 { 0x9822, 0x1, "Alleycat5X 98DX3520-A1"},
75 { 0x9823, 0x1, "Alleycat5X 98DX3530-A1"},
76 { 0x9863, 0x1, "Alleycat5X 98DX3530H-A1"},
77 { 0x9824, 0x1, "Alleycat5X 98DX3540-A1"},
78 { 0x9825, 0x1, "Alleycat5X 98DX3550-A1"},
79
80 { 0xB400, 0x0, "Alleycat5-plus 98DX2538-A0"},
81 { 0xB401, 0x0, "Alleycat5-plus 98DX2535-A0"},
82 { 0xB402, 0x0, "Alleycat5-plus 98DX2532-A0"},
83 { 0xB403, 0x0, "Alleycat5-plus 98DX2531-A0"},
84 { 0xB408, 0x0, "Alleycat5 98DX2528-A0"},
85 { 0xB409, 0x0, "Alleycat5 98DX2525-A0"},
86 { 0xB40A, 0x0, "Alleycat5 98DX2522-A0"},
87 { 0xB40B, 0x0, "Alleycat5 98DX2521-A0"},
88 { 0xB410, 0x0, "Alleycat5-lite 98DX2518-A0"},
89 { 0xB411, 0x0, "Alleycat5-lite 98DX2515-A0"},
90 { 0xB412, 0x0, "Alleycat5-lite 98DX2512-A0"},
91 { 0xB413, 0x0, "Alleycat5-lite 98DX2511-A0"},
92 { 0x9800, 0x0, "Alleycat5X 98DX3500M-A0"},
93 { 0x9806, 0x0, "Alleycat5X 98DX3501M-A0"},
94 { 0x9801, 0x0, "Alleycat5X 98DX3510M-A0"},
95 { 0x9802, 0x0, "Alleycat5X 98DX3520M-A0"},
96 { 0x9803, 0x0, "Alleycat5X 98DX3530M-A0"},
97 { 0x9804, 0x0, "Alleycat5X 98DX3540M-A0"},
98 { 0x9805, 0x0, "Alleycat5X 98DX3550M-A0"},
99 { 0x9820, 0x0, "Alleycat5X 98DX3500-A0"},
100 { 0x9826, 0x0, "Alleycat5X 98DX3501-A0"},
101 { 0x9821, 0x0, "Alleycat5X 98DX3510-A0"},
102 { 0x9861, 0x0, "Alleycat5X 98DX3510H-A0"},
103 { 0x9841, 0x0, "Alleycat5X 98DX3510MH-A0"},
104 { 0x9822, 0x0, "Alleycat5X 98DX3520-A0"},
105 { 0x9823, 0x0, "Alleycat5X 98DX3530-A0"},
106 { 0x9863, 0x0, "Alleycat5X 98DX3530H-A0"},
107 { 0x9824, 0x0, "Alleycat5X 98DX3540-A0"},
108 { 0x9825, 0x0, "Alleycat5X 98DX3550-A0"},
109};
110
111#define BIT_VAL(b) ((1ULL << ((b) + 1)) - 1)
112#define BIT_RANGE(bl, bh) (BIT_VAL(bh) - BIT_VAL((bl) - 1))
113
114#define PLL_MAX_CHOICE 4
115
116#define CPU_TYPE_AC5 0
117#define CPU_TYPE_AC5x 1
118#define CPU_TYPE_LAST 2
119
120enum mvebu_sar_opts {
121 SAR_CPU_FREQ = 0,
122 SAR_DDR_FREQ,
123 SAR_AP_FABRIC_FREQ,
124 SAR_CP_FABRIC_FREQ,
125 SAR_CP0_PCIE0_CLK,
126 SAR_CP0_PCIE1_CLK,
127 SAR_CP1_PCIE0_CLK,
128 SAR_CP1_PCIE1_CLK,
129 SAR_BOOT_SRC,
130 SAR_MAX_IDX
131};
132
133static const u32 pll_freq_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1][PLL_MAX_CHOICE] = {
134 [CPU_TYPE_AC5] = {
135 [SAR_CPU_FREQ] = {
136 800, 1200, 1400, 1000
137 },
138 [SAR_DDR_FREQ] = {
139 1200, 800, 0, 0
140 },
141 [SAR_AP_FABRIC_FREQ] = {
142 396, 290, 197, 0
143 },
144 },
145 [CPU_TYPE_AC5x] = {
146 [SAR_CPU_FREQ] = {
147 800, 1200, 1500, 1600
148 },
149 [SAR_DDR_FREQ] = {
150 1200, 800, 0, 0
151 },
152 [SAR_AP_FABRIC_FREQ] = {
153 0, 0, 0, 0
154 }
155 }
156};
157
158static const u32 soc_sar_masks_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1] = {
159 [CPU_TYPE_AC5] = {
160 [SAR_CPU_FREQ] = BIT_RANGE(18, 20),
161 [SAR_DDR_FREQ] = BIT_RANGE(16, 17),
162 [SAR_AP_FABRIC_FREQ] = BIT_RANGE(22, 23),
163 },
164 [CPU_TYPE_AC5x] = {
165 [SAR_CPU_FREQ] = BIT_RANGE(8, 10),
166 [SAR_DDR_FREQ] = BIT_RANGE(6, 7),
167 [SAR_AP_FABRIC_FREQ] = 1,
168 },
169};
170
171static int get_soc_type_rev(u32 *type, u32 *rev)
172{
173 *type = (readl(DEVICE_ID_REG) & DEVICE_ID_MASK) >> DEVICE_ID_OFFSET;
174 *rev = (readl(DEVICE_ID_REG) & REV_ID_MASK) >> REV_ID_OFFSET;
175
176 return 0;
177}
178
179static void get_one_sar_freq(int cpu_type, u32 sar_reg_val, enum mvebu_sar_opts sar_opt, u32 *freq)
180{
181 u32 mask;
182 unsigned char choice;
183
184 mask = soc_sar_masks_tbl[cpu_type][sar_opt];
185 choice = (sar_reg_val & mask) >> (__builtin_ffs(mask) - 1);
186 *freq = pll_freq_tbl[cpu_type][sar_opt][choice];
187}
188
189void get_sar_freq(struct sar_freq_modes *sar_freq)
190{
191 int cpu_type;
192 u32 soc_type, rev;
193 u32 sar_reg_val = readl(DEVICE_SAR_REG);
194
195 get_soc_type_rev(&soc_type, &rev);
196 cpu_type = (soc_type & 0xFF00) == AC5X_DEV_ID ? CPU_TYPE_AC5x : CPU_TYPE_AC5;
197
198 get_one_sar_freq(cpu_type, sar_reg_val, SAR_CPU_FREQ, &sar_freq->p_clk);
199 get_one_sar_freq(cpu_type, sar_reg_val, SAR_AP_FABRIC_FREQ, &sar_freq->nb_clk);
200 get_one_sar_freq(cpu_type, sar_reg_val, SAR_DDR_FREQ, &sar_freq->d_clk);
201}
202
203static int get_soc_table_index(u32 *index)
204{
205 u32 soc_type;
206 u32 rev, i, ret = 1;
207
208 *index = 0;
209 get_soc_type_rev(&soc_type, &rev);
210
211 for (i = 0; i < ARRAY_SIZE(soc_info_table) && ret != 0; i++) {
212 if (soc_type != soc_info_table[i].dev_id ||
213 rev != soc_info_table[i].rev_id)
214 continue;
215
216 *index = i;
217 ret = 0;
218 }
219
220 if (ret && ((soc_type & 0xFF00) == AC5X_DEV_ID))
221 *index = 1;
222
223 return ret;
224}
225
226static int get_soc_name(char **soc_name)
227{
228 u32 index;
229
230 get_soc_table_index(&index);
231 *soc_name = soc_info_table[index].soc_name;
232
233 return 0;
234}
235
236/* Print device's SoC name and AP & CP information */
237void soc_print_device_info(void)
238{
239 char *soc_name = NULL;
240
241 get_soc_name(&soc_name);
242
243 printf("SoC: %s\n", soc_name);
244}
245
246void soc_print_clock_info(void)
247{
248 struct sar_freq_modes sar_freq;
249
250 get_sar_freq(&sar_freq);
251 printf("Clock: CPU %4d MHz\n", sar_freq.p_clk);
252 printf("\tDDR %4d MHz\n", sar_freq.d_clk);
253 printf("\tFABRIC %4d MHz\n", sar_freq.nb_clk);
254 printf("\tMSS %4d MHz\n", 200);
255}
256
Chris Packham01be6722023-07-10 10:47:33 +1200257/* Return NAND clock in Hz */
258u32 mvebu_get_nand_clock(void)
259{
260 return 400 * 1000000;
261}
262
Chris Packhameaab4612022-11-05 17:23:59 +1300263/*
264 * Override of __weak int mach_cpu_init(void) :
265 * SoC/machine dependent CPU setup
266 */
267int mach_cpu_init(void)
268{
269 u32 phy_i;
270 u64 new_val, phy_base = 0x7F080800;
271
272 /* Init USB PHY */
273#define USB_STEPPING 0x20000
274#define WRITE_MASK(addr, mask, val) \
275 { new_val = (readl(addr) & (~(mask))) | (val);\
276 writel(new_val, addr); }
277
278 for (phy_i = 0; phy_i < 2; phy_i++, phy_base += USB_STEPPING) {
279 WRITE_MASK(phy_base + 0x4, 0x3, 0x2);
280 WRITE_MASK(phy_base + 0xC, 0x3000000, 0x2000000);
281 WRITE_MASK(phy_base + 0x1C, 0x3, 0x2);
282 WRITE_MASK(phy_base + 0x0, 0x1FF007F, 0x600005);
283 WRITE_MASK(phy_base + 0xC, 0x000F000, 0x0002000);
284 /* Calibration Threshold Setting = 4*/
285 WRITE_MASK(phy_base + 0x8, 0x700, 0x400)
286 WRITE_MASK(phy_base + 0x14, 0x000000F, 0x000000a);
287 /* Change AMP to 4*/
288 WRITE_MASK(phy_base + 0xC, 0x3700000, 0x3400000);
289 WRITE_MASK(phy_base + 0x4, 0x3, 0x3);
290 /* Impedance calibration triggering is performed by USB probe */
291 }
292
293 return 0;
294}