]>
Commit | Line | Data |
---|---|---|
50dcf89d DE |
1 | /* |
2 | * (C) Copyright 2014 | |
3 | * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <hwconfig.h> | |
10 | #include <i2c.h> | |
11 | #include <spi.h> | |
12 | #include <libfdt.h> | |
13 | #include <fdt_support.h> | |
14 | #include <pci.h> | |
15 | #include <mpc83xx.h> | |
16 | #include <fsl_esdhc.h> | |
17 | #include <asm/io.h> | |
18 | #include <asm/fsl_serdes.h> | |
19 | #include <asm/fsl_mpc83xx_serdes.h> | |
20 | ||
21 | #include "mpc8308.h" | |
22 | ||
23 | #include <gdsys_fpga.h> | |
24 | ||
d4e58888 | 25 | #include "../common/ioep-fpga.h" |
50dcf89d DE |
26 | #include "../common/osd.h" |
27 | #include "../common/mclink.h" | |
28 | #include "../common/phy.h" | |
5c3b6dc1 | 29 | #include "../common/fanctrl.h" |
50dcf89d DE |
30 | |
31 | #include <pca953x.h> | |
32 | #include <pca9698.h> | |
33 | ||
34 | #include <miiphy.h> | |
35 | ||
36 | DECLARE_GLOBAL_DATA_PTR; | |
37 | ||
38 | #define MAX_MUX_CHANNELS 2 | |
39 | ||
50dcf89d DE |
40 | enum { |
41 | MCFPGA_DONE = 1 << 0, | |
42 | MCFPGA_INIT_N = 1 << 1, | |
43 | MCFPGA_PROGRAM_N = 1 << 2, | |
44 | MCFPGA_UPDATE_ENABLE_N = 1 << 3, | |
45 | MCFPGA_RESET_N = 1 << 4, | |
46 | }; | |
47 | ||
48 | enum { | |
49 | GPIO_MDC = 1 << 14, | |
50 | GPIO_MDIO = 1 << 15, | |
51 | }; | |
52 | ||
53 | unsigned int mclink_fpgacount; | |
54 | struct ihs_fpga *fpga_ptr[] = CONFIG_SYS_FPGA_PTR; | |
55 | ||
5c3b6dc1 DE |
56 | struct { |
57 | u8 bus; | |
58 | u8 addr; | |
59 | } hrcon_fans[] = CONFIG_HRCON_FANS; | |
60 | ||
50dcf89d DE |
61 | int fpga_set_reg(u32 fpga, u16 *reg, off_t regoff, u16 data) |
62 | { | |
63 | int res; | |
64 | ||
65 | switch (fpga) { | |
66 | case 0: | |
67 | out_le16(reg, data); | |
68 | break; | |
69 | default: | |
70 | res = mclink_send(fpga - 1, regoff, data); | |
71 | if (res < 0) { | |
72 | printf("mclink_send reg %02lx data %04x returned %d\n", | |
73 | regoff, data, res); | |
74 | return res; | |
75 | } | |
76 | break; | |
77 | } | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
82 | int fpga_get_reg(u32 fpga, u16 *reg, off_t regoff, u16 *data) | |
83 | { | |
84 | int res; | |
85 | ||
86 | switch (fpga) { | |
87 | case 0: | |
88 | *data = in_le16(reg); | |
89 | break; | |
90 | default: | |
91 | if (fpga > mclink_fpgacount) | |
92 | return -EINVAL; | |
93 | res = mclink_receive(fpga - 1, regoff, data); | |
94 | if (res < 0) { | |
95 | printf("mclink_receive reg %02lx returned %d\n", | |
96 | regoff, res); | |
97 | return res; | |
98 | } | |
99 | } | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
104 | int checkboard(void) | |
105 | { | |
00caae6d | 106 | char *s = env_get("serial#"); |
50dcf89d DE |
107 | bool hw_type_cat = pca9698_get_value(0x20, 20); |
108 | ||
109 | puts("Board: "); | |
110 | ||
111 | printf("HRCon %s", hw_type_cat ? "CAT" : "Fiber"); | |
112 | ||
113 | if (s != NULL) { | |
114 | puts(", serial# "); | |
115 | puts(s); | |
116 | } | |
117 | ||
118 | puts("\n"); | |
119 | ||
120 | return 0; | |
121 | } | |
122 | ||
50dcf89d DE |
123 | int last_stage_init(void) |
124 | { | |
125 | int slaves; | |
126 | unsigned int k; | |
127 | unsigned int mux_ch; | |
b847f5b6 | 128 | unsigned char mclink_controllers[] = { 0x3c, 0x3d, 0x3e }; |
50dcf89d DE |
129 | u16 fpga_features; |
130 | bool hw_type_cat = pca9698_get_value(0x20, 20); | |
131 | bool ch0_rgmii2_present = false; | |
132 | ||
133 | FPGA_GET_REG(0, fpga_features, &fpga_features); | |
134 | ||
135 | /* Turn on Parade DP501 */ | |
136 | pca9698_direction_output(0x20, 10, 1); | |
7ed45d3d | 137 | pca9698_direction_output(0x20, 11, 1); |
50dcf89d DE |
138 | |
139 | ch0_rgmii2_present = !pca9698_get_value(0x20, 30); | |
140 | ||
b847f5b6 | 141 | /* wait for FPGA done, then reset FPGA */ |
50dcf89d DE |
142 | for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) { |
143 | unsigned int ctr = 0; | |
144 | ||
145 | if (i2c_probe(mclink_controllers[k])) | |
146 | continue; | |
147 | ||
148 | while (!(pca953x_get_val(mclink_controllers[k]) | |
149 | & MCFPGA_DONE)) { | |
150 | udelay(100000); | |
151 | if (ctr++ > 5) { | |
152 | printf("no done for mclink_controller %d\n", k); | |
153 | break; | |
154 | } | |
155 | } | |
b847f5b6 DE |
156 | |
157 | pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0); | |
158 | pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0); | |
159 | udelay(10); | |
160 | pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, | |
161 | MCFPGA_RESET_N); | |
50dcf89d DE |
162 | } |
163 | ||
164 | if (hw_type_cat) { | |
5a49f174 JH |
165 | int retval; |
166 | struct mii_dev *mdiodev = mdio_alloc(); | |
167 | if (!mdiodev) | |
168 | return -ENOMEM; | |
169 | strncpy(mdiodev->name, bb_miiphy_buses[0].name, MDIO_NAME_LEN); | |
170 | mdiodev->read = bb_miiphy_read; | |
171 | mdiodev->write = bb_miiphy_write; | |
172 | ||
173 | retval = mdio_register(mdiodev); | |
174 | if (retval < 0) | |
175 | return retval; | |
50dcf89d DE |
176 | for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) { |
177 | if ((mux_ch == 1) && !ch0_rgmii2_present) | |
178 | continue; | |
179 | ||
180 | setup_88e1514(bb_miiphy_buses[0].name, mux_ch); | |
181 | } | |
182 | } | |
183 | ||
184 | /* give slave-PLLs and Parade DP501 some time to be up and running */ | |
185 | udelay(500000); | |
186 | ||
187 | mclink_fpgacount = CONFIG_SYS_MCLINK_MAX; | |
188 | slaves = mclink_probe(); | |
189 | mclink_fpgacount = 0; | |
190 | ||
d4e58888 | 191 | ioep_fpga_print_info(0); |
50dcf89d | 192 | osd_probe(0); |
7ed45d3d DE |
193 | #ifdef CONFIG_SYS_OSD_DH |
194 | osd_probe(4); | |
195 | #endif | |
50dcf89d DE |
196 | |
197 | if (slaves <= 0) | |
198 | return 0; | |
199 | ||
200 | mclink_fpgacount = slaves; | |
201 | ||
202 | for (k = 1; k <= slaves; ++k) { | |
203 | FPGA_GET_REG(k, fpga_features, &fpga_features); | |
204 | ||
d4e58888 | 205 | ioep_fpga_print_info(k); |
50dcf89d | 206 | osd_probe(k); |
7ed45d3d DE |
207 | #ifdef CONFIG_SYS_OSD_DH |
208 | osd_probe(k + 4); | |
209 | #endif | |
50dcf89d | 210 | if (hw_type_cat) { |
5a49f174 JH |
211 | int retval; |
212 | struct mii_dev *mdiodev = mdio_alloc(); | |
213 | if (!mdiodev) | |
214 | return -ENOMEM; | |
215 | strncpy(mdiodev->name, bb_miiphy_buses[k].name, | |
216 | MDIO_NAME_LEN); | |
217 | mdiodev->read = bb_miiphy_read; | |
218 | mdiodev->write = bb_miiphy_write; | |
219 | ||
220 | retval = mdio_register(mdiodev); | |
221 | if (retval < 0) | |
222 | return retval; | |
50dcf89d DE |
223 | setup_88e1514(bb_miiphy_buses[k].name, 0); |
224 | } | |
225 | } | |
226 | ||
5c3b6dc1 DE |
227 | for (k = 0; k < ARRAY_SIZE(hrcon_fans); ++k) { |
228 | i2c_set_bus_num(hrcon_fans[k].bus); | |
229 | init_fan_controller(hrcon_fans[k].addr); | |
230 | } | |
231 | ||
50dcf89d DE |
232 | return 0; |
233 | } | |
234 | ||
235 | /* | |
7ed45d3d | 236 | * provide access to fpga gpios and controls (for I2C bitbang) |
50dcf89d DE |
237 | * (these may look all too simple but make iocon.h much more readable) |
238 | */ | |
239 | void fpga_gpio_set(unsigned int bus, int pin) | |
240 | { | |
7ed45d3d | 241 | FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, gpio.set, pin); |
50dcf89d DE |
242 | } |
243 | ||
244 | void fpga_gpio_clear(unsigned int bus, int pin) | |
245 | { | |
7ed45d3d | 246 | FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, gpio.clear, pin); |
50dcf89d DE |
247 | } |
248 | ||
249 | int fpga_gpio_get(unsigned int bus, int pin) | |
250 | { | |
251 | u16 val; | |
252 | ||
7ed45d3d | 253 | FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, gpio.read, &val); |
50dcf89d DE |
254 | |
255 | return val & pin; | |
256 | } | |
257 | ||
7ed45d3d DE |
258 | void fpga_control_set(unsigned int bus, int pin) |
259 | { | |
260 | u16 val; | |
261 | ||
262 | FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, control, &val); | |
263 | FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, control, val | pin); | |
264 | } | |
265 | ||
266 | void fpga_control_clear(unsigned int bus, int pin) | |
267 | { | |
268 | u16 val; | |
269 | ||
270 | FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, control, &val); | |
271 | FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, control, val & ~pin); | |
272 | } | |
273 | ||
50dcf89d DE |
274 | void mpc8308_init(void) |
275 | { | |
276 | pca9698_direction_output(0x20, 4, 1); | |
277 | } | |
278 | ||
279 | void mpc8308_set_fpga_reset(unsigned state) | |
280 | { | |
281 | pca9698_set_value(0x20, 4, state ? 0 : 1); | |
282 | } | |
283 | ||
284 | void mpc8308_setup_hw(void) | |
285 | { | |
286 | immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; | |
287 | ||
288 | /* | |
289 | * set "startup-finished"-gpios | |
290 | */ | |
291 | setbits_be32(&immr->gpio[0].dir, (1 << (31-11)) | (1 << (31-12))); | |
292 | setbits_be32(&immr->gpio[0].dat, 1 << (31-12)); | |
293 | } | |
294 | ||
295 | int mpc8308_get_fpga_done(unsigned fpga) | |
296 | { | |
297 | return pca9698_get_value(0x20, 19); | |
298 | } | |
299 | ||
300 | #ifdef CONFIG_FSL_ESDHC | |
301 | int board_mmc_init(bd_t *bd) | |
302 | { | |
303 | immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; | |
304 | sysconf83xx_t *sysconf = &immr->sysconf; | |
305 | ||
306 | /* Enable cache snooping in eSDHC system configuration register */ | |
307 | out_be32(&sysconf->sdhccr, 0x02000000); | |
308 | ||
309 | return fsl_esdhc_mmc_init(bd); | |
310 | } | |
311 | #endif | |
312 | ||
313 | static struct pci_region pcie_regions_0[] = { | |
314 | { | |
315 | .bus_start = CONFIG_SYS_PCIE1_MEM_BASE, | |
316 | .phys_start = CONFIG_SYS_PCIE1_MEM_PHYS, | |
317 | .size = CONFIG_SYS_PCIE1_MEM_SIZE, | |
318 | .flags = PCI_REGION_MEM, | |
319 | }, | |
320 | { | |
321 | .bus_start = CONFIG_SYS_PCIE1_IO_BASE, | |
322 | .phys_start = CONFIG_SYS_PCIE1_IO_PHYS, | |
323 | .size = CONFIG_SYS_PCIE1_IO_SIZE, | |
324 | .flags = PCI_REGION_IO, | |
325 | }, | |
326 | }; | |
327 | ||
328 | void pci_init_board(void) | |
329 | { | |
330 | immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; | |
331 | sysconf83xx_t *sysconf = &immr->sysconf; | |
332 | law83xx_t *pcie_law = sysconf->pcielaw; | |
333 | struct pci_region *pcie_reg[] = { pcie_regions_0 }; | |
334 | ||
335 | fsl_setup_serdes(CONFIG_FSL_SERDES1, FSL_SERDES_PROTO_PEX, | |
336 | FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V); | |
337 | ||
338 | /* Deassert the resets in the control register */ | |
339 | out_be32(&sysconf->pecr1, 0xE0008000); | |
340 | udelay(2000); | |
341 | ||
342 | /* Configure PCI Express Local Access Windows */ | |
343 | out_be32(&pcie_law[0].bar, CONFIG_SYS_PCIE1_BASE & LAWBAR_BAR); | |
344 | out_be32(&pcie_law[0].ar, LBLAWAR_EN | LBLAWAR_512MB); | |
345 | ||
346 | mpc83xx_pcie_init(1, pcie_reg); | |
347 | } | |
348 | ||
349 | ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) | |
350 | { | |
351 | info->portwidth = FLASH_CFI_16BIT; | |
352 | info->chipwidth = FLASH_CFI_BY16; | |
353 | info->interface = FLASH_CFI_X16; | |
354 | return 1; | |
355 | } | |
356 | ||
357 | #if defined(CONFIG_OF_BOARD_SETUP) | |
e895a4b0 | 358 | int ft_board_setup(void *blob, bd_t *bd) |
50dcf89d DE |
359 | { |
360 | ft_cpu_setup(blob, bd); | |
a5c289b9 | 361 | fsl_fdt_fixup_dr_usb(blob, bd); |
50dcf89d | 362 | fdt_fixup_esdhc(blob, bd); |
e895a4b0 SG |
363 | |
364 | return 0; | |
50dcf89d DE |
365 | } |
366 | #endif | |
367 | ||
368 | /* | |
369 | * FPGA MII bitbang implementation | |
370 | */ | |
371 | ||
372 | struct fpga_mii { | |
373 | unsigned fpga; | |
374 | int mdio; | |
375 | } fpga_mii[] = { | |
376 | { 0, 1}, | |
377 | { 1, 1}, | |
378 | { 2, 1}, | |
379 | { 3, 1}, | |
380 | }; | |
381 | ||
382 | static int mii_dummy_init(struct bb_miiphy_bus *bus) | |
383 | { | |
384 | return 0; | |
385 | } | |
386 | ||
387 | static int mii_mdio_active(struct bb_miiphy_bus *bus) | |
388 | { | |
389 | struct fpga_mii *fpga_mii = bus->priv; | |
390 | ||
391 | if (fpga_mii->mdio) | |
392 | FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); | |
393 | else | |
394 | FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO); | |
395 | ||
396 | return 0; | |
397 | } | |
398 | ||
399 | static int mii_mdio_tristate(struct bb_miiphy_bus *bus) | |
400 | { | |
401 | struct fpga_mii *fpga_mii = bus->priv; | |
402 | ||
403 | FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); | |
404 | ||
405 | return 0; | |
406 | } | |
407 | ||
408 | static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) | |
409 | { | |
410 | struct fpga_mii *fpga_mii = bus->priv; | |
411 | ||
412 | if (v) | |
413 | FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); | |
414 | else | |
415 | FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO); | |
416 | ||
417 | fpga_mii->mdio = v; | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) | |
423 | { | |
424 | u16 gpio; | |
425 | struct fpga_mii *fpga_mii = bus->priv; | |
426 | ||
427 | FPGA_GET_REG(fpga_mii->fpga, gpio.read, &gpio); | |
428 | ||
429 | *v = ((gpio & GPIO_MDIO) != 0); | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
434 | static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) | |
435 | { | |
436 | struct fpga_mii *fpga_mii = bus->priv; | |
437 | ||
438 | if (v) | |
439 | FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDC); | |
440 | else | |
441 | FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDC); | |
442 | ||
443 | return 0; | |
444 | } | |
445 | ||
446 | static int mii_delay(struct bb_miiphy_bus *bus) | |
447 | { | |
448 | udelay(1); | |
449 | ||
450 | return 0; | |
451 | } | |
452 | ||
453 | struct bb_miiphy_bus bb_miiphy_buses[] = { | |
454 | { | |
455 | .name = "board0", | |
456 | .init = mii_dummy_init, | |
457 | .mdio_active = mii_mdio_active, | |
458 | .mdio_tristate = mii_mdio_tristate, | |
459 | .set_mdio = mii_set_mdio, | |
460 | .get_mdio = mii_get_mdio, | |
461 | .set_mdc = mii_set_mdc, | |
462 | .delay = mii_delay, | |
463 | .priv = &fpga_mii[0], | |
464 | }, | |
465 | { | |
466 | .name = "board1", | |
467 | .init = mii_dummy_init, | |
468 | .mdio_active = mii_mdio_active, | |
469 | .mdio_tristate = mii_mdio_tristate, | |
470 | .set_mdio = mii_set_mdio, | |
471 | .get_mdio = mii_get_mdio, | |
472 | .set_mdc = mii_set_mdc, | |
473 | .delay = mii_delay, | |
474 | .priv = &fpga_mii[1], | |
475 | }, | |
476 | { | |
477 | .name = "board2", | |
478 | .init = mii_dummy_init, | |
479 | .mdio_active = mii_mdio_active, | |
480 | .mdio_tristate = mii_mdio_tristate, | |
481 | .set_mdio = mii_set_mdio, | |
482 | .get_mdio = mii_get_mdio, | |
483 | .set_mdc = mii_set_mdc, | |
484 | .delay = mii_delay, | |
485 | .priv = &fpga_mii[2], | |
486 | }, | |
487 | { | |
488 | .name = "board3", | |
489 | .init = mii_dummy_init, | |
490 | .mdio_active = mii_mdio_active, | |
491 | .mdio_tristate = mii_mdio_tristate, | |
492 | .set_mdio = mii_set_mdio, | |
493 | .get_mdio = mii_get_mdio, | |
494 | .set_mdc = mii_set_mdc, | |
495 | .delay = mii_delay, | |
496 | .priv = &fpga_mii[3], | |
497 | }, | |
498 | }; | |
499 | ||
500 | int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) / | |
501 | sizeof(bb_miiphy_buses[0]); |