command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / board / theadorable / theadorable.c
index 0e232656fc906f05d95b84fd61797f39aa5dbda7..6ee09034ea4e376514347012c9182d7974ed2fac 100644 (file)
@@ -1,22 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2015-2016 Stefan Roese <sr@denx.de>
- *
- * SPDX-License-Identifier:    GPL-2.0+
+ * Copyright (C) 2015-2019 Stefan Roese <sr@denx.de>
  */
 
 #include <common.h>
+#include <command.h>
+#include <console.h>
+#include <i2c.h>
+#include <init.h>
+#include <net.h>
+#include <pci.h>
+#if !defined(CONFIG_SPL_BUILD)
+#include <bootcount.h>
+#endif
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
+#include <linux/mbus.h>
 #ifdef CONFIG_NET
 #include <netdev.h>
 #endif
+#include <u-boot/crc.h>
+#include "theadorable.h"
 
 #include "../drivers/ddr/marvell/axp/ddr3_hw_training.h"
 #include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#define MV_USB_PHY_BASE                        (MVEBU_AXP_USB_BASE + 0x800)
+#define PHY_CHANNEL_RX_CTRL0_REG(port, chan) \
+       (MV_USB_PHY_BASE + ((port) << 12) + ((chan) << 6) + 0x8)
+
 #define THEADORABLE_GPP_OUT_ENA_LOW    0x00336780
 #define THEADORABLE_GPP_OUT_ENA_MID    0x00003cf0
 #define THEADORABLE_GPP_OUT_ENA_HIGH   (~(0x0))
@@ -25,6 +41,16 @@ DECLARE_GLOBAL_DATA_PTR;
 #define THEADORABLE_GPP_OUT_VAL_MID    0x0007000c
 #define THEADORABLE_GPP_OUT_VAL_HIGH   0x00000000
 
+#define GPIO_USB0_PWR_ON               18
+#define GPIO_USB1_PWR_ON               19
+
+#define PEX_SWITCH_NOT_FOUNT_LIMIT     3
+
+#define STM_I2C_BUS    1
+#define STM_I2C_ADDR   0x27
+#define REBOOT_DELAY   1000            /* reboot-delay in ms */
+#define ABORT_TIMEOUT  3000            /* 3 seconds reboot abort timeout */
+
 /* DDR3 static configuration */
 static MV_DRAM_MC_INIT ddr3_theadorable[MV_MAX_DDR3_STATIC_SIZE] = {
        {0x00001400, 0x7301ca28},       /* DDR SDRAM Configuration Register */
@@ -96,17 +122,30 @@ MV_BIN_SERDES_CFG theadorable_serdes_cfg[] = {
        },
 };
 
+/*
+ * Define a board-specific detection pulse-width array for the SerDes PCIe
+ * interfaces. If not defined in the board code, the default of currently 2
+ * is used. Values from 0...3 are possible (2 bits).
+ */
+u8 serdes_pex_pulse_width[4] = { 0, 2, 2, 2 };
+
 MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
 {
        /* Only one mode supported for this board */
        return &board_ddr_modes[0];
 }
 
-MV_BIN_SERDES_CFG *board_serdes_cfg_get(u8 pex_mode)
+MV_BIN_SERDES_CFG *board_serdes_cfg_get(void)
 {
        return &theadorable_serdes_cfg[0];
 }
 
+u8 board_sat_r_get(u8 dev_num, u8 reg)
+{
+       /* Bit x enables PCI 2.0 link capabilities instead of PCI 1.x */
+       return 0xe;     /* PEX port 0 is PCIe Gen1, PEX port 1..3 PCIe Gen2 */
+}
+
 int board_early_init_f(void)
 {
        /* Configure MPP */
@@ -133,15 +172,48 @@ int board_early_init_f(void)
 
 int board_init(void)
 {
+       int ret;
+
        /* adress of boot parameters */
        gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
 
+       /*
+        * Map SPI devices via MBUS so that they can be accessed via
+        * the SPI direct access mode
+        */
+       mbus_dt_setup_win(&mbus_state, SPI_BUS0_DEV1_BASE, SPI_BUS0_DEV1_SIZE,
+                         CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI0_CS1);
+       mbus_dt_setup_win(&mbus_state, SPI_BUS1_DEV2_BASE, SPI_BUS0_DEV1_SIZE,
+                         CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI1_CS2);
+
+       /*
+        * Set RX Channel Control 0 Register:
+        * Tests have shown, that setting the LPF_COEF from 0 (1/8)
+        * to 3 (1/1) results in a more stable USB connection.
+        */
+       setbits_le32(PHY_CHANNEL_RX_CTRL0_REG(0, 1), 0xc);
+       setbits_le32(PHY_CHANNEL_RX_CTRL0_REG(0, 2), 0xc);
+       setbits_le32(PHY_CHANNEL_RX_CTRL0_REG(0, 3), 0xc);
+
+       /* Toggle USB power */
+       ret = gpio_request(GPIO_USB0_PWR_ON, "USB0_PWR_ON");
+       if (ret < 0)
+               return ret;
+       gpio_direction_output(GPIO_USB0_PWR_ON, 0);
+       ret = gpio_request(GPIO_USB1_PWR_ON, "USB1_PWR_ON");
+       if (ret < 0)
+               return ret;
+       gpio_direction_output(GPIO_USB1_PWR_ON, 0);
+       mdelay(1);
+       gpio_set_value(GPIO_USB0_PWR_ON, 1);
+       gpio_set_value(GPIO_USB1_PWR_ON, 1);
+
        return 0;
 }
 
 int checkboard(void)
 {
-       puts("Board: theadorable\n");
+       board_fpga_add();
 
        return 0;
 }
@@ -154,18 +226,126 @@ int board_eth_init(bd_t *bis)
 }
 #endif
 
-int board_video_init(void)
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOARD_LATE_INIT)
+int board_late_init(void)
 {
-       struct mvebu_lcd_info lcd_info;
-
-       /* Reserved memory area via CONFIG_SYS_MEM_TOP_HIDE */
-       lcd_info.fb_base        = gd->ram_size;
-       lcd_info.x_res          = 240;
-       lcd_info.x_fp           = 1;
-       lcd_info.x_bp           = 45;
-       lcd_info.y_res          = 320;
-       lcd_info.y_fp           = 1;
-       lcd_info.y_bp           = 3;
-
-       return mvebu_lcd_register_init(&lcd_info);
+       pci_dev_t bdf;
+       ulong bootcount;
+
+       /*
+        * Check if the PEX switch is detected (somtimes its not available
+        * on the PCIe bus). In this case, try to recover by issuing a
+        * soft-reset or even a power-cycle, depending on the bootcounter
+        * value.
+        */
+       bdf = pci_find_device(PCI_VENDOR_ID_PLX, 0x8619, 0);
+       if (bdf == -1) {
+               unsigned long start_time = get_timer(0);
+               u8 i2c_buf[8];
+               int ret;
+
+               /* PEX switch not found! */
+               bootcount = bootcount_load();
+               printf("Failed to find PLX PEX-switch (bootcount=%ld)\n",
+                      bootcount);
+
+               /*
+                * The user can exit this boot-loop in the error case by
+                * hitting Ctrl-C. So wait some time for this key here.
+                */
+               printf("Continue booting with Ctrl-C, otherwise rebooting\n");
+               do {
+                       /* Handle control-c and timeouts */
+                       if (ctrlc()) {
+                               printf("PEX error boot-loop aborted!\n");
+                               return 0;
+                       }
+               } while (get_timer(start_time) < ABORT_TIMEOUT);
+
+
+               /*
+                * At this stage the bootcounter has not been incremented
+                * yet. We need to do this manually here to get an actually
+                * working bootcounter in this error case.
+                */
+               bootcount_inc();
+
+               if (bootcount > PEX_SWITCH_NOT_FOUNT_LIMIT) {
+                       printf("Issuing power-switch via uC!\n");
+
+                       printf("Issuing power-switch via uC!\n");
+                       i2c_set_bus_num(STM_I2C_BUS);
+                       i2c_buf[0] = STM_I2C_ADDR << 1;
+                       i2c_buf[1] = 0xc5;      /* cmd */
+                       i2c_buf[2] = 0x01;      /* enable */
+                       /* Delay before reboot */
+                       i2c_buf[3] = REBOOT_DELAY & 0x00ff;
+                       i2c_buf[4] = (REBOOT_DELAY & 0xff00) >> 8;
+                       /* Delay before shutdown */
+                       i2c_buf[5] = 0x00;
+                       i2c_buf[6] = 0x00;
+                       i2c_buf[7] = crc8(0x72, &i2c_buf[0], 7);
+
+                       ret = i2c_write(STM_I2C_ADDR, 0, 0, &i2c_buf[1], 7);
+                       if (ret) {
+                               printf("I2C write error (ret=%d)\n", ret);
+                               printf("Issuing soft-reset...\n");
+                               /* default handling: SOFT reset */
+                               do_reset(NULL, 0, 0, NULL);
+                       }
+
+                       /* Wait for power-cycle to occur... */
+                       printf("Waiting for power-cycle via uC...\n");
+                       while (1)
+                               ;
+               } else {
+                       printf("Issuing soft-reset...\n");
+                       /* default handling: SOFT reset */
+                       do_reset(NULL, 0, 0, NULL);
+               }
+       }
+
+       return 0;
 }
+#endif
+
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_PCI)
+int do_pcie_test(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+       pci_dev_t bdf;
+       u16 ven_id, dev_id;
+
+       if (argc != 3)
+               return cmd_usage(cmdtp);
+
+       ven_id = simple_strtoul(argv[1], NULL, 16);
+       dev_id = simple_strtoul(argv[2], NULL, 16);
+
+       printf("Checking for PCIe device: VendorID 0x%04x, DeviceId 0x%04x\n",
+              ven_id, dev_id);
+
+       /*
+        * Check if the PCIe device is detected (somtimes its not available
+        * on the PCIe bus)
+        */
+       bdf = pci_find_device(ven_id, dev_id, 0);
+       if (bdf == -1) {
+               /* PCIe device not found! */
+               printf("Failed to find PCIe device\n");
+       } else {
+               /* PCIe device found! */
+               printf("PCIe device found, resetting board...\n");
+
+               /* default handling: SOFT reset */
+               do_reset(NULL, 0, 0, NULL);
+       }
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       pcie,   3,   0,     do_pcie_test,
+       "Test for presence of a PCIe device",
+       "<VendorID> <DeviceID>"
+);
+#endif