blob: 470ea32f9c3ccaf43b6597a2016103dff6e44f7e [file] [log] [blame]
Marek Behúnf835bed2018-04-24 17:21:31 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
4 */
5
6#include <common.h>
Marek Behún455ef5b2020-04-08 19:25:22 +02007#include <asm/arch/cpu.h>
Marek Behún1055ce12020-04-08 12:02:07 +02008#include <asm/arch/soc.h>
Marek Behún9602a8c2018-08-21 12:22:09 +02009#include <asm/io.h>
Marek Behún28e935f2020-04-08 12:02:08 +020010#include <asm/gpio.h>
Marek Behúnf835bed2018-04-24 17:21:31 +020011#include <clk.h>
Marek Behún28e935f2020-04-08 12:02:08 +020012#include <dm.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060013#include <env.h>
Marek Behún9602a8c2018-08-21 12:22:09 +020014#include <fdt_support.h>
Marek Behún28e935f2020-04-08 12:02:08 +020015#include <init.h>
16#include <linux/libfdt.h>
17#include <linux/string.h>
18#include <miiphy.h>
19#include <mvebu/comphy.h>
20#include <spi.h>
Marek Behúnf835bed2018-04-24 17:21:31 +020021
Marek Behún35572c92018-12-17 16:10:08 +010022#include "mox_sp.h"
23
Marek Behún9602a8c2018-08-21 12:22:09 +020024#define MAX_MOX_MODULES 10
25
26#define MOX_MODULE_SFP 0x1
27#define MOX_MODULE_PCI 0x2
28#define MOX_MODULE_TOPAZ 0x3
29#define MOX_MODULE_PERIDOT 0x4
30#define MOX_MODULE_USB3 0x5
31#define MOX_MODULE_PASSPCI 0x6
32
Marek Behún1055ce12020-04-08 12:02:07 +020033#define ARMADA_37XX_NB_GPIO_SEL (MVEBU_REGISTER(0x13830))
34#define ARMADA_37XX_SPI_CTRL (MVEBU_REGISTER(0x10600))
35#define ARMADA_37XX_SPI_CFG (MVEBU_REGISTER(0x10604))
36#define ARMADA_37XX_SPI_DOUT (MVEBU_REGISTER(0x10608))
37#define ARMADA_37XX_SPI_DIN (MVEBU_REGISTER(0x1060c))
Marek Behún9602a8c2018-08-21 12:22:09 +020038
Marek Behún4529fce2020-04-08 12:02:05 +020039#define ETH1_PATH "/soc/internal-regs@d0000000/ethernet@40000"
40#define MDIO_PATH "/soc/internal-regs@d0000000/mdio@32004"
41#define SFP_GPIO_PATH "/soc/internal-regs@d0000000/spi@10600/moxtet@1/gpio@0"
Marek Behún9602a8c2018-08-21 12:22:09 +020042#define PCIE_PATH "/soc/pcie@d0070000"
Marek Behún4529fce2020-04-08 12:02:05 +020043#define SFP_PATH "/sfp"
Marek Behún9602a8c2018-08-21 12:22:09 +020044
Marek Behúnf835bed2018-04-24 17:21:31 +020045DECLARE_GLOBAL_DATA_PTR;
46
Marek Behún9602a8c2018-08-21 12:22:09 +020047#if defined(CONFIG_OF_BOARD_FIXUP)
48int board_fix_fdt(void *blob)
49{
50 u8 topology[MAX_MOX_MODULES];
51 int i, size, node;
52 bool enable;
53
54 /*
55 * SPI driver is not loaded in driver model yet, but we have to find out
56 * if pcie should be enabled in U-Boot's device tree. Therefore we have
57 * to read SPI by reading/writing SPI registers directly
58 */
59
Marek Behún9602a8c2018-08-21 12:22:09 +020060 writel(0x10df, ARMADA_37XX_SPI_CFG);
Marek Behúna4e697f2020-04-08 12:02:03 +020061 /* put pin from GPIO to SPI mode */
62 clrbits_le32(ARMADA_37XX_NB_GPIO_SEL, BIT(12));
63 /* enable SPI CS1 */
64 setbits_le32(ARMADA_37XX_SPI_CTRL, BIT(17));
Marek Behún9602a8c2018-08-21 12:22:09 +020065
66 while (!(readl(ARMADA_37XX_SPI_CTRL) & 0x2))
67 udelay(1);
68
69 for (i = 0; i < MAX_MOX_MODULES; ++i) {
70 writel(0x0, ARMADA_37XX_SPI_DOUT);
71
72 while (!(readl(ARMADA_37XX_SPI_CTRL) & 0x2))
73 udelay(1);
74
75 topology[i] = readl(ARMADA_37XX_SPI_DIN) & 0xff;
76 if (topology[i] == 0xff)
77 break;
78
79 topology[i] &= 0xf;
80 }
81
82 size = i;
83
Marek Behúna4e697f2020-04-08 12:02:03 +020084 /* disable SPI CS1 */
85 clrbits_le32(ARMADA_37XX_SPI_CTRL, BIT(17));
Marek Behún9602a8c2018-08-21 12:22:09 +020086
87 if (size > 1 && (topology[1] == MOX_MODULE_PCI ||
88 topology[1] == MOX_MODULE_USB3 ||
89 topology[1] == MOX_MODULE_PASSPCI))
90 enable = true;
91 else
92 enable = false;
93
94 node = fdt_path_offset(blob, PCIE_PATH);
95
96 if (node < 0) {
97 printf("Cannot find PCIe node in U-Boot's device tree!\n");
98 return 0;
99 }
100
101 if (fdt_setprop_string(blob, node, "status",
102 enable ? "okay" : "disabled") < 0) {
103 printf("Cannot %s PCIe in U-Boot's device tree!\n",
104 enable ? "enable" : "disable");
105 return 0;
106 }
107
Marek Behún455ef5b2020-04-08 19:25:22 +0200108 if (a3700_fdt_fix_pcie_regions(blob) < 0) {
109 printf("Cannot fix PCIe regions in U-Boot's device tree!\n");
110 return 0;
111 }
112
Marek Behún9602a8c2018-08-21 12:22:09 +0200113 return 0;
114}
115#endif
116
Marek Behúnf835bed2018-04-24 17:21:31 +0200117int board_init(void)
118{
119 /* address of boot parameters */
120 gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
121
Marek Behúnf835bed2018-04-24 17:21:31 +0200122 return 0;
123}
124
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100125static int mox_do_spi(u8 *in, u8 *out, size_t size)
Marek Behúnf835bed2018-04-24 17:21:31 +0200126{
127 struct spi_slave *slave;
128 struct udevice *dev;
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100129 int ret;
Marek Behúnf835bed2018-04-24 17:21:31 +0200130
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100131 ret = spi_get_bus_and_cs(0, 1, 1000000, SPI_CPHA | SPI_CPOL,
132 "spi_generic_drv", "moxtet@1", &dev,
133 &slave);
Marek Behúnf835bed2018-04-24 17:21:31 +0200134 if (ret)
135 goto fail;
136
137 ret = spi_claim_bus(slave);
138 if (ret)
139 goto fail_free;
140
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100141 ret = spi_xfer(slave, size * 8, out, in, SPI_XFER_ONCE);
142
143 spi_release_bus(slave);
144fail_free:
145 spi_free_slave(slave);
146fail:
147 return ret;
148}
149
150static int mox_get_topology(const u8 **ptopology, int *psize, int *pis_sd)
151{
152 static int is_sd;
153 static u8 topology[MAX_MOX_MODULES - 1];
154 static int size;
155 u8 din[MAX_MOX_MODULES], dout[MAX_MOX_MODULES];
156 int ret, i;
157
158 if (size) {
159 if (ptopology)
160 *ptopology = topology;
161 if (psize)
162 *psize = size;
163 if (pis_sd)
164 *pis_sd = is_sd;
165 return 0;
166 }
Marek Behúnf835bed2018-04-24 17:21:31 +0200167
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100168 memset(din, 0, MAX_MOX_MODULES);
169 memset(dout, 0, MAX_MOX_MODULES);
170
171 ret = mox_do_spi(din, dout, MAX_MOX_MODULES);
Marek Behúnf835bed2018-04-24 17:21:31 +0200172 if (ret)
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100173 return ret;
Marek Behúnf835bed2018-04-24 17:21:31 +0200174
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100175 if (din[0] == 0x10)
176 is_sd = 1;
177 else if (din[0] == 0x00)
178 is_sd = 0;
179 else
180 return -ENODEV;
Marek Behúnf835bed2018-04-24 17:21:31 +0200181
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100182 for (i = 1; i < MAX_MOX_MODULES && din[i] != 0xff; ++i)
183 topology[i - 1] = din[i] & 0xf;
184 size = i - 1;
185
186 if (ptopology)
187 *ptopology = topology;
188 if (psize)
189 *psize = size;
190 if (pis_sd)
191 *pis_sd = is_sd;
192
193 return 0;
194}
195
Marek Behúna261d132018-12-17 16:10:02 +0100196int comphy_update_map(struct comphy_map *serdes_map, int count)
197{
198 int ret, i, size, sfpindex = -1, swindex = -1;
199 const u8 *topology;
200
201 ret = mox_get_topology(&topology, &size, NULL);
202 if (ret)
203 return ret;
204
205 for (i = 0; i < size; ++i) {
206 if (topology[i] == MOX_MODULE_SFP && sfpindex == -1)
207 sfpindex = i;
208 else if ((topology[i] == MOX_MODULE_TOPAZ ||
209 topology[i] == MOX_MODULE_PERIDOT) &&
210 swindex == -1)
211 swindex = i;
212 }
213
214 if (sfpindex >= 0 && swindex >= 0) {
215 if (sfpindex < swindex)
216 serdes_map[0].speed = PHY_SPEED_1_25G;
217 else
218 serdes_map[0].speed = PHY_SPEED_3_125G;
219 } else if (sfpindex >= 0) {
220 serdes_map[0].speed = PHY_SPEED_1_25G;
221 } else if (swindex >= 0) {
222 serdes_map[0].speed = PHY_SPEED_3_125G;
223 }
224
225 return 0;
226}
227
Marek Behún35b35132018-12-17 16:10:03 +0100228#define SW_SMI_CMD_R(d, r) (0x9800 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
229#define SW_SMI_CMD_W(d, r) (0x9400 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
230
231static int sw_multi_read(struct mii_dev *bus, int sw, int dev, int reg)
232{
233 bus->write(bus, sw, 0, 0, SW_SMI_CMD_R(dev, reg));
234 mdelay(5);
235 return bus->read(bus, sw, 0, 1);
236}
237
238static void sw_multi_write(struct mii_dev *bus, int sw, int dev, int reg,
239 u16 val)
240{
241 bus->write(bus, sw, 0, 1, val);
242 bus->write(bus, sw, 0, 0, SW_SMI_CMD_W(dev, reg));
243 mdelay(5);
244}
245
246static int sw_scratch_read(struct mii_dev *bus, int sw, int reg)
247{
248 sw_multi_write(bus, sw, 0x1c, 0x1a, (reg & 0x7f) << 8);
249 return sw_multi_read(bus, sw, 0x1c, 0x1a) & 0xff;
250}
251
252static void sw_led_write(struct mii_dev *bus, int sw, int port, int reg,
253 u16 val)
254{
255 sw_multi_write(bus, sw, port, 0x16, 0x8000 | ((reg & 7) << 12)
256 | (val & 0x7ff));
257}
258
259static void sw_blink_leds(struct mii_dev *bus, int peridot, int topaz)
260{
261 int i, p;
262 struct {
263 int port;
264 u16 val;
265 int wait;
266 } regs[] = {
267 { 2, 0xef, 1 }, { 2, 0xfe, 1 }, { 2, 0x33, 0 },
268 { 4, 0xef, 1 }, { 4, 0xfe, 1 }, { 4, 0x33, 0 },
269 { 3, 0xfe, 1 }, { 3, 0xef, 1 }, { 3, 0x33, 0 },
270 { 1, 0xfe, 1 }, { 1, 0xef, 1 }, { 1, 0x33, 0 }
271 };
272
273 for (i = 0; i < 12; ++i) {
274 for (p = 0; p < peridot; ++p) {
275 sw_led_write(bus, 0x10 + p, regs[i].port, 0,
276 regs[i].val);
277 sw_led_write(bus, 0x10 + p, regs[i].port + 4, 0,
278 regs[i].val);
279 }
280 if (topaz) {
281 sw_led_write(bus, 0x2, 0x10 + regs[i].port, 0,
282 regs[i].val);
283 }
284
285 if (regs[i].wait)
286 mdelay(75);
287 }
288}
289
290static void check_switch_address(struct mii_dev *bus, int addr)
291{
292 if (sw_scratch_read(bus, addr, 0x70) >> 3 != addr)
293 printf("Check of switch MDIO address failed for 0x%02x\n",
294 addr);
295}
296
297static int sfp, pci, topaz, peridot, usb, passpci;
298static int sfp_pos, peridot_pos[3];
299static int module_count;
300
301static int configure_peridots(struct gpio_desc *reset_gpio)
302{
303 int i, ret;
304 u8 dout[MAX_MOX_MODULES];
305
306 memset(dout, 0, MAX_MOX_MODULES);
307
308 /* set addresses of Peridot modules */
309 for (i = 0; i < peridot; ++i)
310 dout[module_count - peridot_pos[i]] = (~i) & 3;
311
312 /*
313 * if there is a SFP module connected to the last Peridot module, set
314 * the P10_SMODE to 1 for the Peridot module
315 */
316 if (sfp)
317 dout[module_count - peridot_pos[i - 1]] |= 1 << 3;
318
319 dm_gpio_set_value(reset_gpio, 1);
320 mdelay(10);
321
322 ret = mox_do_spi(NULL, dout, module_count + 1);
323
324 mdelay(10);
325 dm_gpio_set_value(reset_gpio, 0);
326
327 mdelay(50);
328
329 return ret;
330}
331
332static int get_reset_gpio(struct gpio_desc *reset_gpio)
333{
334 int node;
335
336 node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "cznic,moxtet");
337 if (node < 0) {
338 printf("Cannot find Moxtet bus device node!\n");
339 return -1;
340 }
341
342 gpio_request_by_name_nodev(offset_to_ofnode(node), "reset-gpios", 0,
343 reset_gpio, GPIOD_IS_OUT);
344
345 if (!dm_gpio_is_valid(reset_gpio)) {
346 printf("Cannot find reset GPIO for Moxtet bus!\n");
347 return -1;
348 }
349
Marek Behún35572c92018-12-17 16:10:08 +0100350 return 0;
351}
352
353int misc_init_r(void)
354{
355 int ret;
356 u8 mac1[6], mac2[6];
357
358 ret = mbox_sp_get_board_info(NULL, mac1, mac2, NULL, NULL);
359 if (ret < 0) {
360 printf("Cannot read data from OTP!\n");
361 return 0;
362 }
363
364 if (is_valid_ethaddr(mac1) && !env_get("ethaddr"))
365 eth_env_set_enetaddr("ethaddr", mac1);
366
367 if (is_valid_ethaddr(mac2) && !env_get("eth1addr"))
368 eth_env_set_enetaddr("eth1addr", mac2);
369
Marek Behún35b35132018-12-17 16:10:03 +0100370 return 0;
371}
372
Marek Behún35572c92018-12-17 16:10:08 +0100373static void mox_print_info(void)
374{
375 int ret, board_version, ram_size;
376 u64 serial_number;
377 const char *pub_key;
378
379 ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
380 &ram_size);
381 if (ret < 0)
382 return;
383
384 printf("Turris Mox:\n");
385 printf(" Board version: %i\n", board_version);
386 printf(" RAM size: %i MiB\n", ram_size);
387 printf(" Serial Number: %016llX\n", serial_number);
388
389 pub_key = mox_sp_get_ecdsa_public_key();
390 if (pub_key)
391 printf(" ECDSA Public Key: %s\n", pub_key);
392 else
393 printf("Cannot read ECDSA Public Key\n");
394}
395
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100396int last_stage_init(void)
397{
398 int ret, i;
399 const u8 *topology;
Marek Behún35b35132018-12-17 16:10:03 +0100400 int is_sd;
401 struct mii_dev *bus;
402 struct gpio_desc reset_gpio = {};
Marek Behúnf835bed2018-04-24 17:21:31 +0200403
Marek Behún35572c92018-12-17 16:10:08 +0100404 mox_print_info();
405
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100406 ret = mox_get_topology(&topology, &module_count, &is_sd);
407 if (ret) {
408 printf("Cannot read module topology!\n");
409 return 0;
410 }
411
Marek Behún35572c92018-12-17 16:10:08 +0100412 printf(" SD/eMMC version: %s\n", is_sd ? "SD" : "eMMC");
413
414 if (module_count)
415 printf("Module Topology:\n");
416
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100417 for (i = 0; i < module_count; ++i) {
418 switch (topology[i]) {
419 case MOX_MODULE_SFP:
420 printf("% 4i: SFP Module\n", i + 1);
Marek Behúnf835bed2018-04-24 17:21:31 +0200421 break;
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100422 case MOX_MODULE_PCI:
423 printf("% 4i: Mini-PCIe Module\n", i + 1);
Marek Behúnf835bed2018-04-24 17:21:31 +0200424 break;
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100425 case MOX_MODULE_TOPAZ:
426 printf("% 4i: Topaz Switch Module (4-port)\n", i + 1);
427 break;
428 case MOX_MODULE_PERIDOT:
429 printf("% 4i: Peridot Switch Module (8-port)\n", i + 1);
430 break;
431 case MOX_MODULE_USB3:
432 printf("% 4i: USB 3.0 Module (4 ports)\n", i + 1);
433 break;
434 case MOX_MODULE_PASSPCI:
435 printf("% 4i: Passthrough Mini-PCIe Module\n", i + 1);
Marek Behúnf835bed2018-04-24 17:21:31 +0200436 break;
437 default:
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100438 printf("% 4i: unknown (ID %i)\n", i + 1, topology[i]);
Marek Behúnf835bed2018-04-24 17:21:31 +0200439 }
440 }
Marek Behúnf835bed2018-04-24 17:21:31 +0200441
Marek Behún35b35132018-12-17 16:10:03 +0100442 /* now check if modules are connected in supported mode */
443
444 for (i = 0; i < module_count; ++i) {
445 switch (topology[i]) {
446 case MOX_MODULE_SFP:
447 if (sfp) {
448 printf("Error: Only one SFP module is supported!\n");
449 } else if (topaz) {
450 printf("Error: SFP module cannot be connected after Topaz Switch module!\n");
451 } else {
452 sfp_pos = i;
453 ++sfp;
454 }
455 break;
456 case MOX_MODULE_PCI:
Marek Behún4529fce2020-04-08 12:02:05 +0200457 if (pci)
Marek Behún35b35132018-12-17 16:10:03 +0100458 printf("Error: Only one Mini-PCIe module is supported!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200459 else if (usb)
Marek Behún35b35132018-12-17 16:10:03 +0100460 printf("Error: Mini-PCIe module cannot come after USB 3.0 module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200461 else if (i && (i != 1 || !passpci))
Marek Behún35b35132018-12-17 16:10:03 +0100462 printf("Error: Mini-PCIe module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200463 else
Marek Behún35b35132018-12-17 16:10:03 +0100464 ++pci;
Marek Behún35b35132018-12-17 16:10:03 +0100465 break;
466 case MOX_MODULE_TOPAZ:
Marek Behún4529fce2020-04-08 12:02:05 +0200467 if (topaz)
Marek Behún35b35132018-12-17 16:10:03 +0100468 printf("Error: Only one Topaz module is supported!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200469 else if (peridot >= 3)
Marek Behún35b35132018-12-17 16:10:03 +0100470 printf("Error: At most two Peridot modules can come before Topaz module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200471 else
Marek Behún35b35132018-12-17 16:10:03 +0100472 ++topaz;
Marek Behún35b35132018-12-17 16:10:03 +0100473 break;
474 case MOX_MODULE_PERIDOT:
475 if (sfp || topaz) {
476 printf("Error: Peridot module must come before SFP or Topaz module!\n");
477 } else if (peridot >= 3) {
478 printf("Error: At most three Peridot modules are supported!\n");
479 } else {
480 peridot_pos[peridot] = i;
481 ++peridot;
482 }
483 break;
484 case MOX_MODULE_USB3:
Marek Behún4529fce2020-04-08 12:02:05 +0200485 if (pci)
Marek Behún35b35132018-12-17 16:10:03 +0100486 printf("Error: USB 3.0 module cannot come after Mini-PCIe module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200487 else if (usb)
Marek Behún35b35132018-12-17 16:10:03 +0100488 printf("Error: Only one USB 3.0 module is supported!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200489 else if (i && (i != 1 || !passpci))
Marek Behún35b35132018-12-17 16:10:03 +0100490 printf("Error: USB 3.0 module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200491 else
Marek Behún35b35132018-12-17 16:10:03 +0100492 ++usb;
Marek Behún35b35132018-12-17 16:10:03 +0100493 break;
494 case MOX_MODULE_PASSPCI:
Marek Behún4529fce2020-04-08 12:02:05 +0200495 if (passpci)
Marek Behún35b35132018-12-17 16:10:03 +0100496 printf("Error: Only one Passthrough Mini-PCIe module is supported!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200497 else if (i != 0)
Marek Behún35b35132018-12-17 16:10:03 +0100498 printf("Error: Passthrough Mini-PCIe module should be the first connected module!\n");
Marek Behún4529fce2020-04-08 12:02:05 +0200499 else
Marek Behún35b35132018-12-17 16:10:03 +0100500 ++passpci;
Marek Behún35b35132018-12-17 16:10:03 +0100501 }
502 }
503
504 /* now configure modules */
505
506 if (get_reset_gpio(&reset_gpio) < 0)
507 return 0;
508
509 if (peridot > 0) {
510 if (configure_peridots(&reset_gpio) < 0) {
511 printf("Cannot configure Peridot modules!\n");
512 peridot = 0;
513 }
514 } else {
515 dm_gpio_set_value(&reset_gpio, 1);
516 mdelay(50);
517 dm_gpio_set_value(&reset_gpio, 0);
518 mdelay(50);
519 }
520
521 if (peridot || topaz) {
522 /*
523 * now check if the addresses are set by reading Scratch & Misc
524 * register 0x70 of Peridot (and potentially Topaz) modules
525 */
526
527 bus = miiphy_get_dev_by_name("neta@30000");
528 if (!bus) {
529 printf("Cannot get MDIO bus device!\n");
530 } else {
531 for (i = 0; i < peridot; ++i)
532 check_switch_address(bus, 0x10 + i);
533
534 if (topaz)
535 check_switch_address(bus, 0x2);
536
537 sw_blink_leds(bus, peridot, topaz);
538 }
539 }
540
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100541 printf("\n");
Marek Behúnf835bed2018-04-24 17:21:31 +0200542
Marek Behúnf68ed8b2018-12-17 16:10:01 +0100543 return 0;
Marek Behúnf835bed2018-04-24 17:21:31 +0200544}
Marek Behún4529fce2020-04-08 12:02:05 +0200545
546#if defined(CONFIG_OF_BOARD_SETUP)
547
548static int vnode_by_path(void *blob, const char *fmt, va_list ap)
549{
550 char path[128];
551
552 vsnprintf(path, 128, fmt, ap);
553 return fdt_path_offset(blob, path);
554}
555
556static int node_by_path(void *blob, const char *fmt, ...)
557{
558 va_list ap;
559 int res;
560
561 va_start(ap, fmt);
562 res = vnode_by_path(blob, fmt, ap);
563 va_end(ap);
564
565 return res;
566}
567
568static int phandle_by_path(void *blob, const char *fmt, ...)
569{
570 va_list ap;
571 int node, phandle, res;
572
573 va_start(ap, fmt);
574 node = vnode_by_path(blob, fmt, ap);
575 va_end(ap);
576
577 if (node < 0)
578 return node;
579
580 phandle = fdt_get_phandle(blob, node);
581 if (phandle > 0)
582 return phandle;
583
584 phandle = fdt_get_max_phandle(blob);
585 if (phandle < 0)
586 return phandle;
587
588 phandle += 1;
589
590 res = fdt_setprop_u32(blob, node, "linux,phandle", phandle);
591 if (res < 0)
592 return res;
593
594 res = fdt_setprop_u32(blob, node, "phandle", phandle);
595 if (res < 0)
596 return res;
597
598 return phandle;
599}
600
601static int enable_by_path(void *blob, const char *fmt, ...)
602{
603 va_list ap;
604 int node;
605
606 va_start(ap, fmt);
607 node = vnode_by_path(blob, fmt, ap);
608 va_end(ap);
609
610 if (node < 0)
611 return node;
612
613 return fdt_setprop_string(blob, node, "status", "okay");
614}
615
616static bool is_topaz(int id)
617{
618 return topaz && id == peridot + topaz - 1;
619}
620
621static int switch_addr(int id)
622{
623 return is_topaz(id) ? 0x2 : 0x10 + id;
624}
625
626static int setup_switch(void *blob, int id)
627{
628 int res, addr, i, node, phandle;
629
630 addr = switch_addr(id);
631
632 /* first enable the switch by setting status = "okay" */
633 res = enable_by_path(blob, MDIO_PATH "/switch%i@%x", id, addr);
634 if (res < 0)
635 return res;
636
637 /*
638 * now if there are more switches or a SFP module coming after,
639 * enable corresponding ports
640 */
641 if (id < peridot + topaz - 1) {
642 res = enable_by_path(blob,
643 MDIO_PATH "/switch%i@%x/ports/port@a",
644 id, addr);
645 } else if (id == peridot - 1 && !topaz && sfp) {
646 res = enable_by_path(blob,
647 MDIO_PATH "/switch%i@%x/ports/port-sfp@a",
648 id, addr);
649 } else {
650 res = 0;
651 }
652 if (res < 0)
653 return res;
654
655 if (id >= peridot + topaz - 1)
656 return 0;
657
658 /* finally change link property if needed */
659 node = node_by_path(blob, MDIO_PATH "/switch%i@%x/ports/port@a", id,
660 addr);
661 if (node < 0)
662 return node;
663
664 for (i = id + 1; i < peridot + topaz; ++i) {
665 phandle = phandle_by_path(blob,
666 MDIO_PATH "/switch%i@%x/ports/port@%x",
667 i, switch_addr(i),
668 is_topaz(i) ? 5 : 9);
669 if (phandle < 0)
670 return phandle;
671
672 if (i == id + 1)
673 res = fdt_setprop_u32(blob, node, "link", phandle);
674 else
675 res = fdt_appendprop_u32(blob, node, "link", phandle);
676 if (res < 0)
677 return res;
678 }
679
680 return 0;
681}
682
683static int remove_disabled_nodes(void *blob)
684{
685 while (1) {
686 int res, offset;
687
688 offset = fdt_node_offset_by_prop_value(blob, -1, "status",
689 "disabled", 9);
690 if (offset < 0)
691 break;
692
693 res = fdt_del_node(blob, offset);
694 if (res < 0)
695 return res;
696 }
697
698 return 0;
699}
700
701int ft_board_setup(void *blob, bd_t *bd)
702{
703 int node, phandle, res;
704
705 /*
706 * If MOX B (PCI), MOX F (USB) or MOX G (Passthrough PCI) modules are
707 * connected, enable the PCIe node.
708 */
709 if (pci || usb || passpci) {
710 node = fdt_path_offset(blob, PCIE_PATH);
711 if (node < 0)
712 return node;
713
714 res = fdt_setprop_string(blob, node, "status", "okay");
715 if (res < 0)
716 return res;
Marek Behún455ef5b2020-04-08 19:25:22 +0200717
718 /* Fix PCIe regions for devices with 4 GB RAM */
719 res = a3700_fdt_fix_pcie_regions(blob);
720 if (res < 0)
721 return res;
Marek Behún4529fce2020-04-08 12:02:05 +0200722 }
723
724 /*
725 * If MOX C (Topaz switch) and/or MOX E (Peridot switch) are connected,
726 * enable the eth1 node and setup the switches.
727 */
728 if (peridot || topaz) {
729 int i;
730
731 res = enable_by_path(blob, ETH1_PATH);
732 if (res < 0)
733 return res;
734
735 for (i = 0; i < peridot + topaz; ++i) {
736 res = setup_switch(blob, i);
737 if (res < 0)
738 return res;
739 }
740 }
741
742 /*
743 * If MOX D (SFP cage module) is connected, enable the SFP node and eth1
744 * node. If there is no Peridot switch between MOX A and MOX D, add link
745 * to the SFP node to eth1 node.
746 * Also enable and configure SFP GPIO controller node.
747 */
748 if (sfp) {
749 res = enable_by_path(blob, SFP_PATH);
750 if (res < 0)
751 return res;
752
753 res = enable_by_path(blob, ETH1_PATH);
754 if (res < 0)
755 return res;
756
757 if (!peridot) {
758 phandle = phandle_by_path(blob, SFP_PATH);
759 if (phandle < 0)
760 return res;
761
762 node = node_by_path(blob, ETH1_PATH);
763 if (node < 0)
764 return node;
765
766 res = fdt_setprop_u32(blob, node, "sfp", phandle);
767 if (res < 0)
768 return res;
769
770 res = fdt_setprop_string(blob, node, "phy-mode",
771 "sgmii");
772 if (res < 0)
773 return res;
774 }
775
776 res = enable_by_path(blob, SFP_GPIO_PATH);
777 if (res < 0)
778 return res;
779
780 if (sfp_pos) {
781 char newname[16];
782
783 /* moxtet-sfp is on non-zero position, change default */
784 node = node_by_path(blob, SFP_GPIO_PATH);
785 if (node < 0)
786 return node;
787
788 res = fdt_setprop_u32(blob, node, "reg", sfp_pos);
789 if (res < 0)
790 return res;
791
792 sprintf(newname, "gpio@%x", sfp_pos);
793
794 res = fdt_set_name(blob, node, newname);
795 if (res < 0)
796 return res;
797 }
798 }
799
800 fdt_fixup_ethernet(blob);
801
802 /* Finally remove disabled nodes, as per Rob Herring's request. */
803 remove_disabled_nodes(blob);
804
805 return 0;
806}
807
808#endif