
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@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@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