]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - board/enbw/enbw_cmc/enbw_cmc.c
Merge remote-tracking branch 'u-boot-samsung/master'
[karo-tx-uboot.git] / board / enbw / enbw_cmc / enbw_cmc.c
index 6c0d931eea06921f10f4625ee4dfd256e27d1799..53b83621473239e2ce5739c7c00ce38099696768 100644 (file)
  * Copyright (C) 2009 Nick Thompson, GE Fanuc, Ltd. <nick.thompson@gefanuc.com>
  * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <mmc.h>
 #include <net.h>
 #include <netdev.h>
+#include <spi.h>
+#include <linux/ctype.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/da850_lowlevel.h>
 #include <asm/arch/davinci_misc.h>
-#include <asm/arch/emif_defs.h>
+#include <asm/ti-common/davinci_nand.h>
 #include <asm/arch/emac_defs.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux_defs.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sdmmc_defs.h>
 #include <asm/arch/timer_defs.h>
+#include <asm/davinci_rtc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -86,16 +77,22 @@ static const struct pinmux_config enbw_pins[] = {
        { pinmux(5), 1, 0 },
        { pinmux(5), 1, 3 },
        { pinmux(5), 1, 7 },
-       { pinmux(6), 1, 0 },
-       { pinmux(6), 1, 1 },
+       { pinmux(5), 1, 5 },
+       { pinmux(5), 1, 4 },
+       { pinmux(5), 1, 3 },
+       { pinmux(5), 1, 2 },
+       { pinmux(5), 1, 1 },
+       { pinmux(5), 1, 0 },
+       { pinmux(6), 8, 0 },
+       { pinmux(6), 8, 1 },
        { pinmux(6), 8, 2 },
        { pinmux(6), 8, 3 },
-       { pinmux(6), 1, 4 },
+       { pinmux(6), 8, 4 },
        { pinmux(6), 8, 5 },
        { pinmux(6), 1, 7 },
        { pinmux(7), 8, 2 },
        { pinmux(7), 1, 3 },
-       { pinmux(7), 1, 6 },
+       { pinmux(7), 8, 6 },
        { pinmux(7), 1, 7 },
        { pinmux(13), 8, 2 },
        { pinmux(13), 8, 3 },
@@ -163,24 +160,37 @@ struct gpio_config {
        unsigned char value;
 };
 
-static const struct gpio_config enbw_gpio_config[] = {
+static const struct gpio_config enbw_gpio_config_hut[] = {
+       { "RS485 enable",       8, 11, 1, 0 },
+       { "RS485 iso",          8, 10, 1, 1 },
+       { "W2HUT RS485 Rx ena", 8,  9, 1, 0 },
+       { "W2HUT RS485 iso",    8,  8, 1, 1 },
+};
+
+static const struct gpio_config enbw_gpio_config_w[] = {
        { "RS485 enable",       8, 11, 1, 0 },
        { "RS485 iso",          8, 10, 1, 0 },
        { "W2HUT RS485 Rx ena", 8,  9, 1, 0 },
        { "W2HUT RS485 iso",    8,  8, 1, 0 },
+};
+
+static const struct gpio_config enbw_gpio_config[] = {
        { "LAN reset",          7, 15, 1, 1 },
        { "ena 11V PLC",        7, 14, 1, 0 },
        { "ena 1.5V PLC",       7, 13, 1, 0 },
        { "disable VBUS",       7, 12, 1, 1 },
-       { "PLC reset",          6, 13, 1, 1 },
+       { "PLC reset",          6, 13, 1, 0 },
        { "LCM RS",             6, 12, 1, 0 },
        { "LCM R/W",            6, 11, 1, 0 },
        { "PLC pairing",        6, 10, 1, 1 },
        { "PLC MDIO CLK",       6,  9, 1, 0 },
        { "HK218",              6,  8, 1, 0 },
        { "HK218 Rx",           6,  1, 1, 1 },
-       { "TPM reset",          6,  0, 1, 1 },
-       { "LCM E",              2,  2, 1, 1 },
+       { "TPM reset",          6,  0, 1, 0 },
+       { "Board-Type",         3,  9, 0, 0 },
+       { "HW-ID0",             2,  7, 0, 0 },
+       { "HW-ID1",             2,  6, 0, 0 },
+       { "HW-ID2",             2,  3, 0, 0 },
        { "PV-IF RxD ena",      0, 15, 1, 1 },
        { "LED1",               1, 15, 1, 1 },
        { "LED2",               0,  1, 1, 1 },
@@ -229,34 +239,57 @@ static void enbw_cmc_switch(int port, int on)
        }
 }
 
-int board_init(void)
+static int enbw_cmc_init_gpio(const struct gpio_config *conf, int sz)
 {
        int i, ret;
 
-#ifndef CONFIG_USE_IRQ
-       irq_init();
-#endif
-       /* address of boot parameters, not used as booting with DTT */
-       gd->bd->bi_boot_params = 0;
-
-       for (i = 0; i < ARRAY_SIZE(enbw_gpio_config); i++) {
-               int gpio = enbw_gpio_config[i].bank * 16 +
-                       enbw_gpio_config[i].gpio;
+       for (i = 0; i < sz; i++) {
+               int gpio = conf[i].bank * 16 +
+                       conf[i].gpio;
 
-               ret = gpio_request(gpio, enbw_gpio_config[i].name);
+               ret = gpio_request(gpio, conf[i].name);
                if (ret) {
                        printf("%s: Could not get %s gpio\n", __func__,
-                               enbw_gpio_config[i].name);
-                       return -1;
+                               conf[i].name);
+                       return ret;
                }
 
-               if (enbw_gpio_config[i].out)
+               if (conf[i].out)
                        gpio_direction_output(gpio,
-                               enbw_gpio_config[i].value);
+                               conf[i].value);
                else
                        gpio_direction_input(gpio);
        }
 
+       return 0;
+}
+
+int board_init(void)
+{
+       int board_type, hw_id;
+
+#ifndef CONFIG_USE_IRQ
+       irq_init();
+#endif
+       /* address of boot parameters, not used as booting with DTT */
+       gd->bd->bi_boot_params = 0;
+
+       enbw_cmc_init_gpio(enbw_gpio_config, ARRAY_SIZE(enbw_gpio_config));
+
+       /* detect HW version */
+       board_type = gpio_get_value(CONFIG_ENBW_CMC_BOARD_TYPE);
+       hw_id = gpio_get_value(CONFIG_ENBW_CMC_HW_ID_BIT0) +
+               (gpio_get_value(CONFIG_ENBW_CMC_HW_ID_BIT1) << 1) +
+               (gpio_get_value(CONFIG_ENBW_CMC_HW_ID_BIT2) << 2);
+       printf("BOARD: CMC-%s hw id: %d\n", (board_type ? "w2" : "hut"),
+               hw_id);
+       if (board_type)
+               enbw_cmc_init_gpio(enbw_gpio_config_w,
+                       ARRAY_SIZE(enbw_gpio_config_w));
+       else
+               enbw_cmc_init_gpio(enbw_gpio_config_hut,
+                       ARRAY_SIZE(enbw_gpio_config_hut));
+
        /* setup the SUSPSRC for ARM to control emulation suspend */
        clrbits_le32(&davinci_syscfg_regs->suspsrc,
                (DAVINCI_SYSCFG_SUSPSRC_EMAC | DAVINCI_SYSCFG_SUSPSRC_I2C |
@@ -267,31 +300,284 @@ int board_init(void)
 }
 
 #ifdef CONFIG_DRIVER_TI_EMAC
+
+#define KSZ_CMD_READ   0x03
+#define KSZ_CMD_WRITE  0x02
+#define KSZ_ID         0x95
+
+static int enbw_cmc_switch_read(struct spi_slave *spi, u8 reg, u8 *val)
+{
+       unsigned long flags = SPI_XFER_BEGIN;
+       int ret;
+       int cmd_len;
+       u8 cmd[2];
+
+       cmd[0] = KSZ_CMD_READ;
+       cmd[1] = reg;
+       cmd_len = 2;
+
+       ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+       if (ret) {
+               debug("Failed to send command (%zu bytes): %d\n",
+                               cmd_len, ret);
+               return -EINVAL;
+       }
+       flags |= SPI_XFER_END;
+       *val = 0;
+       cmd_len = 1;
+       ret = spi_xfer(spi, cmd_len * 8, NULL, val, flags);
+       if (ret) {
+               debug("Failed to read (%zu bytes): %d\n",
+                               cmd_len, ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int enbw_cmc_switch_read_ident(struct spi_slave *spi)
+{
+       int ret;
+       u8 val;
+
+       ret = enbw_cmc_switch_read(spi, 0, &val);
+       if (ret) {
+               debug("Failed to read\n");
+               return -EINVAL;
+       }
+
+       if (val != KSZ_ID)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int enbw_cmc_switch_write(struct spi_slave *spi, unsigned long reg,
+               unsigned long val)
+{
+       unsigned long flags = SPI_XFER_BEGIN;
+       int ret;
+       int cmd_len;
+       u8 cmd[3];
+
+       cmd[0] = KSZ_CMD_WRITE;
+       cmd[1] = reg;
+       cmd[2] = val;
+       cmd_len = 3;
+       flags |= SPI_XFER_END;
+
+       ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+       if (ret) {
+               debug("Failed to send command (%zu bytes): %d\n",
+                               cmd_len, ret);
+               return -EINVAL;
+       }
+
+       udelay(1000);
+       ret = enbw_cmc_switch_read(spi, reg, &cmd[0]);
+       if (ret) {
+               debug("Failed to read\n");
+               return -EINVAL;
+       }
+       if (val != cmd[0])
+               debug("warning: reg: %lx va: %x soll: %lx\n",
+                       reg, cmd[0], val);
+
+       return 0;
+}
+
+static int enbw_cmc_eof(unsigned char *ptr)
+{
+       if (*ptr == 0xff)
+               return 1;
+
+       return 0;
+}
+
+static char *enbw_cmc_getnewline(char *ptr)
+{
+       while (*ptr != 0x0a) {
+               ptr++;
+               if (enbw_cmc_eof((unsigned char *)ptr))
+                       return NULL;
+       }
+
+       ptr++;
+       return ptr;
+}
+
+static char *enbw_cmc_getvalue(char *ptr, int *value)
+{
+       int     end = 0;
+
+       *value = -EINVAL;
+
+       if (!isxdigit(*ptr))
+               end = 1;
+
+       while (end) {
+               if ((*ptr == '#') || (*ptr == ';')) {
+                       ptr = enbw_cmc_getnewline(ptr);
+                       return ptr;
+               }
+               if (ptr != NULL) {
+                       if (isxdigit(*ptr)) {
+                               end = 0;
+                       } else if (*ptr == 0x0a) {
+                               ptr++;
+                               return ptr;
+                       } else {
+                               ptr++;
+                               if (enbw_cmc_eof((unsigned char *)ptr))
+                                       return NULL;
+                       }
+               } else {
+                       return NULL;
+               }
+       }
+       *value = (int)simple_strtoul((const char *)ptr, &ptr, 16);
+       ptr++;
+       return ptr;
+}
+
+static struct spi_slave *enbw_cmc_init_spi(void)
+{
+       struct spi_slave *spi;
+       int ret;
+
+       spi = spi_setup_slave(0, 0, 1000000, 0);
+       if (!spi) {
+               printf("Failed to set up slave\n");
+               return NULL;
+       }
+
+       ret = spi_claim_bus(spi);
+       if (ret) {
+               debug("Failed to claim SPI bus: %d\n", ret);
+               goto err_claim_bus;
+       }
+
+       ret = enbw_cmc_switch_read_ident(spi);
+       if (ret)
+               goto err_read;
+
+       return spi;
+err_read:
+       spi_release_bus(spi);
+err_claim_bus:
+       spi_free_slave(spi);
+       return NULL;
+}
+
+static int enbw_cmc_config_switch(unsigned long addr)
+{
+       struct spi_slave *spi;
+       char *ptr = (char *)addr;
+       int value, reg;
+       int ret = 0;
+
+       debug("configure switch with file on addr: 0x%lx\n", addr);
+
+       spi = enbw_cmc_init_spi();
+       if (!spi)
+               return -EINVAL;
+
+       while (ptr != NULL) {
+               ptr = enbw_cmc_getvalue(ptr, &reg);
+               if (ptr != NULL) {
+                       ptr = enbw_cmc_getvalue(ptr, &value);
+                       if ((ptr != NULL) && (value >= 0))
+                               if (enbw_cmc_switch_write(spi, reg, value)) {
+                                       /* error writing to switch */
+                                       ptr = NULL;
+                                       ret = -EINVAL;
+                               }
+               }
+       }
+
+       spi_release_bus(spi);
+       spi_free_slave(spi);
+       return ret;
+}
+
+static int do_switch(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       unsigned long addr;
+
+       if (argc < 2)
+               return cmd_usage(cmdtp);
+
+       addr = simple_strtoul(argv[1], NULL, 16);
+       enbw_cmc_config_switch(addr);
+
+       return 0;
+}
+
+U_BOOT_CMD(switch, 3, 1, do_switch,
+       "switch addr",
+       "[addr]"
+);
+
 /*
  * Initializes on-board ethernet controllers.
  */
 int board_eth_init(bd_t *bis)
 {
-#ifdef CONFIG_DRIVER_TI_EMAC
+       struct spi_slave *spi;
+       const char *s;
+       size_t len = 0;
+       int config = 1;
+
        davinci_emac_mii_mode_sel(0);
-#endif /* CONFIG_DRIVER_TI_EMAC */
 
+       /* send a config file to the switch */
+       s = hwconfig_subarg("switch", "config", &len);
+       if (len) {
+               unsigned long addr = simple_strtoul(s, NULL, 16);
+
+               config = enbw_cmc_config_switch(addr);
+       }
+
+       if (config) {
+               /*
+                * no valid config file -> do we have some args in
+                * hwconfig ?
+                */
+               if ((hwconfig_subarg("switch", "lan", &len)) ||
+                   (hwconfig_subarg("switch", "lmn", &len))) {
+                       /* If so start switch */
+                       spi = enbw_cmc_init_spi();
+                       if (spi) {
+                               if (enbw_cmc_switch_write(spi, 1, 0))
+                                       config = 0;
+                               udelay(10000);
+                               if (enbw_cmc_switch_write(spi, 1, 1))
+                                       config = 0;
+                               spi_release_bus(spi);
+                               spi_free_slave(spi);
+                       }
+               } else {
+                       config = 0;
+               }
+       }
        if (!davinci_emac_initialize()) {
                printf("Error: Ethernet init failed!\n");
                return -1;
        }
 
-       if (hwconfig_subarg_cmp("switch", "lan", "on"))
-               /* Switch port lan on */
-               enbw_cmc_switch(1, 1);
-       else
-               enbw_cmc_switch(1, 0);
+       if (config) {
+               if (hwconfig_subarg_cmp("switch", "lan", "on"))
+                       /* Switch port lan on */
+                       enbw_cmc_switch(1, 1);
+               else
+                       enbw_cmc_switch(1, 0);
 
-       if (hwconfig_subarg_cmp("switch", "pwl", "on"))
-               /* Switch port pwl on */
-               enbw_cmc_switch(2, 1);
-       else
-               enbw_cmc_switch(2, 0);
+               if (hwconfig_subarg_cmp("switch", "lmn", "on"))
+                       /* Switch port pwl on */
+                       enbw_cmc_switch(2, 1);
+               else
+                       enbw_cmc_switch(2, 0);
+       }
 
        return 0;
 }
@@ -517,34 +803,28 @@ void arch_memory_failure_handle(void)
 }
 #endif
 
-#if defined(CONFIG_BOOTCOUNT_LIMIT)
-void bootcount_store(ulong a)
+ulong post_word_load(void)
 {
        struct davinci_rtc *reg =
-               (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR;
+               (struct davinci_rtc *)CONFIG_SYS_POST_WORD_ADDR;
+
+       return in_be32(&reg->scratch2);
+}
+
+void post_word_store(ulong value)
+{
+       struct davinci_rtc *reg =
+               (struct davinci_rtc *)CONFIG_SYS_POST_WORD_ADDR;
 
        /*
         * write RTC kick register to enable write
-        * for RTC Scratch registers. Scratch0 and 1 are
+        * for RTC Scratch registers. Cratch0 and 1 are
         * used for bootcount values.
         */
        writel(RTC_KICK0R_WE, &reg->kick0r);
        writel(RTC_KICK1R_WE, &reg->kick1r);
-       out_be32(&reg->scratch0, a);
-       out_be32(&reg->scratch1, BOOTCOUNT_MAGIC);
-}
-
-ulong bootcount_load(void)
-{
-       struct davinci_rtc *reg =
-               (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR;
-
-       if (in_be32(&reg->scratch1) != BOOTCOUNT_MAGIC)
-               return 0;
-       else
-               return in_be32(&reg->scratch0);
+       out_be32(&reg->scratch2, value);
 }
-#endif
 
 void board_gpio_init(void)
 {
@@ -558,6 +838,19 @@ void board_gpio_init(void)
        clrbits_le32(&gpio->out_data, 0x8000407e);
        /* set LED 1 - 5 to state on */
        setbits_le32(&gpio->out_data, 0x8000001e);
+
+       /*
+        * set some gpio pins to low, this is needed early,
+        * so we have no gpio Interface here
+        * gpios:
+        * 8[8]  Mode PV select  low
+        * 8[9]  Debug Rx Enable low
+        * 8[10] Mode Select PV  low
+        * 8[11] Counter Interface RS485 Rx-Enable low
+        */
+       gpio = davinci_gpio_bank8;
+       clrbits_le32(&gpio->dir, 0x00000f00);
+       clrbits_le32(&gpio->out_data, 0x0f00);
 }
 
 int board_late_init(void)