[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