[RFC PATCH 2/2] board: ti: am65x: Move to using Extension framework
Roger Quadros
rogerq at kernel.org
Mon Jul 10 16:50:26 CEST 2023
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 <rogerq at kernel.org>
---
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 at 38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
+ { "gpio at 38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
+ { "gpio at 38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
+ { "gpio at 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 at 38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
- { "gpio at 38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
- { "gpio at 38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
- { "gpio at 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
More information about the U-Boot
mailing list