Commit 7dd7c2e796ca6481c9341cf9df0328bdb5bd9fd8

Authored by Marek Behún
Committed by Stefan Roese
1 parent 9433cd1109

arm: mvebu: turris_mox: Check and configure modules

Check if Mox modules are connected in supported mode, then configure
the MDIO addresses of switch modules.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
Signed-off-by: Stefan Roese <sr@denx.de>

Showing 2 changed files with 244 additions and 1 deletions Side-by-side Diff

arch/arm/dts/armada-3720-turris-mox.dts
... ... @@ -110,6 +110,17 @@
110 110 spi-max-frequency = <20000000>;
111 111 m25p,fast-read;
112 112 };
  113 +
  114 + moxtet@1 {
  115 + #address-cells = <1>;
  116 + #size-cells = <0>;
  117 + compatible = "cznic,moxtet";
  118 + reg = <1>;
  119 + reset-gpios = <&gpiosb 2 GPIO_ACTIVE_LOW>;
  120 + spi-max-frequency = <1000000>;
  121 + spi-cpol;
  122 + spi-cpha;
  123 + };
113 124 };
114 125  
115 126 &uart0 {
board/CZ.NIC/turris_mox/turris_mox.c
... ... @@ -4,11 +4,13 @@
4 4 */
5 5  
6 6 #include <common.h>
  7 +#include <asm/gpio.h>
7 8 #include <asm/io.h>
8 9 #include <dm.h>
9 10 #include <clk.h>
10 11 #include <spi.h>
11 12 #include <mvebu/comphy.h>
  13 +#include <miiphy.h>
12 14 #include <linux/string.h>
13 15 #include <linux/libfdt.h>
14 16 #include <fdt_support.h>
15 17  
... ... @@ -239,11 +241,138 @@
239 241 return 0;
240 242 }
241 243  
  244 +#define SW_SMI_CMD_R(d, r) (0x9800 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
  245 +#define SW_SMI_CMD_W(d, r) (0x9400 | (((d) & 0x1f) << 5) | ((r) & 0x1f))
  246 +
  247 +static int sw_multi_read(struct mii_dev *bus, int sw, int dev, int reg)
  248 +{
  249 + bus->write(bus, sw, 0, 0, SW_SMI_CMD_R(dev, reg));
  250 + mdelay(5);
  251 + return bus->read(bus, sw, 0, 1);
  252 +}
  253 +
  254 +static void sw_multi_write(struct mii_dev *bus, int sw, int dev, int reg,
  255 + u16 val)
  256 +{
  257 + bus->write(bus, sw, 0, 1, val);
  258 + bus->write(bus, sw, 0, 0, SW_SMI_CMD_W(dev, reg));
  259 + mdelay(5);
  260 +}
  261 +
  262 +static int sw_scratch_read(struct mii_dev *bus, int sw, int reg)
  263 +{
  264 + sw_multi_write(bus, sw, 0x1c, 0x1a, (reg & 0x7f) << 8);
  265 + return sw_multi_read(bus, sw, 0x1c, 0x1a) & 0xff;
  266 +}
  267 +
  268 +static void sw_led_write(struct mii_dev *bus, int sw, int port, int reg,
  269 + u16 val)
  270 +{
  271 + sw_multi_write(bus, sw, port, 0x16, 0x8000 | ((reg & 7) << 12)
  272 + | (val & 0x7ff));
  273 +}
  274 +
  275 +static void sw_blink_leds(struct mii_dev *bus, int peridot, int topaz)
  276 +{
  277 + int i, p;
  278 + struct {
  279 + int port;
  280 + u16 val;
  281 + int wait;
  282 + } regs[] = {
  283 + { 2, 0xef, 1 }, { 2, 0xfe, 1 }, { 2, 0x33, 0 },
  284 + { 4, 0xef, 1 }, { 4, 0xfe, 1 }, { 4, 0x33, 0 },
  285 + { 3, 0xfe, 1 }, { 3, 0xef, 1 }, { 3, 0x33, 0 },
  286 + { 1, 0xfe, 1 }, { 1, 0xef, 1 }, { 1, 0x33, 0 }
  287 + };
  288 +
  289 + for (i = 0; i < 12; ++i) {
  290 + for (p = 0; p < peridot; ++p) {
  291 + sw_led_write(bus, 0x10 + p, regs[i].port, 0,
  292 + regs[i].val);
  293 + sw_led_write(bus, 0x10 + p, regs[i].port + 4, 0,
  294 + regs[i].val);
  295 + }
  296 + if (topaz) {
  297 + sw_led_write(bus, 0x2, 0x10 + regs[i].port, 0,
  298 + regs[i].val);
  299 + }
  300 +
  301 + if (regs[i].wait)
  302 + mdelay(75);
  303 + }
  304 +}
  305 +
  306 +static void check_switch_address(struct mii_dev *bus, int addr)
  307 +{
  308 + if (sw_scratch_read(bus, addr, 0x70) >> 3 != addr)
  309 + printf("Check of switch MDIO address failed for 0x%02x\n",
  310 + addr);
  311 +}
  312 +
  313 +static int sfp, pci, topaz, peridot, usb, passpci;
  314 +static int sfp_pos, peridot_pos[3];
  315 +static int module_count;
  316 +
  317 +static int configure_peridots(struct gpio_desc *reset_gpio)
  318 +{
  319 + int i, ret;
  320 + u8 dout[MAX_MOX_MODULES];
  321 +
  322 + memset(dout, 0, MAX_MOX_MODULES);
  323 +
  324 + /* set addresses of Peridot modules */
  325 + for (i = 0; i < peridot; ++i)
  326 + dout[module_count - peridot_pos[i]] = (~i) & 3;
  327 +
  328 + /*
  329 + * if there is a SFP module connected to the last Peridot module, set
  330 + * the P10_SMODE to 1 for the Peridot module
  331 + */
  332 + if (sfp)
  333 + dout[module_count - peridot_pos[i - 1]] |= 1 << 3;
  334 +
  335 + dm_gpio_set_value(reset_gpio, 1);
  336 + mdelay(10);
  337 +
  338 + ret = mox_do_spi(NULL, dout, module_count + 1);
  339 +
  340 + mdelay(10);
  341 + dm_gpio_set_value(reset_gpio, 0);
  342 +
  343 + mdelay(50);
  344 +
  345 + return ret;
  346 +}
  347 +
  348 +static int get_reset_gpio(struct gpio_desc *reset_gpio)
  349 +{
  350 + int node;
  351 +
  352 + node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "cznic,moxtet");
  353 + if (node < 0) {
  354 + printf("Cannot find Moxtet bus device node!\n");
  355 + return -1;
  356 + }
  357 +
  358 + gpio_request_by_name_nodev(offset_to_ofnode(node), "reset-gpios", 0,
  359 + reset_gpio, GPIOD_IS_OUT);
  360 +
  361 + if (!dm_gpio_is_valid(reset_gpio)) {
  362 + printf("Cannot find reset GPIO for Moxtet bus!\n");
  363 + return -1;
  364 + }
  365 +
  366 + return 0;
  367 +}
  368 +
242 369 int last_stage_init(void)
243 370 {
244 371 int ret, i;
245 372 const u8 *topology;
246   - int module_count, is_sd;
  373 + int is_sd;
  374 + struct mii_dev *bus;
  375 + struct gpio_desc reset_gpio = {};
247 376  
248 377 ret = mox_get_topology(&topology, &module_count, &is_sd);
249 378 if (ret) {
... ... @@ -275,6 +404,109 @@
275 404 break;
276 405 default:
277 406 printf("% 4i: unknown (ID %i)\n", i + 1, topology[i]);
  407 + }
  408 + }
  409 +
  410 + /* now check if modules are connected in supported mode */
  411 +
  412 + for (i = 0; i < module_count; ++i) {
  413 + switch (topology[i]) {
  414 + case MOX_MODULE_SFP:
  415 + if (sfp) {
  416 + printf("Error: Only one SFP module is supported!\n");
  417 + } else if (topaz) {
  418 + printf("Error: SFP module cannot be connected after Topaz Switch module!\n");
  419 + } else {
  420 + sfp_pos = i;
  421 + ++sfp;
  422 + }
  423 + break;
  424 + case MOX_MODULE_PCI:
  425 + if (pci) {
  426 + printf("Error: Only one Mini-PCIe module is supported!\n");
  427 + } else if (usb) {
  428 + printf("Error: Mini-PCIe module cannot come after USB 3.0 module!\n");
  429 + } else if (i && (i != 1 || !passpci)) {
  430 + printf("Error: Mini-PCIe module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
  431 + } else {
  432 + ++pci;
  433 + }
  434 + break;
  435 + case MOX_MODULE_TOPAZ:
  436 + if (topaz) {
  437 + printf("Error: Only one Topaz module is supported!\n");
  438 + } else if (peridot >= 3) {
  439 + printf("Error: At most two Peridot modules can come before Topaz module!\n");
  440 + } else {
  441 + ++topaz;
  442 + }
  443 + break;
  444 + case MOX_MODULE_PERIDOT:
  445 + if (sfp || topaz) {
  446 + printf("Error: Peridot module must come before SFP or Topaz module!\n");
  447 + } else if (peridot >= 3) {
  448 + printf("Error: At most three Peridot modules are supported!\n");
  449 + } else {
  450 + peridot_pos[peridot] = i;
  451 + ++peridot;
  452 + }
  453 + break;
  454 + case MOX_MODULE_USB3:
  455 + if (pci) {
  456 + printf("Error: USB 3.0 module cannot come after Mini-PCIe module!\n");
  457 + } else if (usb) {
  458 + printf("Error: Only one USB 3.0 module is supported!\n");
  459 + } else if (i && (i != 1 || !passpci)) {
  460 + printf("Error: USB 3.0 module should be the first connected module or come right after Passthrough Mini-PCIe module!\n");
  461 + } else {
  462 + ++usb;
  463 + }
  464 + break;
  465 + case MOX_MODULE_PASSPCI:
  466 + if (passpci) {
  467 + printf("Error: Only one Passthrough Mini-PCIe module is supported!\n");
  468 + } else if (i != 0) {
  469 + printf("Error: Passthrough Mini-PCIe module should be the first connected module!\n");
  470 + } else {
  471 + ++passpci;
  472 + }
  473 + }
  474 + }
  475 +
  476 + /* now configure modules */
  477 +
  478 + if (get_reset_gpio(&reset_gpio) < 0)
  479 + return 0;
  480 +
  481 + if (peridot > 0) {
  482 + if (configure_peridots(&reset_gpio) < 0) {
  483 + printf("Cannot configure Peridot modules!\n");
  484 + peridot = 0;
  485 + }
  486 + } else {
  487 + dm_gpio_set_value(&reset_gpio, 1);
  488 + mdelay(50);
  489 + dm_gpio_set_value(&reset_gpio, 0);
  490 + mdelay(50);
  491 + }
  492 +
  493 + if (peridot || topaz) {
  494 + /*
  495 + * now check if the addresses are set by reading Scratch & Misc
  496 + * register 0x70 of Peridot (and potentially Topaz) modules
  497 + */
  498 +
  499 + bus = miiphy_get_dev_by_name("neta@30000");
  500 + if (!bus) {
  501 + printf("Cannot get MDIO bus device!\n");
  502 + } else {
  503 + for (i = 0; i < peridot; ++i)
  504 + check_switch_address(bus, 0x10 + i);
  505 +
  506 + if (topaz)
  507 + check_switch_address(bus, 0x2);
  508 +
  509 + sw_blink_leds(bus, peridot, topaz);
278 510 }
279 511 }
280 512