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