Support the Expansion cards via Extension framework.
This should make 'expansion' command work to scan
for expansion cards and apply DT overlays.

Card detection code is moved to a library so
other boards can benefit from it.

Signed-off-by: Roger Quadros <[email protected]>
---
 board/ti/am65x/evm.c               | 264 ++++++++---------------------
 board/ti/common/Kconfig            |   8 +
 board/ti/common/Makefile           |   1 +
 board/ti/common/ti_card_detect.c   | 155 +++++++++++++++++
 board/ti/common/ti_card_detect.h   |  43 +++++
 configs/am65x_evm_a53_defconfig    |   2 +
 configs/am65x_hs_evm_a53_defconfig |   2 +
 7 files changed, 280 insertions(+), 195 deletions(-)
 create mode 100644 board/ti/common/ti_card_detect.c
 create mode 100644 board/ti/common/ti_card_detect.h

diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c
index 706b219818..5bb187a062 100644
--- a/board/ti/am65x/evm.c
+++ b/board/ti/am65x/evm.c
@@ -22,21 +22,10 @@
 #include <spl.h>
 
 #include "../common/board_detect.h"
+#include "../common/ti_card_detect.h"
 
 #define board_is_am65x_base_board()    board_ti_is("AM6-COMPROCEVM")
 
-/* Daughter card presence detection signals */
-enum {
-       AM65X_EVM_APP_BRD_DET,
-       AM65X_EVM_LCD_BRD_DET,
-       AM65X_EVM_SERDES_BRD_DET,
-       AM65X_EVM_HDMI_GPMC_BRD_DET,
-       AM65X_EVM_BRD_DET_COUNT,
-};
-
-/* Max number of MAC addresses that are parsed/processed per daughter card */
-#define DAUGHTER_CARD_NO_OF_MAC_ADDR   8
-
 /* Regiter that controls the SERDES0 lane and clock assignment */
 #define CTRLMMR_SERDES0_CTRL    0x00104080
 #define PCIE_LANE0              0x1
@@ -99,6 +88,74 @@ int board_fit_config_name_match(const char *name)
 }
 #endif
 
+/* Expansion card Slot IDs */
+enum {
+       AM65X_EVM_APP_BRD_DET,
+       AM65X_EVM_LCD_BRD_DET,
+       AM65X_EVM_SERDES_BRD_DET,
+       AM65X_EVM_HDMI_GPMC_BRD_DET,
+       AM65X_EVM_BRD_DET_COUNT,
+};
+
+/* Expansion card slots */
+static const struct ti_card_slot_map am65x_slot_map[] = {
+       { "gpio@38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
+       { "gpio@38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
+       { "gpio@38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
+       { "gpio@38_3", 0x53, }, /* AM65X_EVM_HDMI_GPMC_BRD_DET */
+};
+
+/* Supported Expansion cards */
+static const struct ti_card_info am65x_card_info[] = {
+       {
+               AM65X_EVM_APP_BRD_DET,
+               "AM6-GPAPPEVM",
+               "k3-am654-gp.dtbo",
+               0,
+               TI_CARD_OWNER,
+               TI_CARD_VERSION_1,
+       },
+       {
+               AM65X_EVM_APP_BRD_DET,
+               "AM6-IDKAPPEVM",
+               "k3-am654-idk.dtbo",
+               3,
+               TI_CARD_OWNER,
+               TI_CARD_VERSION_1,
+       },
+       {
+               AM65X_EVM_SERDES_BRD_DET,
+               "SER-PCIE2LEVM",
+               "k3-am654-pcie-usb2.dtbo",
+               0,
+               TI_CARD_OWNER,
+               TI_CARD_VERSION_1,
+       },
+       {
+               AM65X_EVM_SERDES_BRD_DET,
+               "SER-PCIEUSBEVM",
+               "k3-am654-pcie-usb3.dtbo",
+               0,
+               TI_CARD_OWNER,
+               TI_CARD_VERSION_1,
+       },
+       {
+               AM65X_EVM_LCD_BRD_DET,
+               "OLDI-LCD1EVM",
+               "k3-am654-evm-oldi-lcd1evm.dtbo",
+               0,
+               TI_CARD_OWNER,
+               TI_CARD_VERSION_1,
+       },
+};
+
+int extension_board_scan(struct list_head *extension_list)
+{
+       return ti_card_detect(am65x_slot_map, ARRAY_SIZE(am65x_slot_map),
+                             am65x_card_info, ARRAY_SIZE(am65x_card_info),
+                             extension_list);
+}
+
 #ifdef CONFIG_TI_I2C_BOARD_DETECT
 int do_board_detect(void)
 {
@@ -143,187 +200,7 @@ invalid_eeprom:
        set_board_info_env_am6(name);
 }
 
-static int init_daughtercard_det_gpio(char *gpio_name, struct gpio_desc *desc)
-{
-       int ret;
-
-       memset(desc, 0, sizeof(*desc));
-
-       ret = dm_gpio_lookup_name(gpio_name, desc);
-       if (ret < 0)
-               return ret;
-
-       /* Request GPIO, simply re-using the name as label */
-       ret = dm_gpio_request(desc, gpio_name);
-       if (ret < 0)
-               return ret;
 
-       return dm_gpio_set_dir_flags(desc, GPIOD_IS_IN);
-}
-
-static int probe_daughtercards(void)
-{
-       struct ti_am6_eeprom ep;
-       struct gpio_desc board_det_gpios[AM65X_EVM_BRD_DET_COUNT];
-       char mac_addr[DAUGHTER_CARD_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
-       u8 mac_addr_cnt;
-       char name_overlays[1024] = { 0 };
-       int i, j;
-       int ret;
-
-       /*
-        * Daughter card presence detection signal name to GPIO (via I2C I/O
-        * expander @ address 0x38) name and EEPROM I2C address mapping.
-        */
-       const struct {
-               char *gpio_name;
-               u8 i2c_addr;
-       } slot_map[AM65X_EVM_BRD_DET_COUNT] = {
-               { "gpio@38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
-               { "gpio@38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
-               { "gpio@38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
-               { "gpio@38_3", 0x53, }, /* AM65X_EVM_HDMI_GPMC_BRD_DET */
-       };
-
-       /* Declaration of daughtercards to probe */
-       const struct {
-               u8 slot_index;          /* Slot the card is installed */
-               char *card_name;        /* EEPROM-programmed card name */
-               char *dtbo_name;        /* Device tree overlay to apply */
-               u8 eth_offset;          /* ethXaddr MAC address index offset */
-       } cards[] = {
-               {
-                       AM65X_EVM_APP_BRD_DET,
-                       "AM6-GPAPPEVM",
-                       "k3-am654-gp.dtbo",
-                       0,
-               },
-               {
-                       AM65X_EVM_APP_BRD_DET,
-                       "AM6-IDKAPPEVM",
-                       "k3-am654-idk.dtbo",
-                       3,
-               },
-               {
-                       AM65X_EVM_SERDES_BRD_DET,
-                       "SER-PCIE2LEVM",
-                       "k3-am654-pcie-usb2.dtbo",
-                       0,
-               },
-               {
-                       AM65X_EVM_SERDES_BRD_DET,
-                       "SER-PCIEUSBEVM",
-                       "k3-am654-pcie-usb3.dtbo",
-                       0,
-               },
-               {
-                       AM65X_EVM_LCD_BRD_DET,
-                       "OLDI-LCD1EVM",
-                       "k3-am654-evm-oldi-lcd1evm.dtbo",
-                       0,
-               },
-       };
-
-       /*
-        * Initialize GPIO used for daughtercard slot presence detection and
-        * keep the resulting handles in local array for easier access.
-        */
-       for (i = 0; i < AM65X_EVM_BRD_DET_COUNT; i++) {
-               ret = init_daughtercard_det_gpio(slot_map[i].gpio_name,
-                                                &board_det_gpios[i]);
-               if (ret < 0)
-                       return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(cards); i++) {
-               /* Obtain card-specific slot index and associated I2C address */
-               u8 slot_index = cards[i].slot_index;
-               u8 i2c_addr = slot_map[slot_index].i2c_addr;
-
-               /*
-                * The presence detection signal is active-low, hence skip
-                * over this card slot if anything other than 0 is returned.
-                */
-               ret = dm_gpio_get_value(&board_det_gpios[slot_index]);
-               if (ret < 0)
-                       return ret;
-               else if (ret)
-                       continue;
-
-               /* Get and parse the daughter card EEPROM record */
-               ret = ti_i2c_eeprom_am6_get(CONFIG_EEPROM_BUS_ADDRESS, i2c_addr,
-                                           &ep,
-                                           (char **)mac_addr,
-                                           DAUGHTER_CARD_NO_OF_MAC_ADDR,
-                                           &mac_addr_cnt);
-               if (ret) {
-                       pr_err("Reading daughtercard EEPROM at 0x%02x failed 
%d\n",
-                              i2c_addr, ret);
-                       /*
-                        * Even this is pretty serious let's just skip over
-                        * this particular daughtercard, rather than ending
-                        * the probing process altogether.
-                        */
-                       continue;
-               }
-
-               /* Only process the parsed data if we found a match */
-               if (strncmp(ep.name, cards[i].card_name, sizeof(ep.name)))
-                       continue;
-
-               printf("Detected: %s rev %s\n", ep.name, ep.version);
-
-               /*
-                * Populate any MAC addresses from daughtercard into the U-Boot
-                * environment, starting with a card-specific offset so we can
-                * have multiple cards contribute to the MAC pool in a well-
-                * defined manner.
-                */
-               for (j = 0; j < mac_addr_cnt; j++) {
-                       if (!is_valid_ethaddr((u8 *)mac_addr[j]))
-                               continue;
-
-                       eth_env_set_enetaddr_by_index("eth",
-                                                     cards[i].eth_offset + j,
-                                                     (uchar *)mac_addr[j]);
-               }
-
-               /*
-                * It has been observed that setting SERDES0 lane mux to USB 
prevents USB
-                * 2.0 operation on USB0. Setting SERDES0 lane mux to non-USB 
when USB0 is
-                * used in USB 2.0 only mode solves this issue. For USB3.0+2.0 
operation
-                * this issue is not present.
-                *
-                * Implement this workaround by writing 1 to LANE_FUNC_SEL 
field in
-                * CTRLMMR_SERDES0_CTRL register.
-                */
-               if (!strncmp(ep.name, "SER-PCIE2LEVM", sizeof(ep.name)))
-                       writel(PCIE_LANE0, CTRLMMR_SERDES0_CTRL);
-
-               /* Skip if no overlays are to be added */
-               if (!strlen(cards[i].dtbo_name))
-                       continue;
-
-               /*
-                * Make sure we are not running out of buffer space by checking
-                * if we can fit the new overlay, a trailing space to be used
-                * as a separator, plus the terminating zero.
-                */
-               if (strlen(name_overlays) + strlen(cards[i].dtbo_name) + 2 >
-                   sizeof(name_overlays))
-                       return -ENOMEM;
-
-               /* Append to our list of overlays */
-               strcat(name_overlays, cards[i].dtbo_name);
-               strcat(name_overlays, " ");
-       }
-
-       /* Apply device tree overlay(s) to the U-Boot environment, if any */
-       if (strlen(name_overlays))
-               return env_set("name_overlays", name_overlays);
-
-       return 0;
-}
 #endif
 
 int board_late_init(void)
@@ -340,9 +217,6 @@ int board_late_init(void)
                 * an index of 1.
                 */
                board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
-
-               /* Check for and probe any plugged-in daughtercards */
-               probe_daughtercards();
        }
 
        return 0;
diff --git a/board/ti/common/Kconfig b/board/ti/common/Kconfig
index 72ee2d6d0e..039a2722f3 100644
--- a/board/ti/common/Kconfig
+++ b/board/ti/common/Kconfig
@@ -12,6 +12,14 @@ config TI_CAPE_DETECT
           Support Beagle Bone Cape detection for TI platforms
           e.g. AM335x BeagleBone.
 
+config TI_CARD_DETECT
+       bool "Support Expansion Card detection for TI platforms"
+       default y if TARGET_AM654_A53_EVM
+       depends on SUPPORT_EXTENSION_SCAN
+       help
+          Support Expansion Card detection for TI platforms
+          e.g. AM654-EVM
+
 config EEPROM_BUS_ADDRESS
        int "Board EEPROM's I2C bus address"
        range 0 8
diff --git a/board/ti/common/Makefile b/board/ti/common/Makefile
index 5db433f77f..f3922f231b 100644
--- a/board/ti/common/Makefile
+++ b/board/ti/common/Makefile
@@ -3,3 +3,4 @@
 
 obj-${CONFIG_TI_I2C_BOARD_DETECT} += board_detect.o
 obj-${CONFIG_TI_CAPE_DETECT} += cape_detect.o
+obj-${CONFIG_TI_CARD_DETECT} += ti_card_detect.o
diff --git a/board/ti/common/ti_card_detect.c b/board/ti/common/ti_card_detect.c
new file mode 100644
index 0000000000..7efb42cbbe
--- /dev/null
+++ b/board/ti/common/ti_card_detect.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI EVM Extension card handling
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <extension_board.h>
+#include "board_detect.h"
+#include "ti_card_detec.h"
+
+/* Max number of MAC addresses that are parsed/processed per daughter card */
+#define DAUGHTER_CARD_NO_OF_MAC_ADDR    8
+
+static const char *k3_dtbo_list[AM64X_MAX_DAUGHTER_CARDS] = {NULL};
+
+static int init_daughtercard_det_gpio(char *gpio_name, struct gpio_desc *desc)
+{
+       int ret;
+
+       memset(desc, 0, sizeof(*desc));
+
+       ret = dm_gpio_lookup_name(gpio_name, desc);
+       if (ret < 0)
+               return ret;
+
+       /* Request GPIO, simply re-using the name as label */
+       ret = dm_gpio_request(desc, gpio_name);
+       if (ret < 0)
+               return ret;
+
+       return dm_gpio_set_dir_flags(desc, GPIOD_IS_IN);
+}
+
+int ti_card_detect(const struct ti_card_slot_map *slot_map, int num_slots,
+                  const struct ti_card_info *cards, int num_cards,
+                  struct list_head *extension_list)
+{
+       char mac_addr[DAUGHTER_CARD_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
+       struct gpio_desc *board_det_gpios;
+       struct ti_am6_eeprom ep;
+       struct extension *extn;
+       u8 mac_addr_cnt;
+       int found_cards = 0;
+       int i, j;
+       int ret;
+
+       board_det_gpios = calloc(num_slots, sizeof(struct gpio_desc));
+       if (!board_det_gpios)
+               return -ENOMEM;
+
+       /*
+        * Initialize GPIO used for daughtercard slot presence detection and
+        * keep the resulting handles in local array for easier access.
+        */
+       for (i = 0; i < num_slots; i++) {
+               ret = init_daughtercard_det_gpio(slot_map[i].gpio_name,
+                                                &board_det_gpios[i]);
+               if (ret < 0) {
+                       pr_err("Couldn't get Card detect GPIO for slot %d: 
%d\n",
+                              i, ret);
+                       return ret;
+               }
+       }
+
+       for (i = 0; i < num_cards; i++) {
+               extn = calloc(1, sizeof(struct extension));
+               /* freed in cmd/extension_board.c */
+               if (!extn) {
+                       pr_err("%s: Error in memory allocation\n", __func__);
+                       return found_cards;
+               }
+
+               /* Obtain card-specific slot index and associated I2C address */
+               u8 slot_index = cards[i].slot_index;
+               u8 i2c_addr = slot_map[slot_index].i2c_addr;
+
+               /*
+                * The presence detection signal is active-low, hence skip
+                * over this card slot if anything other than 0 is returned.
+                */
+               ret = dm_gpio_get_value(&board_det_gpios[slot_index]);
+               if (ret < 0)
+                       return ret;
+               else if (ret)
+                       continue;
+
+               /* Get and parse the daughter card EEPROM record */
+               ret = ti_i2c_eeprom_am6_get(CONFIG_EEPROM_BUS_ADDRESS, i2c_addr,
+                                           &ep,
+                                           (char **)mac_addr,
+                                           DAUGHTER_CARD_NO_OF_MAC_ADDR,
+                                           &mac_addr_cnt);
+               if (ret) {
+                       pr_err("Reading expansion card EEPROM at 0x%02x failed 
%d\n",
+                              i2c_addr, ret);
+                       /*
+                        * Even this is pretty serious let's just skip over
+                        * this particular daughtercard, rather than ending
+                        * the probing process altogether.
+                        */
+                       continue;
+               }
+
+               /* Only process the parsed data if we found a match */
+               if (strncmp(ep.name, cards[i].card_name, sizeof(ep.name)))
+                       continue;
+
+               printf("Detected: %s rev %s\n", ep.name, ep.version);
+
+               /*
+                * Populate any MAC addresses from daughtercard into the U-Boot
+                * environment, starting with a card-specific offset so we can
+                * have multiple cards contribute to the MAC pool in a well-
+                * defined manner.
+                */
+               for (j = 0; j < mac_addr_cnt; j++) {
+                       if (!is_valid_ethaddr((u8 *)mac_addr[j]))
+                               continue;
+
+                       eth_env_set_enetaddr_by_index("eth",
+                                                     cards[i].eth_offset + j,
+                                                     (uchar *)mac_addr[j]);
+               }
+
+               /*
+                * It has been observed that setting SERDES0 lane mux to USB 
prevents USB
+                * 2.0 operation on USB0. Setting SERDES0 lane mux to non-USB 
when USB0 is
+                * used in USB 2.0 only mode solves this issue. For USB3.0+2.0 
operation
+                * this issue is not present.
+                *
+                * Implement this workaround by writing 1 to LANE_FUNC_SEL 
field in
+                * CTRLMMR_SERDES0_CTRL register.
+                */
+               if (!strncmp(ep.name, "SER-PCIE2LEVM", sizeof(ep.name)))
+                       writel(PCIE_LANE0, CTRLMMR_SERDES0_CTRL);
+
+               /* Skip if no overlays are to be added */
+               if (!strlen(cards[i].dtbo_name))
+                       continue;
+
+               strlcpy(extn->overlay, cards[i].dtbo_name, 
sizeof(extn->overlay));
+               strlcpy(extn->name, cards[i].card_name, sizeof(extn->name));
+               strlcpy(extn->version, cards[i].version, sizeof(extn->version));
+               strlcpy(extn->owner, cards[i].owner, sizeof(extn->owner));
+               list_add_tail(&extn->list, extension_list);
+
+               found_cards++;
+       }
+
+       return found_cards;
+}
diff --git a/board/ti/common/ti_card_detect.h b/board/ti/common/ti_card_detect.h
new file mode 100644
index 0000000000..398376976a
--- /dev/null
+++ b/board/ti/common/ti_card_detect.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * TI EVM Extension card handling
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#define TI_CARD_OWNER          "Texas Instruments Inc."
+#define TI_CARD_VERSION_1      "v1"
+/*
+ * ti_card_slot_map - A board may have 1 or more expansion slots.
+ * This data structure provides information for 1 slot.
+ *
+ * @det_gpio_name: GPIO name for the Expansion Card presense sense
+ * @card_i2c_addr: I2C address of expansion card EEPROM
+ */
+struct ti_card_slot_map {
+       char *det_gpio_name;
+       u8 card_i2c_addr;
+};
+
+/*
+ * ti_card_info - Information about a particular expansion card
+ *
+ * @slot_index: The Slot the card is typically installed in
+ * @card_name: EEPROM-programmed card name
+ * @dtbo_name: Device tree overlay for this card
+ * @eth_offset: ethXaddr MAC address index offset
+ * @owner: Manufacturer string
+ * @version: Version string
+ */
+struct ti_card_info {
+       u8 slot_index;
+       char *card_name;
+       char *dtbo_name;
+       u8 eth_offset;
+       char *owner;
+       char *version;
+};
+
+int ti_card_detect(const struct ti_card_slot_map *slot_map, int num_slots,
+                  const struct ti_card_info *cards, int num_cards,
+                  struct list_head *extension_list);
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index f294a4595f..e8e13479ce 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -179,3 +179,5 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0451
 CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
 CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_PHANDLE_CHECK_SEQ=y
+CONFIG_SUPPORT_EXTENSION_SCAN=y
+CONFIG_CMD_EXTENSION=y
diff --git a/configs/am65x_hs_evm_a53_defconfig 
b/configs/am65x_hs_evm_a53_defconfig
index e0277d4787..ff569a9216 100644
--- a/configs/am65x_hs_evm_a53_defconfig
+++ b/configs/am65x_hs_evm_a53_defconfig
@@ -157,3 +157,5 @@ CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0451
 CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
 CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_SUPPORT_EXTENSION_SCAN=y
+CONFIG_CMD_EXTENSION=y
-- 
2.34.1

Reply via email to