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