board/km: add support for seli8 design based on nxp ls102x
[platform/kernel/u-boot.git] / board / keymile / common / ivm.c
index f0e91bb..14c70b9 100644 (file)
@@ -1,15 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2011
  * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
-#include <hush.h>
+#include <cli_hush.h>
+#include <env.h>
 #include <i2c.h>
 #include "common.h"
 
+#define MAC_STR_SZ     20
+
 static int ivm_calc_crc(unsigned char *buf, int len)
 {
        const unsigned short crc_tab[16] = {
@@ -44,28 +46,27 @@ static int ivm_set_value(char *name, char *value)
 {
        char tempbuf[256];
 
-       if (value != NULL) {
+       if (value) {
                sprintf(tempbuf, "%s=%s", name, value);
                return set_local_var(tempbuf, 0);
-       } else {
-               unset_local_var(name);
        }
+       unset_local_var(name);
        return 0;
 }
 
 static int ivm_get_value(unsigned char *buf, int len, char *name, int off,
-                               int check)
+                        int check)
 {
        unsigned short  val;
        unsigned char   valbuf[30];
 
-       if ((buf[off + 0] != buf[off + 2]) &&
-           (buf[off + 2] != buf[off + 4])) {
+       if (buf[off + 0] != buf[off + 2] &&
+           buf[off + 2] != buf[off + 4]) {
                printf("%s Error corrupted %s\n", __func__, name);
                val = -1;
        } else {
                val = buf[off + 0] + (buf[off + 1] << 8);
-               if ((val == 0) && (check == 1))
+               if (val == 0 && check == 1)
                        val = -1;
        }
        sprintf((char *)valbuf, "%x", val);
@@ -96,9 +97,9 @@ static char convert_char(char c)
 }
 
 static int ivm_findinventorystring(int type,
-                                       unsigned char *const string,
-                                       unsigned long maxlen,
-                                       unsigned char *buf)
+                                  unsigned char *const string,
+                                  unsigned long maxlen,
+                                  unsigned char *buf)
 {
        int xcode = 0;
        unsigned long cr = 0;
@@ -120,7 +121,7 @@ static int ivm_findinventorystring(int type,
 
        /* Look for the requested number of CR. */
        while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
-               if ((buf[addr] == '\r'))
+               if (buf[addr] == '\r')
                        cr++;
                addr++;
        }
@@ -131,12 +132,12 @@ static int ivm_findinventorystring(int type,
         */
        if (addr < INVENTORYDATASIZE) {
                /* Copy the IVM string in the corresponding string */
-               for (; (buf[addr] != '\r')                      &&
-                       ((buf[addr] != ';') ||  (!stop))        &&
-                       (size < (maxlen - 1)                    &&
-                       (addr < INVENTORYDATASIZE)); addr++) {
+               for (; (buf[addr] != '\r')              &&
+                    ((buf[addr] != ';') ||  (!stop))   &&
+                    (size < (maxlen - 1)               &&
+                    (addr < INVENTORYDATASIZE)); addr++) {
                        size += sprintf((char *)string + size, "%c",
-                                               convert_char (buf[addr]));
+                                       convert_char (buf[addr]));
                }
 
                /*
@@ -174,56 +175,55 @@ static int ivm_check_crc(unsigned char *buf, int block)
        unsigned long   crceeprom;
 
        crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
-       crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
+       crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] +
                        buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
        if (crc != crceeprom) {
                if (block == 0)
-                       printf("Error CRC Block: %d EEprom: calculated: \
-                       %lx EEprom: %lx\n", block, crc, crceeprom);
+                       printf("Error CRC Block: %d EEprom: calculated: %lx EEprom: %lx\n",
+                              block, crc, crceeprom);
                return -1;
        }
        return 0;
 }
 
-static int calculate_mac_offset(unsigned char *valbuf, unsigned char *buf,
-                               int offset)
+/* take care of the possible MAC address offset and the IVM content offset */
+static int process_mac(unsigned char *valbuf, unsigned char *buf,
+                      int offset, bool unique)
 {
+       unsigned char mac[6];
        unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6];
 
-       if (offset == 0)
-               return 0;
+       /* use an intermediate buffer, to not change IVM content
+        * MAC address is at offset 1
+        */
+       memcpy(mac, buf + 1, 6);
 
-       val += offset;
-       buf[4] = (val >> 16) & 0xff;
-       buf[5] = (val >> 8) & 0xff;
-       buf[6] = val & 0xff;
-       sprintf((char *)valbuf, "%pM", buf + 1);
+       /* MAC address can be set to locally administred, this is only allowed
+        * for interfaces which have now connection to the outside. For these
+        * addresses we need to set the second bit in the first byte.
+        */
+       if (!unique)
+               mac[0] |= 0x2;
+
+       if (offset) {
+               val += offset;
+               mac[3] = (val >> 16) & 0xff;
+               mac[4] = (val >> 8) & 0xff;
+               mac[5] = val & 0xff;
+       }
+
+       sprintf((char *)valbuf, "%pM", mac);
        return 0;
 }
 
 static int ivm_analyze_block2(unsigned char *buf, int len)
 {
-       unsigned char   valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
+       unsigned char   valbuf[MAC_STR_SZ];
        unsigned long   count;
 
-       /* IVM_MAC Adress begins at offset 1 */
+       /* IVM_MAC Address begins at offset 1 */
        sprintf((char *)valbuf, "%pM", buf + 1);
        ivm_set_value("IVM_MacAddress", (char *)valbuf);
-       /* if an offset is defined, add it */
-       calculate_mac_offset(buf, valbuf, CONFIG_PIGGY_MAC_ADRESS_OFFSET);
-#ifdef MACH_TYPE_KM_KIRKWOOD
-       setenv((char *)"ethaddr", (char *)valbuf);
-#else
-       if (getenv("ethaddr") == NULL)
-               setenv((char *)"ethaddr", (char *)valbuf);
-#endif
-#ifdef CONFIG_KMVECT1
-/* KMVECT1 has two ethernet interfaces */
-       if (getenv("eth1addr") == NULL) {
-               calculate_mac_offset(buf, valbuf, 1);
-               setenv((char *)"eth1addr", (char *)valbuf);
-       }
-#endif
        /* IVM_MacCount */
        count = (buf[10] << 24) +
                   (buf[11] << 16) +
@@ -236,7 +236,7 @@ static int ivm_analyze_block2(unsigned char *buf, int len)
        return 0;
 }
 
-static int ivm_analyze_eeprom(unsigned char *buf, int len)
+int ivm_analyze_eeprom(unsigned char *buf, int len)
 {
        unsigned short  val;
        unsigned char   valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
@@ -246,9 +246,9 @@ static int ivm_analyze_eeprom(unsigned char *buf, int len)
                return -1;
 
        ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
-                       "IVM_BoardId", 0, 1);
+                     "IVM_BoardId", 0, 1);
        val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
-                       "IVM_HWKey", 6, 1);
+                           "IVM_HWKey", 6, 1);
        if (val != 0xffff) {
                sprintf((char *)valbuf, "%x", ((val / 100) % 10));
                ivm_set_value("IVM_HWVariant", (char *)valbuf);
@@ -256,11 +256,11 @@ static int ivm_analyze_eeprom(unsigned char *buf, int len)
                ivm_set_value("IVM_HWVersion", (char *)valbuf);
        }
        ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
-               "IVM_Functions", 12, 0);
+                     "IVM_Functions", 12, 0);
 
        GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
        GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
-       tmp = (unsigned char *) getenv("IVM_DeviceName");
+       tmp = (unsigned char *)env_get("IVM_DeviceName");
        if (tmp) {
                int     len = strlen((char *)tmp);
                int     i = 0;
@@ -268,7 +268,7 @@ static int ivm_analyze_eeprom(unsigned char *buf, int len)
                while (i < len) {
                        if (tmp[i] == ';') {
                                ivm_set_value("IVM_ShortText",
-                                       (char *)&tmp[i + 1]);
+                                             (char *)&tmp[i + 1]);
                                break;
                        }
                        i++;
@@ -291,26 +291,84 @@ static int ivm_analyze_eeprom(unsigned char *buf, int len)
        if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
                return 0;
        ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2],
-               CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
+                          CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
+
+       return 0;
+}
+
+static int ivm_populate_env(unsigned char *buf, int len, int mac_address_offset)
+{
+       unsigned char   *page2;
+       unsigned char   valbuf[MAC_STR_SZ];
+
+       /* do we have the page 2 filled ? if not return */
+       if (ivm_check_crc(buf, 2))
+               return 0;
+       page2 = &buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2];
+
+       if (IS_ENABLED(CONFIG_KMTEGR1)) {
+               /* KMTEGR1 has a special setup. eth0 has no connection to the
+                * outside and gets an locally administred MAC address, eth1 is
+                * the debug interface and gets the official MAC address from
+                * the IVM
+                */
+               process_mac(valbuf, page2, mac_address_offset, false);
+               env_set((char *)"ethaddr", (char *)valbuf);
+               process_mac(valbuf, page2, mac_address_offset, true);
+               env_set((char *)"eth1addr", (char *)valbuf);
+       } else if (IS_ENABLED(CONFIG_ARCH_LS1021A)) {
+               /* LS102xA has 1xRGMII for debug connection and
+                * 2xSGMII for back-plane mgmt connection
+                */
+               process_mac(valbuf, page2, 1, true);
+               env_set((char *)"ethaddr", (char *)valbuf);
+               process_mac(valbuf, page2, 2, true);
+               env_set((char *)"eth1addr", (char *)valbuf);
+               process_mac(valbuf, page2, mac_address_offset, true);
+               env_set((char *)"eth2addr", (char *)valbuf);
+       } else {
+               process_mac(valbuf, page2, mac_address_offset, true);
+               env_set((char *)"ethaddr", (char *)valbuf);
+       }
+       if (IS_ENABLED(CONFIG_TARGET_KMCENT2)) {
+               /* 3rd ethernet interface */
+               process_mac(valbuf, page2, 2, true);
+               env_set((char *)"eth4addr", (char *)valbuf);
+       }
 
        return 0;
 }
 
-int ivm_read_eeprom(void)
+int ivm_read_eeprom(unsigned char *buf, int len, int mac_address_offset)
 {
-       uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
        int ret;
+#if CONFIG_IS_ENABLED(DM_I2C)
+       struct udevice *eedev = NULL;
+
+       ret = i2c_get_chip_for_busnum(CONFIG_KM_IVM_BUS,
+                                     CONFIG_SYS_I2C_EEPROM_ADDR, 1, &eedev);
+       if (ret) {
+               printf("failed to get device for EEPROM at address 0x%02x\n",
+                      CONFIG_SYS_I2C_EEPROM_ADDR);
+               return 1;
+       }
 
+       ret = dm_i2c_read(eedev, 0, buf, len);
+       if (ret != 0) {
+               printf("Error: Unable to read from I2C EEPROM at address %02X:%02X\n",
+                      CONFIG_SYS_I2C_EEPROM_ADDR, 0);
+               return 1;
+       }
+#else
        i2c_set_bus_num(CONFIG_KM_IVM_BUS);
        /* add deblocking here */
        i2c_make_abort();
 
-       ret = i2c_read(CONFIG_SYS_IVM_EEPROM_ADR, 0, 1, i2c_buffer,
-               CONFIG_SYS_IVM_EEPROM_MAX_LEN);
+       ret = i2c_read(CONFIG_SYS_IVM_EEPROM_ADR, 0, 1, buf, len);
        if (ret != 0) {
                printf("Error reading EEprom\n");
                return -2;
        }
-
-       return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
+#endif
+       return ivm_populate_env(buf, len, mac_address_offset);
 }