1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/mach-mv78xx0/common.c |
4 | * |
5 | * Core functions for Marvell MV78xx0 SoCs |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> |
10 | #include <linux/io.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/serial_8250.h> |
13 | #include <linux/ata_platform.h> |
14 | #include <linux/clk-provider.h> |
15 | #include <linux/ethtool.h> |
16 | #include <asm/hardware/cache-feroceon-l2.h> |
17 | #include <asm/mach/map.h> |
18 | #include <asm/mach/time.h> |
19 | #include <linux/platform_data/usb-ehci-orion.h> |
20 | #include <linux/platform_data/mtd-orion_nand.h> |
21 | #include <plat/time.h> |
22 | #include <plat/common.h> |
23 | #include <plat/addr-map.h> |
24 | #include "mv78xx0.h" |
25 | #include "bridge-regs.h" |
26 | #include "common.h" |
27 | |
28 | static int get_tclk(void); |
29 | |
30 | /***************************************************************************** |
31 | * Common bits |
32 | ****************************************************************************/ |
33 | int mv78xx0_core_index(void) |
34 | { |
35 | u32 ; |
36 | |
37 | /* |
38 | * Read Extra Features register. |
39 | */ |
40 | __asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (extra)); |
41 | |
42 | return !!(extra & 0x00004000); |
43 | } |
44 | |
45 | static int get_hclk(void) |
46 | { |
47 | int hclk; |
48 | |
49 | /* |
50 | * HCLK tick rate is configured by DEV_D[7:5] pins. |
51 | */ |
52 | switch ((readl(SAMPLE_AT_RESET_LOW) >> 5) & 7) { |
53 | case 0: |
54 | hclk = 166666667; |
55 | break; |
56 | case 1: |
57 | hclk = 200000000; |
58 | break; |
59 | case 2: |
60 | hclk = 266666667; |
61 | break; |
62 | case 3: |
63 | hclk = 333333333; |
64 | break; |
65 | case 4: |
66 | hclk = 400000000; |
67 | break; |
68 | default: |
69 | panic(fmt: "unknown HCLK PLL setting: %.8x\n" , |
70 | readl(SAMPLE_AT_RESET_LOW)); |
71 | } |
72 | |
73 | return hclk; |
74 | } |
75 | |
76 | static void get_pclk_l2clk(int hclk, int core_index, int *pclk, int *l2clk) |
77 | { |
78 | u32 cfg; |
79 | |
80 | /* |
81 | * Core #0 PCLK/L2CLK is configured by bits [13:8], core #1 |
82 | * PCLK/L2CLK by bits [19:14]. |
83 | */ |
84 | if (core_index == 0) { |
85 | cfg = (readl(SAMPLE_AT_RESET_LOW) >> 8) & 0x3f; |
86 | } else { |
87 | cfg = (readl(SAMPLE_AT_RESET_LOW) >> 14) & 0x3f; |
88 | } |
89 | |
90 | /* |
91 | * Bits [11:8] ([17:14] for core #1) configure the PCLK:HCLK |
92 | * ratio (1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6). |
93 | */ |
94 | *pclk = ((u64)hclk * (2 + (cfg & 0xf))) >> 1; |
95 | |
96 | /* |
97 | * Bits [13:12] ([19:18] for core #1) configure the PCLK:L2CLK |
98 | * ratio (1, 2, 3). |
99 | */ |
100 | *l2clk = *pclk / (((cfg >> 4) & 3) + 1); |
101 | } |
102 | |
103 | static int get_tclk(void) |
104 | { |
105 | int tclk_freq; |
106 | |
107 | /* |
108 | * TCLK tick rate is configured by DEV_A[2:0] strap pins. |
109 | */ |
110 | switch ((readl(SAMPLE_AT_RESET_HIGH) >> 6) & 7) { |
111 | case 1: |
112 | tclk_freq = 166666667; |
113 | break; |
114 | case 3: |
115 | tclk_freq = 200000000; |
116 | break; |
117 | default: |
118 | panic(fmt: "unknown TCLK PLL setting: %.8x\n" , |
119 | readl(SAMPLE_AT_RESET_HIGH)); |
120 | } |
121 | |
122 | return tclk_freq; |
123 | } |
124 | |
125 | |
126 | /***************************************************************************** |
127 | * I/O Address Mapping |
128 | ****************************************************************************/ |
129 | static struct map_desc mv78xx0_io_desc[] __initdata = { |
130 | { |
131 | .virtual = (unsigned long) MV78XX0_CORE_REGS_VIRT_BASE, |
132 | .pfn = 0, |
133 | .length = MV78XX0_CORE_REGS_SIZE, |
134 | .type = MT_DEVICE, |
135 | }, { |
136 | .virtual = (unsigned long) MV78XX0_REGS_VIRT_BASE, |
137 | .pfn = __phys_to_pfn(MV78XX0_REGS_PHYS_BASE), |
138 | .length = MV78XX0_REGS_SIZE, |
139 | .type = MT_DEVICE, |
140 | }, |
141 | }; |
142 | |
143 | void __init mv78xx0_map_io(void) |
144 | { |
145 | unsigned long phys; |
146 | |
147 | /* |
148 | * Map the right set of per-core registers depending on |
149 | * which core we are running on. |
150 | */ |
151 | if (mv78xx0_core_index() == 0) { |
152 | phys = MV78XX0_CORE0_REGS_PHYS_BASE; |
153 | } else { |
154 | phys = MV78XX0_CORE1_REGS_PHYS_BASE; |
155 | } |
156 | mv78xx0_io_desc[0].pfn = __phys_to_pfn(phys); |
157 | |
158 | iotable_init(mv78xx0_io_desc, ARRAY_SIZE(mv78xx0_io_desc)); |
159 | } |
160 | |
161 | |
162 | /***************************************************************************** |
163 | * CLK tree |
164 | ****************************************************************************/ |
165 | static struct clk *tclk; |
166 | |
167 | static void __init clk_init(void) |
168 | { |
169 | tclk = clk_register_fixed_rate(NULL, name: "tclk" , NULL, flags: 0, fixed_rate: get_tclk()); |
170 | |
171 | orion_clkdev_init(tclk); |
172 | } |
173 | |
174 | /***************************************************************************** |
175 | * EHCI |
176 | ****************************************************************************/ |
177 | void __init mv78xx0_ehci0_init(void) |
178 | { |
179 | orion_ehci_init(USB0_PHYS_BASE, IRQ_MV78XX0_USB_0, EHCI_PHY_NA); |
180 | } |
181 | |
182 | |
183 | /***************************************************************************** |
184 | * EHCI1 |
185 | ****************************************************************************/ |
186 | void __init mv78xx0_ehci1_init(void) |
187 | { |
188 | orion_ehci_1_init(USB1_PHYS_BASE, IRQ_MV78XX0_USB_1); |
189 | } |
190 | |
191 | |
192 | /***************************************************************************** |
193 | * EHCI2 |
194 | ****************************************************************************/ |
195 | void __init mv78xx0_ehci2_init(void) |
196 | { |
197 | orion_ehci_2_init(USB2_PHYS_BASE, IRQ_MV78XX0_USB_2); |
198 | } |
199 | |
200 | |
201 | /***************************************************************************** |
202 | * GE00 |
203 | ****************************************************************************/ |
204 | void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) |
205 | { |
206 | orion_ge00_init(eth_data, |
207 | GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, |
208 | IRQ_MV78XX0_GE_ERR, |
209 | MV643XX_TX_CSUM_DEFAULT_LIMIT); |
210 | } |
211 | |
212 | |
213 | /***************************************************************************** |
214 | * GE01 |
215 | ****************************************************************************/ |
216 | void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) |
217 | { |
218 | orion_ge01_init(eth_data, |
219 | GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, |
220 | MV643XX_TX_CSUM_DEFAULT_LIMIT); |
221 | } |
222 | |
223 | |
224 | /***************************************************************************** |
225 | * GE10 |
226 | ****************************************************************************/ |
227 | void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data) |
228 | { |
229 | u32 dev, rev; |
230 | |
231 | /* |
232 | * On the Z0, ge10 and ge11 are internally connected back |
233 | * to back, and not brought out. |
234 | */ |
235 | mv78xx0_pcie_id(dev: &dev, rev: &rev); |
236 | if (dev == MV78X00_Z0_DEV_ID) { |
237 | eth_data->phy_addr = MV643XX_ETH_PHY_NONE; |
238 | eth_data->speed = SPEED_1000; |
239 | eth_data->duplex = DUPLEX_FULL; |
240 | } |
241 | |
242 | orion_ge10_init(eth_data, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM); |
243 | } |
244 | |
245 | |
246 | /***************************************************************************** |
247 | * GE11 |
248 | ****************************************************************************/ |
249 | void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data) |
250 | { |
251 | u32 dev, rev; |
252 | |
253 | /* |
254 | * On the Z0, ge10 and ge11 are internally connected back |
255 | * to back, and not brought out. |
256 | */ |
257 | mv78xx0_pcie_id(dev: &dev, rev: &rev); |
258 | if (dev == MV78X00_Z0_DEV_ID) { |
259 | eth_data->phy_addr = MV643XX_ETH_PHY_NONE; |
260 | eth_data->speed = SPEED_1000; |
261 | eth_data->duplex = DUPLEX_FULL; |
262 | } |
263 | |
264 | orion_ge11_init(eth_data, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM); |
265 | } |
266 | |
267 | /***************************************************************************** |
268 | * I2C |
269 | ****************************************************************************/ |
270 | void __init mv78xx0_i2c_init(void) |
271 | { |
272 | orion_i2c_init(I2C_0_PHYS_BASE, IRQ_MV78XX0_I2C_0, 8); |
273 | orion_i2c_1_init(I2C_1_PHYS_BASE, IRQ_MV78XX0_I2C_1, 8); |
274 | } |
275 | |
276 | /***************************************************************************** |
277 | * SATA |
278 | ****************************************************************************/ |
279 | void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data) |
280 | { |
281 | orion_sata_init(sata_data, SATA_PHYS_BASE, IRQ_MV78XX0_SATA); |
282 | } |
283 | |
284 | |
285 | /***************************************************************************** |
286 | * UART0 |
287 | ****************************************************************************/ |
288 | void __init mv78xx0_uart0_init(void) |
289 | { |
290 | orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, |
291 | IRQ_MV78XX0_UART_0, tclk); |
292 | } |
293 | |
294 | |
295 | /***************************************************************************** |
296 | * UART1 |
297 | ****************************************************************************/ |
298 | void __init mv78xx0_uart1_init(void) |
299 | { |
300 | orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, |
301 | IRQ_MV78XX0_UART_1, tclk); |
302 | } |
303 | |
304 | |
305 | /***************************************************************************** |
306 | * UART2 |
307 | ****************************************************************************/ |
308 | void __init mv78xx0_uart2_init(void) |
309 | { |
310 | orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE, |
311 | IRQ_MV78XX0_UART_2, tclk); |
312 | } |
313 | |
314 | /***************************************************************************** |
315 | * UART3 |
316 | ****************************************************************************/ |
317 | void __init mv78xx0_uart3_init(void) |
318 | { |
319 | orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE, |
320 | IRQ_MV78XX0_UART_3, tclk); |
321 | } |
322 | |
323 | /***************************************************************************** |
324 | * Time handling |
325 | ****************************************************************************/ |
326 | void __init mv78xx0_init_early(void) |
327 | { |
328 | orion_time_set_base(TIMER_VIRT_BASE); |
329 | if (mv78xx0_core_index() == 0) |
330 | mvebu_mbus_init("marvell,mv78xx0-mbus" , |
331 | BRIDGE_WINS_CPU0_BASE, BRIDGE_WINS_SZ, |
332 | DDR_WINDOW_CPU0_BASE, DDR_WINDOW_CPU_SZ); |
333 | else |
334 | mvebu_mbus_init("marvell,mv78xx0-mbus" , |
335 | BRIDGE_WINS_CPU1_BASE, BRIDGE_WINS_SZ, |
336 | DDR_WINDOW_CPU1_BASE, DDR_WINDOW_CPU_SZ); |
337 | } |
338 | |
339 | void __ref mv78xx0_timer_init(void) |
340 | { |
341 | orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR, |
342 | IRQ_MV78XX0_TIMER_1, get_tclk()); |
343 | } |
344 | |
345 | /**************************************************************************** |
346 | * XOR engine |
347 | ****************************************************************************/ |
348 | void __init mv78xx0_xor_init(void) |
349 | { |
350 | orion_xor0_init(XOR_PHYS_BASE, |
351 | XOR_PHYS_BASE + 0x200, |
352 | IRQ_MV78XX0_XOR_0, IRQ_MV78XX0_XOR_1); |
353 | } |
354 | |
355 | /**************************************************************************** |
356 | * Cryptographic Engines and Security Accelerator (CESA) |
357 | ****************************************************************************/ |
358 | void __init mv78xx0_crypto_init(void) |
359 | { |
360 | mvebu_mbus_add_window_by_id(MV78XX0_MBUS_SRAM_TARGET, |
361 | MV78XX0_MBUS_SRAM_ATTR, |
362 | MV78XX0_SRAM_PHYS_BASE, |
363 | MV78XX0_SRAM_SIZE); |
364 | orion_crypto_init(CRYPTO_PHYS_BASE, MV78XX0_SRAM_PHYS_BASE, |
365 | SZ_8K, IRQ_MV78XX0_CRYPTO); |
366 | } |
367 | |
368 | |
369 | /***************************************************************************** |
370 | * General |
371 | ****************************************************************************/ |
372 | static char * __init mv78xx0_id(void) |
373 | { |
374 | u32 dev, rev; |
375 | |
376 | mv78xx0_pcie_id(dev: &dev, rev: &rev); |
377 | |
378 | if (dev == MV78X00_Z0_DEV_ID) { |
379 | if (rev == MV78X00_REV_Z0) |
380 | return "MV78X00-Z0" ; |
381 | else |
382 | return "MV78X00-Rev-Unsupported" ; |
383 | } else if (dev == MV78100_DEV_ID) { |
384 | if (rev == MV78100_REV_A0) |
385 | return "MV78100-A0" ; |
386 | else if (rev == MV78100_REV_A1) |
387 | return "MV78100-A1" ; |
388 | else |
389 | return "MV78100-Rev-Unsupported" ; |
390 | } else if (dev == MV78200_DEV_ID) { |
391 | if (rev == MV78100_REV_A0) |
392 | return "MV78200-A0" ; |
393 | else |
394 | return "MV78200-Rev-Unsupported" ; |
395 | } else { |
396 | return "Device-Unknown" ; |
397 | } |
398 | } |
399 | |
400 | static int __init is_l2_writethrough(void) |
401 | { |
402 | return !!(readl(CPU_CONTROL) & L2_WRITETHROUGH); |
403 | } |
404 | |
405 | void __init mv78xx0_init(void) |
406 | { |
407 | int core_index; |
408 | int hclk; |
409 | int pclk; |
410 | int l2clk; |
411 | |
412 | core_index = mv78xx0_core_index(); |
413 | hclk = get_hclk(); |
414 | get_pclk_l2clk(hclk, core_index, pclk: &pclk, l2clk: &l2clk); |
415 | |
416 | printk(KERN_INFO "%s " , mv78xx0_id()); |
417 | printk("core #%d, " , core_index); |
418 | printk("PCLK = %dMHz, " , (pclk + 499999) / 1000000); |
419 | printk("L2 = %dMHz, " , (l2clk + 499999) / 1000000); |
420 | printk("HCLK = %dMHz, " , (hclk + 499999) / 1000000); |
421 | printk("TCLK = %dMHz\n" , (get_tclk() + 499999) / 1000000); |
422 | |
423 | if (IS_ENABLED(CONFIG_CACHE_FEROCEON_L2)) |
424 | feroceon_l2_init(is_l2_writethrough()); |
425 | |
426 | /* Setup root of clk tree */ |
427 | clk_init(); |
428 | } |
429 | |
430 | void mv78xx0_restart(enum reboot_mode mode, const char *cmd) |
431 | { |
432 | /* |
433 | * Enable soft reset to assert RSTOUTn. |
434 | */ |
435 | writel(SOFT_RESET_OUT_EN, RSTOUTn_MASK); |
436 | |
437 | /* |
438 | * Assert soft reset. |
439 | */ |
440 | writel(SOFT_RESET, SYSTEM_SOFT_RESET); |
441 | |
442 | while (1) |
443 | ; |
444 | } |
445 | |