SPDX: Convert all of our single license tags to Linux Kernel style
[platform/kernel/u-boot.git] / board / ti / common / board_detect.c
index 6cf4859..c475f10 100644 (file)
@@ -1,19 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Library to support early TI EVM EEPROM handling
  *
  * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
  *     Lokesh Vutla
  *     Steve Kipisz
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <asm/omap_common.h>
+#include <dm/uclass.h>
 #include <i2c.h>
 
 #include "board_detect.h"
 
+#if defined(CONFIG_DM_I2C_COMPAT)
+/**
+ * ti_i2c_set_alen - Set chip's i2c address length
+ * @bus_addr - I2C bus number
+ * @dev_addr - I2C eeprom id
+ * @alen     - I2C address length in bytes
+ *
+ * DM_I2C by default sets the address length to be used to 1. This
+ * function allows this address length to be changed to match the
+ * eeprom used for board detection.
+ */
+int __maybe_unused ti_i2c_set_alen(int bus_addr, int dev_addr, int alen)
+{
+       struct udevice *dev;
+       struct udevice *bus;
+       int rc;
+
+       rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
+       if (rc)
+               return rc;
+       rc = i2c_get_chip(bus, dev_addr, 1, &dev);
+       if (rc)
+               return rc;
+       rc = i2c_set_chip_offset_len(dev, alen);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+#else
+int __maybe_unused ti_i2c_set_alen(int bus_addr, int dev_addr, int alen)
+{
+       return 0;
+}
+#endif
+
 /**
  * ti_i2c_eeprom_init - Initialize an i2c bus and probe for a device
  * @i2c_bus: i2c bus number to initialize
@@ -46,7 +82,17 @@ static int __maybe_unused ti_i2c_eeprom_init(int i2c_bus, int dev_addr)
 static int __maybe_unused ti_i2c_eeprom_read(int dev_addr, int offset,
                                             uchar *ep, int epsize)
 {
-       return i2c_read(dev_addr, offset, 2, ep, epsize);
+       int bus_num, rc, alen;
+
+       bus_num = i2c_get_bus_num();
+
+       alen = 2;
+
+       rc = ti_i2c_set_alen(bus_num, dev_addr, alen);
+       if (rc)
+               return rc;
+
+       return i2c_read(dev_addr, offset, alen, ep, epsize);
 }
 
 /**
@@ -88,6 +134,11 @@ static int __maybe_unused ti_i2c_eeprom_get(int bus_addr, int dev_addr,
         * Read the header first then only read the other contents.
         */
        byte = 2;
+
+       rc = ti_i2c_set_alen(bus_addr, dev_addr, byte);
+       if (rc)
+               return rc;
+
        rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read, 4);
        if (rc)
                return rc;
@@ -100,9 +151,14 @@ static int __maybe_unused ti_i2c_eeprom_get(int bus_addr, int dev_addr,
                 * 1 byte address (some legacy boards need this..)
                 */
                byte = 1;
-               if (rc)
+               if (rc) {
+                       rc = ti_i2c_set_alen(bus_addr, dev_addr, byte);
+                       if (rc)
+                               return rc;
+
                        rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read,
                                      4);
+               }
                if (rc)
                        return rc;
        }
@@ -116,6 +172,30 @@ static int __maybe_unused ti_i2c_eeprom_get(int bus_addr, int dev_addr,
        return 0;
 }
 
+int __maybe_unused ti_i2c_eeprom_am_set(const char *name, const char *rev)
+{
+       struct ti_common_eeprom *ep;
+
+       if (!name || !rev)
+               return -1;
+
+       ep = TI_EEPROM_DATA;
+       if (ep->header == TI_EEPROM_HEADER_MAGIC)
+               goto already_set;
+
+       /* Set to 0 all fields */
+       memset(ep, 0, sizeof(*ep));
+       strncpy(ep->name, name, TI_EEPROM_HDR_NAME_LEN);
+       strncpy(ep->version, rev, TI_EEPROM_HDR_REV_LEN);
+       /* Some dummy serial number to identify the platform */
+       strncpy(ep->serial, "0000", TI_EEPROM_HDR_SERIAL_LEN);
+       /* Mark it with a valid header */
+       ep->header = TI_EEPROM_HEADER_MAGIC;
+
+already_set:
+       return 0;
+}
+
 int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
 {
        int rc;
@@ -123,14 +203,17 @@ int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
        struct ti_common_eeprom *ep;
 
        ep = TI_EEPROM_DATA;
+#ifndef CONFIG_SPL_BUILD
        if (ep->header == TI_EEPROM_HEADER_MAGIC)
-               goto already_read;
+               return 0; /* EEPROM has already been read */
+#endif
 
        /* Initialize with a known bad marker for i2c fails.. */
        ep->header = TI_DEAD_EEPROM_MAGIC;
        ep->name[0] = 0x0;
        ep->version[0] = 0x0;
        ep->serial[0] = 0x0;
+       ep->config[0] = 0x0;
 
        rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
                               sizeof(am_ep), (uint8_t *)&am_ep);
@@ -156,7 +239,52 @@ int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
        memcpy(ep->mac_addr, am_ep.mac_addr,
               TI_EEPROM_HDR_NO_OF_MAC_ADDR * TI_EEPROM_HDR_ETH_ALEN);
 
-already_read:
+       return 0;
+}
+
+int __maybe_unused ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr)
+{
+       int rc, offset = 0;
+       struct dra7_eeprom dra7_ep;
+       struct ti_common_eeprom *ep;
+
+       ep = TI_EEPROM_DATA;
+#ifndef CONFIG_SPL_BUILD
+       if (ep->header == DRA7_EEPROM_HEADER_MAGIC)
+               return 0; /* EEPROM has already been read */
+#endif
+
+       /* Initialize with a known bad marker for i2c fails.. */
+       ep->header = TI_DEAD_EEPROM_MAGIC;
+       ep->name[0] = 0x0;
+       ep->version[0] = 0x0;
+       ep->serial[0] = 0x0;
+       ep->config[0] = 0x0;
+       ep->emif1_size = 0;
+       ep->emif2_size = 0;
+
+       rc = ti_i2c_eeprom_get(bus_addr, dev_addr, DRA7_EEPROM_HEADER_MAGIC,
+                              sizeof(dra7_ep), (uint8_t *)&dra7_ep);
+       if (rc)
+               return rc;
+
+       ep->header = dra7_ep.header;
+       strlcpy(ep->name, dra7_ep.name, TI_EEPROM_HDR_NAME_LEN + 1);
+       ti_eeprom_string_cleanup(ep->name);
+
+       offset = dra7_ep.version_major - 1;
+
+       /* Rev F is skipped */
+       if (offset >= 5)
+               offset = offset + 1;
+       snprintf(ep->version, TI_EEPROM_HDR_REV_LEN + 1, "%c.%d",
+                'A' + offset, dra7_ep.version_minor);
+       ti_eeprom_string_cleanup(ep->version);
+       ep->emif1_size = (u64)dra7_ep.emif1_size;
+       ep->emif2_size = (u64)dra7_ep.emif2_size;
+       strlcpy(ep->config, dra7_ep.config, TI_EEPROM_HDR_CONFIG_LEN + 1);
+       ti_eeprom_string_cleanup(ep->config);
+
        return 0;
 }
 
@@ -185,9 +313,7 @@ char * __maybe_unused board_ti_get_rev(void)
 {
        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 
-       if (ep->header == TI_DEAD_EEPROM_MAGIC)
-               return NULL;
-
+       /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
        return ep->version;
 }
 
@@ -195,9 +321,7 @@ char * __maybe_unused board_ti_get_config(void)
 {
        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 
-       if (ep->header == TI_DEAD_EEPROM_MAGIC)
-               return NULL;
-
+       /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
        return ep->config;
 }
 
@@ -205,9 +329,7 @@ char * __maybe_unused board_ti_get_name(void)
 {
        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 
-       if (ep->header == TI_DEAD_EEPROM_MAGIC)
-               return NULL;
-
+       /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
        return ep->name;
 }
 
@@ -230,25 +352,117 @@ fail:
        memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
 }
 
+u64 __maybe_unused board_ti_get_emif1_size(void)
+{
+       struct ti_common_eeprom *ep = TI_EEPROM_DATA;
+
+       if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
+               return 0;
+
+       return ep->emif1_size;
+}
+
+u64 __maybe_unused board_ti_get_emif2_size(void)
+{
+       struct ti_common_eeprom *ep = TI_EEPROM_DATA;
+
+       if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
+               return 0;
+
+       return ep->emif2_size;
+}
+
 void __maybe_unused set_board_info_env(char *name)
 {
        char *unknown = "unknown";
        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 
        if (name)
-               setenv("board_name", name);
+               env_set("board_name", name);
        else if (ep->name)
-               setenv("board_name", ep->name);
+               env_set("board_name", ep->name);
        else
-               setenv("board_name", unknown);
+               env_set("board_name", unknown);
 
        if (ep->version)
-               setenv("board_rev", ep->version);
+               env_set("board_rev", ep->version);
        else
-               setenv("board_rev", unknown);
+               env_set("board_rev", unknown);
 
        if (ep->serial)
-               setenv("board_serial", ep->serial);
+               env_set("board_serial", ep->serial);
        else
-               setenv("board_serial", unknown);
+               env_set("board_serial", unknown);
+}
+
+static u64 mac_to_u64(u8 mac[6])
+{
+       int i;
+       u64 addr = 0;
+
+       for (i = 0; i < 6; i++) {
+               addr <<= 8;
+               addr |= mac[i];
+       }
+
+       return addr;
+}
+
+static void u64_to_mac(u64 addr, u8 mac[6])
+{
+       mac[5] = addr;
+       mac[4] = addr >> 8;
+       mac[3] = addr >> 16;
+       mac[2] = addr >> 24;
+       mac[1] = addr >> 32;
+       mac[0] = addr >> 40;
+}
+
+void board_ti_set_ethaddr(int index)
+{
+       uint8_t mac_addr[6];
+       int i;
+       u64 mac1, mac2;
+       u8 mac_addr1[6], mac_addr2[6];
+       int num_macs;
+       /*
+        * Export any Ethernet MAC addresses from EEPROM.
+        * The 2 MAC addresses in EEPROM define the address range.
+        */
+       board_ti_get_eth_mac_addr(0, mac_addr1);
+       board_ti_get_eth_mac_addr(1, mac_addr2);
+
+       if (is_valid_ethaddr(mac_addr1) && is_valid_ethaddr(mac_addr2)) {
+               mac1 = mac_to_u64(mac_addr1);
+               mac2 = mac_to_u64(mac_addr2);
+
+               /* must contain an address range */
+               num_macs = mac2 - mac1 + 1;
+               if (num_macs <= 0)
+                       return;
+
+               if (num_macs > 50) {
+                       printf("%s: Too many MAC addresses: %d. Limiting to 50\n",
+                              __func__, num_macs);
+                       num_macs = 50;
+               }
+
+               for (i = 0; i < num_macs; i++) {
+                       u64_to_mac(mac1 + i, mac_addr);
+                       if (is_valid_ethaddr(mac_addr)) {
+                               eth_env_set_enetaddr_by_index("eth", i + index,
+                                                             mac_addr);
+                       }
+               }
+       }
+}
+
+bool __maybe_unused board_ti_was_eeprom_read(void)
+{
+       struct ti_common_eeprom *ep = TI_EEPROM_DATA;
+
+       if (ep->header == TI_EEPROM_HEADER_MAGIC)
+               return true;
+       else
+               return false;
 }