1 // 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 
27 struct soc_info {
28 	u32 dev_id;
29 	u32 rev_id;
30 	char *soc_name;
31 };
32 
33 static 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 
121 enum 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 
134 static 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 
159 static 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 
get_soc_type_rev(u32 * type,u32 * rev)172 static 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 
get_one_sar_freq(int cpu_type,u32 sar_reg_val,enum mvebu_sar_opts sar_opt,u32 * freq)180 static 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 
get_sar_freq(struct sar_freq_modes * sar_freq)190 void 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 
get_soc_table_index(u32 * index)204 static 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 
get_soc_name(char ** soc_name)227 static 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 */
soc_print_device_info(void)238 void 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 
soc_print_clock_info(void)247 void 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 
258 /*
259  * Override of __weak int mach_cpu_init(void) :
260  * SoC/machine dependent CPU setup
261  */
mach_cpu_init(void)262 int mach_cpu_init(void)
263 {
264 	u32 phy_i;
265 	u64 new_val, phy_base = 0x7F080800;
266 
267 	/* Init USB PHY */
268 #define USB_STEPPING	0x20000
269 #define WRITE_MASK(addr, mask, val)		\
270 	{ new_val = (readl(addr) & (~(mask))) | (val);\
271 	writel(new_val, addr); }
272 
273 	for (phy_i = 0; phy_i < 2; phy_i++, phy_base += USB_STEPPING) {
274 		WRITE_MASK(phy_base + 0x4,     0x3,	   0x2);
275 		WRITE_MASK(phy_base + 0xC,     0x3000000,   0x2000000);
276 		WRITE_MASK(phy_base + 0x1C,    0x3,         0x2);
277 		WRITE_MASK(phy_base + 0x0,     0x1FF007F,   0x600005);
278 		WRITE_MASK(phy_base + 0xC,     0x000F000,   0x0002000);
279 		/* Calibration Threshold Setting = 4*/
280 		WRITE_MASK(phy_base + 0x8,     0x700,	   0x400)
281 		WRITE_MASK(phy_base + 0x14,    0x000000F,   0x000000a);
282 		/* Change AMP to 4*/
283 		WRITE_MASK(phy_base + 0xC,     0x3700000,   0x3400000);
284 		WRITE_MASK(phy_base + 0x4,     0x3,	   0x3);
285 		/* Impedance calibration triggering is performed by USB probe */
286 	}
287 
288 	return 0;
289 }
290