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