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