1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2006-2010, 2012-2013 Freescale Semiconductor, Inc. |
4 | * All rights reserved. |
5 | * |
6 | * Author: Andy Fleming <afleming@freescale.com> |
7 | * |
8 | * Based on 83xx/mpc8360e_pb.c by: |
9 | * Li Yang <LeoLi@freescale.com> |
10 | * Yin Olivia <Hong-hua.Yin@freescale.com> |
11 | * |
12 | * Description: |
13 | * MPC85xx MDS board specific routines. |
14 | */ |
15 | |
16 | #include <linux/stddef.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> |
19 | #include <linux/errno.h> |
20 | #include <linux/reboot.h> |
21 | #include <linux/pci.h> |
22 | #include <linux/kdev_t.h> |
23 | #include <linux/major.h> |
24 | #include <linux/console.h> |
25 | #include <linux/delay.h> |
26 | #include <linux/seq_file.h> |
27 | #include <linux/initrd.h> |
28 | #include <linux/fsl_devices.h> |
29 | #include <linux/of.h> |
30 | #include <linux/of_address.h> |
31 | #include <linux/phy.h> |
32 | #include <linux/memblock.h> |
33 | #include <linux/fsl/guts.h> |
34 | |
35 | #include <linux/atomic.h> |
36 | #include <asm/time.h> |
37 | #include <asm/io.h> |
38 | #include <asm/machdep.h> |
39 | #include <asm/pci-bridge.h> |
40 | #include <asm/irq.h> |
41 | #include <mm/mmu_decl.h> |
42 | #include <asm/udbg.h> |
43 | #include <sysdev/fsl_soc.h> |
44 | #include <sysdev/fsl_pci.h> |
45 | #include <soc/fsl/qe/qe.h> |
46 | #include <asm/mpic.h> |
47 | #include <asm/swiotlb.h> |
48 | #include "smp.h" |
49 | |
50 | #include "mpc85xx.h" |
51 | |
52 | #if IS_BUILTIN(CONFIG_PHYLIB) |
53 | |
54 | #define MV88E1111_SCR 0x10 |
55 | #define MV88E1111_SCR_125CLK 0x0010 |
56 | static int mpc8568_fixup_125_clock(struct phy_device *phydev) |
57 | { |
58 | int scr; |
59 | int err; |
60 | |
61 | /* Workaround for the 125 CLK Toggle */ |
62 | scr = phy_read(phydev, MV88E1111_SCR); |
63 | |
64 | if (scr < 0) |
65 | return scr; |
66 | |
67 | err = phy_write(phydev, MV88E1111_SCR, val: scr & ~(MV88E1111_SCR_125CLK)); |
68 | |
69 | if (err) |
70 | return err; |
71 | |
72 | err = phy_write(phydev, MII_BMCR, BMCR_RESET); |
73 | |
74 | if (err) |
75 | return err; |
76 | |
77 | scr = phy_read(phydev, MV88E1111_SCR); |
78 | |
79 | if (scr < 0) |
80 | return scr; |
81 | |
82 | err = phy_write(phydev, MV88E1111_SCR, val: scr | 0x0008); |
83 | |
84 | return err; |
85 | } |
86 | |
87 | static int mpc8568_mds_phy_fixups(struct phy_device *phydev) |
88 | { |
89 | int temp; |
90 | int err; |
91 | |
92 | /* Errata */ |
93 | err = phy_write(phydev,regnum: 29, val: 0x0006); |
94 | |
95 | if (err) |
96 | return err; |
97 | |
98 | temp = phy_read(phydev, regnum: 30); |
99 | |
100 | if (temp < 0) |
101 | return temp; |
102 | |
103 | temp = (temp & (~0x8000)) | 0x4000; |
104 | err = phy_write(phydev,regnum: 30, val: temp); |
105 | |
106 | if (err) |
107 | return err; |
108 | |
109 | err = phy_write(phydev,regnum: 29, val: 0x000a); |
110 | |
111 | if (err) |
112 | return err; |
113 | |
114 | temp = phy_read(phydev, regnum: 30); |
115 | |
116 | if (temp < 0) |
117 | return temp; |
118 | |
119 | temp = phy_read(phydev, regnum: 30); |
120 | |
121 | if (temp < 0) |
122 | return temp; |
123 | |
124 | temp &= ~0x0020; |
125 | |
126 | err = phy_write(phydev,regnum: 30,val: temp); |
127 | |
128 | if (err) |
129 | return err; |
130 | |
131 | /* Disable automatic MDI/MDIX selection */ |
132 | temp = phy_read(phydev, regnum: 16); |
133 | |
134 | if (temp < 0) |
135 | return temp; |
136 | |
137 | temp &= ~0x0060; |
138 | err = phy_write(phydev,regnum: 16,val: temp); |
139 | |
140 | return err; |
141 | } |
142 | |
143 | #endif |
144 | |
145 | /* ************************************************************************ |
146 | * |
147 | * Setup the architecture |
148 | * |
149 | */ |
150 | #ifdef CONFIG_QUICC_ENGINE |
151 | static void __init mpc85xx_mds_reset_ucc_phys(void) |
152 | { |
153 | struct device_node *np; |
154 | static u8 __iomem *bcsr_regs; |
155 | |
156 | /* Map BCSR area */ |
157 | np = of_find_node_by_name(NULL, name: "bcsr" ); |
158 | if (!np) |
159 | return; |
160 | |
161 | bcsr_regs = of_iomap(node: np, index: 0); |
162 | of_node_put(node: np); |
163 | if (!bcsr_regs) |
164 | return; |
165 | |
166 | if (machine_is(mpc8568_mds)) { |
167 | #define BCSR_UCC1_GETH_EN (0x1 << 7) |
168 | #define BCSR_UCC2_GETH_EN (0x1 << 7) |
169 | #define BCSR_UCC1_MODE_MSK (0x3 << 4) |
170 | #define BCSR_UCC2_MODE_MSK (0x3 << 0) |
171 | |
172 | /* Turn off UCC1 & UCC2 */ |
173 | clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); |
174 | clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); |
175 | |
176 | /* Mode is RGMII, all bits clear */ |
177 | clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK | |
178 | BCSR_UCC2_MODE_MSK); |
179 | |
180 | /* Turn UCC1 & UCC2 on */ |
181 | setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); |
182 | setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); |
183 | } else if (machine_is(mpc8569_mds)) { |
184 | #define BCSR7_UCC12_GETHnRST (0x1 << 2) |
185 | #define BCSR8_UEM_MARVELL_RST (0x1 << 1) |
186 | #define BCSR_UCC_RGMII (0x1 << 6) |
187 | #define BCSR_UCC_RTBI (0x1 << 5) |
188 | /* |
189 | * U-Boot mangles interrupt polarity for Marvell PHYs, |
190 | * so reset built-in and UEM Marvell PHYs, this puts |
191 | * the PHYs into their normal state. |
192 | */ |
193 | clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); |
194 | setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); |
195 | |
196 | setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); |
197 | clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); |
198 | |
199 | for_each_compatible_node(np, "network" , "ucc_geth" ) { |
200 | const unsigned int *prop; |
201 | int ucc_num; |
202 | |
203 | prop = of_get_property(node: np, name: "cell-index" , NULL); |
204 | if (prop == NULL) |
205 | continue; |
206 | |
207 | ucc_num = *prop - 1; |
208 | |
209 | prop = of_get_property(node: np, name: "phy-connection-type" , NULL); |
210 | if (prop == NULL) |
211 | continue; |
212 | |
213 | if (strcmp("rtbi" , (const char *)prop) == 0) |
214 | clrsetbits_8(&bcsr_regs[7 + ucc_num], |
215 | BCSR_UCC_RGMII, BCSR_UCC_RTBI); |
216 | } |
217 | } else if (machine_is(p1021_mds)) { |
218 | #define BCSR11_ENET_MICRST (0x1 << 5) |
219 | /* Reset Micrel PHY */ |
220 | clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); |
221 | setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); |
222 | } |
223 | |
224 | iounmap(addr: bcsr_regs); |
225 | } |
226 | |
227 | static void __init mpc85xx_mds_qe_init(void) |
228 | { |
229 | struct device_node *np; |
230 | |
231 | mpc85xx_qe_par_io_init(); |
232 | mpc85xx_mds_reset_ucc_phys(); |
233 | |
234 | if (machine_is(p1021_mds)) { |
235 | |
236 | struct ccsr_guts __iomem *guts; |
237 | |
238 | np = of_find_node_by_name(NULL, name: "global-utilities" ); |
239 | if (np) { |
240 | guts = of_iomap(node: np, index: 0); |
241 | if (!guts) |
242 | pr_err("mpc85xx-rdb: could not map global utilities register\n" ); |
243 | else{ |
244 | /* P1021 has pins muxed for QE and other functions. To |
245 | * enable QE UEC mode, we need to set bit QE0 for UCC1 |
246 | * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 |
247 | * and QE12 for QE MII management signals in PMUXCR |
248 | * register. |
249 | */ |
250 | setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | |
251 | MPC85xx_PMUXCR_QE(3) | |
252 | MPC85xx_PMUXCR_QE(9) | |
253 | MPC85xx_PMUXCR_QE(12)); |
254 | iounmap(addr: guts); |
255 | } |
256 | of_node_put(node: np); |
257 | } |
258 | |
259 | } |
260 | } |
261 | |
262 | #else |
263 | static void __init mpc85xx_mds_qe_init(void) { } |
264 | #endif /* CONFIG_QUICC_ENGINE */ |
265 | |
266 | static void __init mpc85xx_mds_setup_arch(void) |
267 | { |
268 | if (ppc_md.progress) |
269 | ppc_md.progress("mpc85xx_mds_setup_arch()" , 0); |
270 | |
271 | mpc85xx_smp_init(); |
272 | |
273 | mpc85xx_mds_qe_init(); |
274 | |
275 | fsl_pci_assign_primary(); |
276 | |
277 | swiotlb_detect_4g(); |
278 | } |
279 | |
280 | #if IS_BUILTIN(CONFIG_PHYLIB) |
281 | |
282 | static int __init board_fixups(void) |
283 | { |
284 | char phy_id[20]; |
285 | char *compstrs[2] = {"fsl,gianfar-mdio" , "fsl,ucc-mdio" }; |
286 | struct device_node *mdio; |
287 | struct resource res; |
288 | int i; |
289 | |
290 | for (i = 0; i < ARRAY_SIZE(compstrs); i++) { |
291 | mdio = of_find_compatible_node(NULL, NULL, compat: compstrs[i]); |
292 | |
293 | of_address_to_resource(dev: mdio, index: 0, r: &res); |
294 | snprintf(buf: phy_id, size: sizeof(phy_id), fmt: "%llx:%02x" , |
295 | (unsigned long long)res.start, 1); |
296 | |
297 | phy_register_fixup_for_id(bus_id: phy_id, run: mpc8568_fixup_125_clock); |
298 | phy_register_fixup_for_id(bus_id: phy_id, run: mpc8568_mds_phy_fixups); |
299 | |
300 | /* Register a workaround for errata */ |
301 | snprintf(buf: phy_id, size: sizeof(phy_id), fmt: "%llx:%02x" , |
302 | (unsigned long long)res.start, 7); |
303 | phy_register_fixup_for_id(bus_id: phy_id, run: mpc8568_mds_phy_fixups); |
304 | |
305 | of_node_put(node: mdio); |
306 | } |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | machine_arch_initcall(mpc8568_mds, board_fixups); |
312 | machine_arch_initcall(mpc8569_mds, board_fixups); |
313 | |
314 | #endif |
315 | |
316 | static int __init mpc85xx_publish_devices(void) |
317 | { |
318 | return mpc85xx_common_publish_devices(); |
319 | } |
320 | |
321 | machine_arch_initcall(mpc8568_mds, mpc85xx_publish_devices); |
322 | machine_arch_initcall(mpc8569_mds, mpc85xx_publish_devices); |
323 | machine_arch_initcall(p1021_mds, mpc85xx_common_publish_devices); |
324 | |
325 | static void __init mpc85xx_mds_pic_init(void) |
326 | { |
327 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
328 | MPIC_SINGLE_DEST_CPU, |
329 | 0, 256, " OpenPIC " ); |
330 | BUG_ON(mpic == NULL); |
331 | |
332 | mpic_init(mpic); |
333 | } |
334 | |
335 | define_machine(mpc8568_mds) { |
336 | .name = "MPC8568 MDS" , |
337 | .compatible = "MPC85xxMDS" , |
338 | .setup_arch = mpc85xx_mds_setup_arch, |
339 | .init_IRQ = mpc85xx_mds_pic_init, |
340 | .get_irq = mpic_get_irq, |
341 | .progress = udbg_progress, |
342 | #ifdef CONFIG_PCI |
343 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, |
344 | .pcibios_fixup_phb = fsl_pcibios_fixup_phb, |
345 | #endif |
346 | }; |
347 | |
348 | define_machine(mpc8569_mds) { |
349 | .name = "MPC8569 MDS" , |
350 | .compatible = "fsl,MPC8569EMDS" , |
351 | .setup_arch = mpc85xx_mds_setup_arch, |
352 | .init_IRQ = mpc85xx_mds_pic_init, |
353 | .get_irq = mpic_get_irq, |
354 | .progress = udbg_progress, |
355 | #ifdef CONFIG_PCI |
356 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, |
357 | .pcibios_fixup_phb = fsl_pcibios_fixup_phb, |
358 | #endif |
359 | }; |
360 | |
361 | define_machine(p1021_mds) { |
362 | .name = "P1021 MDS" , |
363 | .compatible = "fsl,P1021MDS" , |
364 | .setup_arch = mpc85xx_mds_setup_arch, |
365 | .init_IRQ = mpc85xx_mds_pic_init, |
366 | .get_irq = mpic_get_irq, |
367 | .progress = udbg_progress, |
368 | #ifdef CONFIG_PCI |
369 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, |
370 | .pcibios_fixup_phb = fsl_pcibios_fixup_phb, |
371 | #endif |
372 | }; |
373 | |