From 4b11a6296aab84b628434cdbdd15697fab8a3a93 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Mon, 7 May 2018 23:18:41 +0200 Subject: [PATCH 01/12] mtd: nand: tegra: convert to driver model and live tree The Tegra NAND driver recently got broken by ongoing driver model resp. live tree migration work: NAND: Could not decode nand-flash in device tree Tegra NAND init failed 0 MiB A patch for NAND uclass support was proposed about a year ago: https://patchwork.ozlabs.org/patch/722282/ It was not merged and I do not see on-going work for this. This commit just provides a driver model probe hook to retrieve further configuration from the live device tree. As there is no NAND ulass as of yet (ab)using UCLASS_MTD. Once UCLASS_NAND is supported, it would be possible to migrate to it. Signed-off-by: Marcel Ziswiler Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- drivers/mtd/nand/tegra_nand.c | 98 ++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index d585b7a..74acdfb 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "tegra_nand.h" DECLARE_GLOBAL_DATA_PTR; @@ -28,6 +29,13 @@ DECLARE_GLOBAL_DATA_PTR; /* ECC bytes to be generated for tag data */ #define TAG_ECC_BYTES 4 +static const struct udevice_id tegra_nand_dt_ids[] = { + { + .compatible = "nvidia,tegra20-nand", + }, + { /* sentinel */ } +}; + /* 64 byte oob block info for large page (== 2KB) device * * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC: @@ -90,9 +98,11 @@ struct nand_drv { struct fdt_nand config; }; -static struct nand_drv nand_ctrl; -static struct mtd_info *our_mtd; -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; +struct tegra_nand_info { + struct udevice *dev; + struct nand_drv nand_ctrl; + struct nand_chip nand_chip; +}; /** * Wait for command completion @@ -452,8 +462,8 @@ static void stop_command(struct nand_ctlr *reg) * @param *reg_val address of reg_val * @return 0 if ok, -1 on error */ -static int set_bus_width_page_size(struct fdt_nand *config, - u32 *reg_val) +static int set_bus_width_page_size(struct mtd_info *our_mtd, + struct fdt_nand *config, u32 *reg_val) { if (config->width == 8) *reg_val = CFG_BUS_WIDTH_8BIT; @@ -513,7 +523,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, info = (struct nand_drv *)nand_get_controller_data(chip); config = &info->config; - if (set_bus_width_page_size(config, ®_val)) + if (set_bus_width_page_size(mtd, config, ®_val)) return -EINVAL; /* Need to be 4-byte aligned */ @@ -721,7 +731,7 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, if (((int)chip->oob_poi) & 0x03) return -EINVAL; info = (struct nand_drv *)nand_get_controller_data(chip); - if (set_bus_width_page_size(&info->config, ®_val)) + if (set_bus_width_page_size(mtd, &info->config, ®_val)) return -EINVAL; stop_command(info->reg); @@ -882,51 +892,39 @@ static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT], /** * Decode NAND parameters from the device tree * - * @param blob Device tree blob - * @param node Node containing "nand-flash" compatible node + * @param dev Driver model device + * @param config Device tree NAND configuration * @return 0 if ok, -ve on error (FDT_ERR_...) */ -static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config) +static int fdt_decode_nand(struct udevice *dev, struct fdt_nand *config) { int err; - config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg"); - config->enabled = fdtdec_get_is_enabled(blob, node); - config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8); - err = gpio_request_by_name_nodev(offset_to_ofnode(node), - "nvidia,wp-gpios", 0, &config->wp_gpio, GPIOD_IS_OUT); + config->reg = (struct nand_ctlr *)dev_read_addr(dev); + config->enabled = dev_read_enabled(dev); + config->width = dev_read_u32_default(dev, "nvidia,nand-width", 8); + err = gpio_request_by_name(dev, "nvidia,wp-gpios", 0, &config->wp_gpio, + GPIOD_IS_OUT); if (err) return err; - err = fdtdec_get_int_array(blob, node, "nvidia,timing", - config->timing, FDT_NAND_TIMING_COUNT); + err = dev_read_u32_array(dev, "nvidia,timing", config->timing, + FDT_NAND_TIMING_COUNT); if (err < 0) return err; - /* Now look up the controller and decode that */ - node = fdt_next_node(blob, node, NULL); - if (node < 0) - return node; - return 0; } -/** - * Board-specific NAND initialization - * - * @param nand nand chip info structure - * @return 0, after initialized, -1 on error - */ -int tegra_nand_init(struct nand_chip *nand, int devnum) +static int tegra_probe(struct udevice *dev) { - struct nand_drv *info = &nand_ctrl; + struct tegra_nand_info *tegra = dev_get_priv(dev); + struct nand_chip *nand = &tegra->nand_chip; + struct nand_drv *info = &tegra->nand_ctrl; struct fdt_nand *config = &info->config; - int node, ret; + struct mtd_info *our_mtd; + int ret; - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_NAND); - if (node < 0) - return -1; - if (fdt_decode_nand(gd->fdt_blob, node, config)) { + if (fdt_decode_nand(dev, config)) { printf("Could not decode nand-flash in device tree\n"); return -1; } @@ -949,7 +947,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum) nand->ecc.strength = 1; nand->select_chip = nand_select_chip; nand->dev_ready = nand_dev_ready; - nand_set_controller_data(nand, &nand_ctrl); + nand_set_controller_data(nand, &tegra->nand_ctrl); /* Disable subpage writes as we do not provide ecc->hwctl */ nand->options |= NAND_NO_SUBPAGE_WRITE; @@ -974,17 +972,31 @@ int tegra_nand_init(struct nand_chip *nand, int devnum) if (ret) return ret; - ret = nand_register(devnum, our_mtd); - if (ret) + ret = nand_register(0, our_mtd); + if (ret) { + dev_err(dev, "Failed to register MTD: %d\n", ret); return ret; + } return 0; } +U_BOOT_DRIVER(tegra_nand) = { + .name = "tegra-nand", + .id = UCLASS_MTD, + .of_match = tegra_nand_dt_ids, + .probe = tegra_probe, + .priv_auto_alloc_size = sizeof(struct tegra_nand_info), +}; + void board_nand_init(void) { - struct nand_chip *nand = &nand_chip[0]; - - if (tegra_nand_init(nand, 0)) - puts("Tegra NAND init failed\n"); + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(tegra_nand), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); } From fa91fda8c30a66f87d2c4fde4e0c3f7caf69e09e Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Mon, 7 May 2018 23:18:42 +0200 Subject: [PATCH 02/12] configs: harmony: enable live tree, mtd and ubi U-Boot on Harmony recently got broken by ongoing driver model resp. live tree migration work: U-Boot 2018.03-rc3 (Feb 21 2018 - 15:43:08 +0100) TEGRA20 Model: NVIDIA Tegra20 Harmony evaluation board Board: NVIDIA Harmony DRAM: 1 GiB Video device 'dc@54200000' cannot allocate frame buffer memory -ensure the device is set up before relocation Error binding driver 'tegra_lcd': -28 Some drivers failed to bind Error binding driver 'generic_simple_bus': -28 Some drivers failed to bind initcall sequence 3ffa86d0 failed at call 00121dc0 (err=-28) This commit fixes this by enabling live tree, MTD and UBI for Harmony as well. Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- configs/harmony_defconfig | 6 ++++++ include/configs/harmony.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/configs/harmony_defconfig b/configs/harmony_defconfig index d716fc3..9d4235b 100644 --- a/configs/harmony_defconfig +++ b/configs/harmony_defconfig @@ -18,13 +18,19 @@ CONFIG_CMD_USB=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y +CONFIG_MTDIDS_DEFAULT="nand0=tegra_nand" +CONFIG_MTDPARTS_DEFAULT="mtdparts=tegra_nand:2m(u-boot)ro,1m(u-boot-env),1m(cfgblock)ro,-(ubi)" +CONFIG_CMD_UBI=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_OF_LIVE=y CONFIG_ENV_IS_IN_NAND=y CONFIG_SPL_DM=y CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y +CONFIG_MTD=y +CONFIG_MTD_UBI_FASTMAP=y CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/include/configs/harmony.h b/include/configs/harmony.h index 3ec9e87..51e284e 100644 --- a/include/configs/harmony.h +++ b/include/configs/harmony.h @@ -29,6 +29,10 @@ #define CONFIG_TEGRA_NAND #define CONFIG_SYS_MAX_NAND_DEVICE 1 +/* Dynamic MTD partition support */ +#define CONFIG_MTD_PARTITIONS +#define CONFIG_MTD_DEVICE /* needed for mtdparts commands */ + /* Environment in NAND (which is 512M), aligned to start of last sector */ #define CONFIG_ENV_OFFSET (SZ_512M - SZ_128K) /* 128K sector size */ From 51cd5a147dbd0ea31df5b2b543624ef309b4272b Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Mon, 7 May 2018 23:18:43 +0200 Subject: [PATCH 03/12] configs: colibri_t20: enable mtd Enable CONFIG_MTD as well to make sure UCLASS_MTD is available Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- configs/colibri_t20_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/colibri_t20_defconfig b/configs/colibri_t20_defconfig index 90777e0..e5d33ec 100644 --- a/configs/colibri_t20_defconfig +++ b/configs/colibri_t20_defconfig @@ -35,6 +35,7 @@ CONFIG_ENV_IS_IN_NAND=y CONFIG_SPL_DM=y CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y +CONFIG_MTD=y CONFIG_MTD_UBI_FASTMAP=y CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y From 1c1238f1e166c9ae2f4b08fa7381dc1ebd93a227 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Tue, 8 May 2018 17:34:06 +0200 Subject: [PATCH 04/12] configs: apalis-tk1: fix boot failure using ext4 rootfs Trying to boot from an ext4 rootfs fails due to us defaulting to ext3. While the downstream T20/T30 L4T kernel has issues with ext4 later TK1 L4T should work just fine with it. Hence enable ext4 for sdboot and usbboot on TK1. Signed-off-by: Sanchayan Maity Acked-by: Marcel Ziswiler Signed-off-by: Tom Warren --- include/configs/apalis-tk1.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/configs/apalis-tk1.h b/include/configs/apalis-tk1.h index fe81684..667d084 100644 --- a/include/configs/apalis-tk1.h +++ b/include/configs/apalis-tk1.h @@ -80,7 +80,7 @@ "&& setenv dtbparam ${fdt_addr_r}\0" #define SD_BOOTCMD \ - "sdargs=ip=off root=/dev/mmcblk1p2 rw rootfstype=ext3 rootwait\0" \ + "sdargs=ip=off root=/dev/mmcblk1p2 rw rootfstype=ext4 rootwait\0" \ "sdboot=run setup; setenv bootargs ${defargs} ${sdargs} ${setupargs} " \ "${vidargs}; echo Booting from SD card in 8bit slot...; " \ "run sddtbload; load mmc 1:1 ${kernel_addr_r} " \ @@ -91,7 +91,7 @@ "&& setenv dtbparam ${fdt_addr_r}\0" #define USB_BOOTCMD \ - "usbargs=ip=off root=/dev/sda2 rw rootfstype=ext3 rootwait\0" \ + "usbargs=ip=off root=/dev/sda2 rw rootfstype=ext4 rootwait\0" \ "usbboot=run setup; setenv bootargs ${defargs} ${setupargs} " \ "${usbargs} ${vidargs}; echo Booting from USB stick...; " \ "usb start && run usbdtbload; load usb 0:1 ${kernel_addr_r} " \ From c0cb8c8e8656639ebeeaa0d98a1f3c0807f590b3 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 8 May 2018 17:34:07 +0200 Subject: [PATCH 05/12] apalis-tk1: add missing as3722 gpio0 configuration As the AS3722 GPIO0 is also a not connected on our Apalis TK1 module explicitly configure it to high-impedance as well. Signed-off-by: Marcel Ziswiler Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/dts/tegra124-apalis.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/tegra124-apalis.dts b/arch/arm/dts/tegra124-apalis.dts index 2fc0384..fe08d3e 100644 --- a/arch/arm/dts/tegra124-apalis.dts +++ b/arch/arm/dts/tegra124-apalis.dts @@ -1683,9 +1683,9 @@ bias-pull-up; }; - gpio1_3_4_5_6 { - pins = "gpio1", "gpio3", "gpio4", - "gpio5", "gpio6"; + gpio0_1_3_4_5_6 { + pins = "gpio0", "gpio1", "gpio3", + "gpio4", "gpio5", "gpio6"; bias-high-impedance; }; }; From 4616e33b6a01b2f12c422d0d27afbbbbee2985e8 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 8 May 2018 17:34:08 +0200 Subject: [PATCH 06/12] power: as3722: fix ldo_get/set_enable for ldo index bigger than 7 Fix ldo_get_enable() and ldo_set_enable() functions for LDOs with an index > 7. Turns out there are actually two separate AS3722_LDO_CONTROL registers AS3722_LDO_CONTROL0 and AS3722_LDO_CONTROL1. Actually make use of both. While at it also actually use the enable parameter of the ldo_set_enable() function which now truly allows disabling as opposed to only enabling LDOs. Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- drivers/power/regulator/as3722_regulator.c | 18 ++++++++++++++++-- include/power/as3722.h | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/power/regulator/as3722_regulator.c b/drivers/power/regulator/as3722_regulator.c index 63f4615..a0703c9 100644 --- a/drivers/power/regulator/as3722_regulator.c +++ b/drivers/power/regulator/as3722_regulator.c @@ -13,6 +13,8 @@ #include #include +#define AS3722_LDO_CONTROL0_MAX_INDEX 7 + static int stepdown_get_value(struct udevice *dev) { return -ENOSYS; @@ -68,10 +70,16 @@ static int ldo_set_value(struct udevice *dev, int uvolt) static int ldo_set_enable(struct udevice *dev, bool enable) { struct udevice *pmic = dev_get_parent(dev); + u8 ctrl_reg = AS3722_LDO_CONTROL0; int ldo = dev->driver_data; int ret; - ret = pmic_clrsetbits(pmic, AS3722_LDO_CONTROL, 0, 1 << ldo); + if (ldo > AS3722_LDO_CONTROL0_MAX_INDEX) { + ctrl_reg = AS3722_LDO_CONTROL1; + ldo -= 8; + } + + ret = pmic_clrsetbits(pmic, ctrl_reg, !enable << ldo, enable << ldo); if (ret < 0) { debug("%s: failed to write LDO control register: %d", __func__, ret); @@ -84,10 +92,16 @@ static int ldo_set_enable(struct udevice *dev, bool enable) static int ldo_get_enable(struct udevice *dev) { struct udevice *pmic = dev_get_parent(dev); + u8 ctrl_reg = AS3722_LDO_CONTROL0; int ldo = dev->driver_data; int ret; - ret = pmic_reg_read(pmic, AS3722_LDO_CONTROL); + if (ldo > AS3722_LDO_CONTROL0_MAX_INDEX) { + ctrl_reg = AS3722_LDO_CONTROL1; + ldo -= 8; + } + + ret = pmic_reg_read(pmic, ctrl_reg); if (ret < 0) { debug("%s: failed to read SD control register: %d", __func__, ret); diff --git a/include/power/as3722.h b/include/power/as3722.h index 9f045d5..ab96980 100644 --- a/include/power/as3722.h +++ b/include/power/as3722.h @@ -13,7 +13,8 @@ #define AS3722_SD_VOLTAGE(n) (0x00 + (n)) #define AS3722_LDO_VOLTAGE(n) (0x10 + (n)) #define AS3722_SD_CONTROL 0x4d -#define AS3722_LDO_CONTROL 0x4e +#define AS3722_LDO_CONTROL0 0x4e +#define AS3722_LDO_CONTROL1 0x4f #define AS3722_ASIC_ID1 0x90 #define AS3722_ASIC_ID2 0x91 From 355560d5883ea0188ddb28dd2da9b54e629bd132 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 8 May 2018 17:34:09 +0200 Subject: [PATCH 07/12] pci: tegra: introduce weak tegra_pcie_board_port_reset() function Introduce a weak tegra_pcie_board_port_reset() function by default calling the existing tegra_pcie_port_reset() function. Additionally add a tegra_pcie_port_index_of_port() function to retrieve the specific PCIe port index if required. This allows overriding the PCIe port reset functionality from board specific code as e.g. required for Apalis T30 and Apalis TK1. Signed-off-by: Marcel Ziswiler Acked-by: Stephen Warren Signed-off-by: Tom Warren --- drivers/pci/pci_tegra.c | 17 ++++++++++++++--- include/pci_tegra.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 include/pci_tegra.h diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index b325914..56c0858 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -888,7 +889,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) return ret; } -static void tegra_pcie_port_reset(struct tegra_pcie_port *port) +void tegra_pcie_port_reset(struct tegra_pcie_port *port) { unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); unsigned long value; @@ -905,6 +906,16 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port) afi_writel(port->pcie, value, ctrl); } +int tegra_pcie_port_index_of_port(struct tegra_pcie_port *port) +{ + return port->index; +} + +void __weak tegra_pcie_board_port_reset(struct tegra_pcie_port *port) +{ + tegra_pcie_port_reset(port); +} + static void tegra_pcie_port_enable(struct tegra_pcie_port *port) { struct tegra_pcie *pcie = port->pcie; @@ -923,7 +934,7 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port) afi_writel(pcie, value, ctrl); - tegra_pcie_port_reset(port); + tegra_pcie_board_port_reset(port); if (soc->force_pca_enable) { value = rp_readl(port, RP_VEND_CTL2); @@ -974,7 +985,7 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) } while (--timeout); retry: - tegra_pcie_port_reset(port); + tegra_pcie_board_port_reset(port); } while (--retries); return false; diff --git a/include/pci_tegra.h b/include/pci_tegra.h new file mode 100644 index 0000000..11e92fc --- /dev/null +++ b/include/pci_tegra.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2018 Toradex, Inc. + */ + +struct tegra_pcie_port; + +int tegra_pcie_port_index_of_port(struct tegra_pcie_port *port); + +void tegra_pcie_port_reset(struct tegra_pcie_port *port); From de42975141215e7d02e0ab696b3138959bf2042c Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 8 May 2018 17:34:10 +0200 Subject: [PATCH 08/12] power: as3722: add as3722_ldo_set_voltage signature to header file Just like the already present as3722_sd_set_voltage() add the currently missing signature of the as3722_ldo_set_voltage() function to its header file. Signed-off-by: Marcel Ziswiler Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- include/power/as3722.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/power/as3722.h b/include/power/as3722.h index ab96980..2782857 100644 --- a/include/power/as3722.h +++ b/include/power/as3722.h @@ -25,5 +25,6 @@ #define AS3722_GPIO_CONTROL_INVERT (1 << 7) int as3722_sd_set_voltage(struct udevice *dev, unsigned int sd, u8 value); +int as3722_ldo_set_voltage(struct udevice *dev, unsigned int ldo, u8 value); #endif /* __POWER_AS3722_H__ */ From f1333417e82c3275cb46fe230bcdabd5b5f95922 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 8 May 2018 17:34:11 +0200 Subject: [PATCH 09/12] apalis-tk1: fix pcie reset for reliable gigabit ethernet operation It turns out that the current PCIe reset implementation in the PCIe board init function is not quite working reliably due to PCIe reset timing violations. Fix this by overriding the tegra_pcie_board_port_reset() function. Also allow optionally bringing up the PCIe switch as found on the Apalis Evaluation board. Note however that the Apalis PCIe port is also left disabled in the device tree by default. Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- board/toradex/apalis-tk1/Kconfig | 8 ++ board/toradex/apalis-tk1/apalis-tk1.c | 252 +++++++++++++++++++++------------- 2 files changed, 165 insertions(+), 95 deletions(-) diff --git a/board/toradex/apalis-tk1/Kconfig b/board/toradex/apalis-tk1/Kconfig index 05407ad..159b8fb 100644 --- a/board/toradex/apalis-tk1/Kconfig +++ b/board/toradex/apalis-tk1/Kconfig @@ -25,6 +25,14 @@ config TDX_CFG_BLOCK_PART config TDX_CFG_BLOCK_OFFSET default "-512" +config APALIS_TK1_PCIE_EVALBOARD_INIT + bool "Apalis Evaluation Board PCIe Initialisation" + help + Bring up the Apalis PCIe port with the PCIe switch as found on the + Apalis Evaluation board. Note that by default the PCIe port is also + left disabled in the device tree which needs changing as well for this + to actually work. + source "board/toradex/common/Kconfig" endif diff --git a/board/toradex/apalis-tk1/apalis-tk1.c b/board/toradex/apalis-tk1/apalis-tk1.c index 6bb2acc..d6a736d 100644 --- a/board/toradex/apalis-tk1/apalis-tk1.c +++ b/board/toradex/apalis-tk1/apalis-tk1.c @@ -1,20 +1,29 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2016 Toradex, Inc. + * Copyright (c) 2016-2018 Toradex, Inc. */ #include +#include #include #include #include #include #include +#include #include +#include #include "../common/tdx-common.h" #include "pinmux-config-apalis-tk1.h" -#define LAN_RESET_N TEGRA_GPIO(S, 2) +#define LAN_DEV_OFF_N TEGRA_GPIO(O, 6) +#define LAN_RESET_N TEGRA_GPIO(S, 2) +#define LAN_WAKE_N TEGRA_GPIO(O, 5) +#ifdef CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT +#define PEX_PERST_N TEGRA_GPIO(DD, 1) /* Apalis GPIO7 */ +#define RESET_MOCI_CTRL TEGRA_GPIO(U, 4) +#endif /* CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT */ int arch_misc_init(void) { @@ -58,123 +67,176 @@ void pinmux_init(void) } #ifdef CONFIG_PCI_TEGRA -int tegra_pcie_board_init(void) +/* TODO: Convert to driver model */ +static int as3722_sd_enable(struct udevice *pmic, unsigned int sd) { - /* TODO: Convert to driver model - struct udevice *pmic; int err; - err = as3722_init(&pmic); + if (sd > 6) + return -EINVAL; + + err = pmic_clrsetbits(pmic, AS3722_SD_CONTROL, 0, 1 << sd); if (err) { - error("failed to initialize AS3722 PMIC: %d\n", err); + pr_err("failed to update SD control register: %d", err); return err; } - err = as3722_sd_enable(pmic, 4); - if (err < 0) { - error("failed to enable SD4: %d\n", err); - return err; - } + return 0; +} - err = as3722_sd_set_voltage(pmic, 4, 0x24); - if (err < 0) { - error("failed to set SD4 voltage: %d\n", err); - return err; - } +/* TODO: Convert to driver model */ +static int as3722_ldo_enable(struct udevice *pmic, unsigned int ldo) +{ + int err; + u8 ctrl_reg = AS3722_LDO_CONTROL0; - err = as3722_gpio_configure(pmic, 1, AS3722_GPIO_OUTPUT_VDDH | - AS3722_GPIO_INVERT); - if (err < 0) { - error("failed to configure GPIO#1 as output: %d\n", err); - return err; - } + if (ldo > 11) + return -EINVAL; - err = as3722_gpio_direction_output(pmic, 2, 1); - if (err < 0) { - error("failed to set GPIO#2 high: %d\n", err); - return err; + if (ldo > 7) { + ctrl_reg = AS3722_LDO_CONTROL1; + ldo -= 8; } - */ - /* Reset I210 Gigabit Ethernet Controller */ - gpio_request(LAN_RESET_N, "LAN_RESET_N"); - gpio_direction_output(LAN_RESET_N, 0); - - /* - * Make sure we don't get any back feeding from LAN_WAKE_N resp. - * DEV_OFF_N - */ - gpio_request(TEGRA_GPIO(O, 5), "LAN_WAKE_N"); - gpio_direction_output(TEGRA_GPIO(O, 5), 0); - - gpio_request(TEGRA_GPIO(O, 6), "LAN_DEV_OFF_N"); - gpio_direction_output(TEGRA_GPIO(O, 6), 0); - - /* Make sure LDO9 and LDO10 are initially enabled @ 0V */ - /* TODO: Convert to driver model - err = as3722_ldo_enable(pmic, 9); - if (err < 0) { - error("failed to enable LDO9: %d\n", err); - return err; - } - err = as3722_ldo_enable(pmic, 10); - if (err < 0) { - error("failed to enable LDO10: %d\n", err); - return err; - } - err = as3722_ldo_set_voltage(pmic, 9, 0x80); - if (err < 0) { - error("failed to set LDO9 voltage: %d\n", err); - return err; - } - err = as3722_ldo_set_voltage(pmic, 10, 0x80); - if (err < 0) { - error("failed to set LDO10 voltage: %d\n", err); + err = pmic_clrsetbits(pmic, ctrl_reg, 0, 1 << ldo); + if (err) { + pr_err("failed to update LDO control register: %d", err); return err; } - */ - mdelay(100); - - /* Make sure controller gets enabled by disabling DEV_OFF_N */ - gpio_set_value(TEGRA_GPIO(O, 6), 1); + return 0; +} - /* Enable LDO9 and LDO10 for +V3.3_ETH on patched prototypes */ - /* TODO: Convert to driver model - err = as3722_ldo_set_voltage(pmic, 9, 0xff); - if (err < 0) { - error("failed to set LDO9 voltage: %d\n", err); - return err; +int tegra_pcie_board_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_as3722), &dev); + if (ret) { + pr_err("failed to find AS3722 PMIC: %d\n", ret); + return ret; } - err = as3722_ldo_set_voltage(pmic, 10, 0xff); - if (err < 0) { - error("failed to set LDO10 voltage: %d\n", err); - return err; + + ret = as3722_sd_enable(dev, 4); + if (ret < 0) { + pr_err("failed to enable SD4: %d\n", ret); + return ret; } - */ - mdelay(100); - gpio_set_value(LAN_RESET_N, 1); + ret = as3722_sd_set_voltage(dev, 4, 0x24); + if (ret < 0) { + pr_err("failed to set SD4 voltage: %d\n", ret); + return ret; + } -#ifdef APALIS_TK1_PCIE_EVALBOARD_INIT -#define PEX_PERST_N TEGRA_GPIO(DD, 1) /* Apalis GPIO7 */ -#define RESET_MOCI_CTRL TEGRA_GPIO(U, 4) + gpio_request(LAN_DEV_OFF_N, "LAN_DEV_OFF_N"); + gpio_request(LAN_RESET_N, "LAN_RESET_N"); + gpio_request(LAN_WAKE_N, "LAN_WAKE_N"); - /* Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis Evaluation - Board */ +#ifdef CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT gpio_request(PEX_PERST_N, "PEX_PERST_N"); gpio_request(RESET_MOCI_CTRL, "RESET_MOCI_CTRL"); - gpio_direction_output(PEX_PERST_N, 0); - gpio_direction_output(RESET_MOCI_CTRL, 0); - /* Must be asserted for 100 ms after power and clocks are stable */ - mdelay(100); - gpio_set_value(PEX_PERST_N, 1); - /* Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed Until - 900 us After PEX_PERST# De-assertion */ - mdelay(1); - gpio_set_value(RESET_MOCI_CTRL, 1); -#endif /* APALIS_T30_PCIE_EVALBOARD_INIT */ +#endif /* CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT */ return 0; } + +void tegra_pcie_board_port_reset(struct tegra_pcie_port *port) +{ + int index = tegra_pcie_port_index_of_port(port); + + if (index == 1) { /* I210 Gigabit Ethernet Controller (On-module) */ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_as3722), + &dev); + if (ret) { + debug("%s: Failed to find PMIC\n", __func__); + return; + } + + /* Reset I210 Gigabit Ethernet Controller */ + gpio_direction_output(LAN_RESET_N, 0); + + /* + * Make sure we don't get any back feeding from DEV_OFF_N resp. + * LAN_WAKE_N + */ + gpio_direction_output(LAN_DEV_OFF_N, 0); + gpio_direction_output(LAN_WAKE_N, 0); + + /* Make sure LDO9 and LDO10 are initially enabled @ 0V */ + ret = as3722_ldo_enable(dev, 9); + if (ret < 0) { + pr_err("failed to enable LDO9: %d\n", ret); + return; + } + ret = as3722_ldo_enable(dev, 10); + if (ret < 0) { + pr_err("failed to enable LDO10: %d\n", ret); + return; + } + ret = as3722_ldo_set_voltage(dev, 9, 0x80); + if (ret < 0) { + pr_err("failed to set LDO9 voltage: %d\n", ret); + return; + } + ret = as3722_ldo_set_voltage(dev, 10, 0x80); + if (ret < 0) { + pr_err("failed to set LDO10 voltage: %d\n", ret); + return; + } + + /* Make sure controller gets enabled by disabling DEV_OFF_N */ + gpio_set_value(LAN_DEV_OFF_N, 1); + + /* + * Enable LDO9 and LDO10 for +V3.3_ETH on patched prototype + * V1.0A and sample V1.0B and newer modules + */ + ret = as3722_ldo_set_voltage(dev, 9, 0xff); + if (ret < 0) { + pr_err("failed to set LDO9 voltage: %d\n", ret); + return; + } + ret = as3722_ldo_set_voltage(dev, 10, 0xff); + if (ret < 0) { + pr_err("failed to set LDO10 voltage: %d\n", ret); + return; + } + + /* + * Must be asserted for 100 ms after power and clocks are stable + */ + mdelay(100); + + gpio_set_value(LAN_RESET_N, 1); + } else if (index == 0) { /* Apalis PCIe */ +#ifdef CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT + /* + * Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis + * Evaluation Board + */ + gpio_direction_output(PEX_PERST_N, 0); + gpio_direction_output(RESET_MOCI_CTRL, 0); + + /* + * Must be asserted for 100 ms after power and clocks are stable + */ + mdelay(100); + + gpio_set_value(PEX_PERST_N, 1); + /* + * Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed + * Until 900 us After PEX_PERST# De-assertion + */ + mdelay(1); + gpio_set_value(RESET_MOCI_CTRL, 1); +#endif /* CONFIG_APALIS_TK1_PCIE_EVALBOARD_INIT */ + } +} #endif /* CONFIG_PCI_TEGRA */ From 6ab8a2b0ee7541f6e44fd8dca8cbacd8b7f45e65 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Wed, 9 May 2018 00:18:38 +0200 Subject: [PATCH 10/12] apalis_t30: describe pcie ports Add some more comments describing the various PCIe ports available. Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- arch/arm/dts/tegra30-apalis.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/dts/tegra30-apalis.dts b/arch/arm/dts/tegra30-apalis.dts index 0b84dae..0852d8d 100644 --- a/arch/arm/dts/tegra30-apalis.dts +++ b/arch/arm/dts/tegra30-apalis.dts @@ -43,16 +43,19 @@ vddio-pex-ctl-supply = <&sys_3v3_reg>; hvdd-pex-supply = <&sys_3v3_reg>; + /* Apalis Type Specific 4 Lane PCIe */ pci@1,0 { /* TS_DIFF1/2/3/4 left disabled */ nvidia,num-lanes = <4>; }; + /* Apalis PCIe */ pci@2,0 { /* PCIE1_RX/TX left disabled */ nvidia,num-lanes = <1>; }; + /* I210 Gigabit Ethernet Controller (On-module) */ pci@3,0 { status = "okay"; nvidia,num-lanes = <1>; From b4f901042807e59061a862adc265d8f899b2243f Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Wed, 9 May 2018 00:18:39 +0200 Subject: [PATCH 11/12] apalis_t30: fix pcie port 0 and 1 pin muxing Fix optional Apalis type specific 4 lane PCIe port 0 and Apalis PCIe port 1 pin muxing. Signed-off-by: Marcel Ziswiler Signed-off-by: Tom Warren --- board/toradex/apalis_t30/pinmux-config-apalis_t30.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/board/toradex/apalis_t30/pinmux-config-apalis_t30.h b/board/toradex/apalis_t30/pinmux-config-apalis_t30.h index e28742b..49c2df7 100644 --- a/board/toradex/apalis_t30/pinmux-config-apalis_t30.h +++ b/board/toradex/apalis_t30/pinmux-config-apalis_t30.h @@ -284,17 +284,19 @@ static struct pmux_pingrp_config tegra3_pinmux_common[] = { DEFAULT_PINMUX(SPI1_CS0_N_PX6, SPI1, NORMAL, NORMAL, INPUT), DEFAULT_PINMUX(SPI1_MISO_PX7, SPI1, NORMAL, NORMAL, INPUT), - DEFAULT_PINMUX(PEX_L0_PRSNT_N_PDD0, PCIE, NORMAL, NORMAL, INPUT), - DEFAULT_PINMUX(PEX_L0_RST_N_PDD1, PCIE, NORMAL, NORMAL, OUTPUT), - DEFAULT_PINMUX(PEX_L0_CLKREQ_N_PDD2, PCIE, NORMAL, NORMAL, INPUT), - DEFAULT_PINMUX(PEX_WAKE_N_PDD3, PCIE, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L0_PRSNT_N_PDD0, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L0_RST_N_PDD1, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L0_CLKREQ_N_PDD2, RSVD2, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(PEX_L1_PRSNT_N_PDD4, RSVD2, DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(PEX_L1_RST_N_PDD5, RSVD2, DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(PEX_L1_CLKREQ_N_PDD6, RSVD2, DOWN, TRISTATE, OUTPUT), /* NC */ - DEFAULT_PINMUX(PEX_L1_PRSNT_N_PDD4, PCIE, DOWN, TRISTATE, OUTPUT), /* NC */ - DEFAULT_PINMUX(PEX_L1_RST_N_PDD5, PCIE, DOWN, TRISTATE, OUTPUT), /* NC */ - DEFAULT_PINMUX(PEX_L1_CLKREQ_N_PDD6, PCIE, DOWN, TRISTATE, OUTPUT), /* NC */ DEFAULT_PINMUX(PEX_L2_PRSNT_N_PDD7, PCIE, NORMAL, NORMAL, INPUT), DEFAULT_PINMUX(PEX_L2_RST_N_PCC6, PCIE, NORMAL, NORMAL, OUTPUT), DEFAULT_PINMUX(PEX_L2_CLKREQ_N_PCC7, PCIE, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_WAKE_N_PDD3, PCIE, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(HDMI_CEC_PEE3, CEC, NORMAL, NORMAL, INPUT), DEFAULT_PINMUX(HDMI_INT_PN7, RSVD1, NORMAL, NORMAL, INPUT), From 71cb3d7c7897cd02ca731f4c510fff49705b84b7 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Wed, 9 May 2018 00:18:40 +0200 Subject: [PATCH 12/12] apalis_t30: fix optional pcie port reset for reliable pcie operation Allow optionally bringing up the Apalis type specific 4 lane PCIe port as well as the PCIe switch as found on the Apalis Evaluation board. In order to avoid violating the PCIe reset timing do this by overriding the tegra_pcie_board_port_reset() function. Note however that both the Apalis type specific 4 lane PCIe port as well as the regular Apalis PCIe port are also left disabled in the device tree by default. Signed-off-by: Marcel Ziswiler Acked-by: Stephen Warren Signed-off-by: Tom Warren --- board/toradex/apalis_t30/Kconfig | 9 ++++++ board/toradex/apalis_t30/apalis_t30.c | 57 ++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/board/toradex/apalis_t30/Kconfig b/board/toradex/apalis_t30/Kconfig index 16224da..9cd4970 100644 --- a/board/toradex/apalis_t30/Kconfig +++ b/board/toradex/apalis_t30/Kconfig @@ -25,6 +25,15 @@ config TDX_CFG_BLOCK_PART config TDX_CFG_BLOCK_OFFSET default "-512" +config APALIS_T30_PCIE_EVALBOARD_INIT + bool "Apalis Evaluation Board PCIe Initialisation" + help + Bring up the Apalis type specific 4 lane PCIe port as well as the + Apalis PCIe port with the PCIe switch as found on the Apalis + Evaluation board. Note that by default both those ports are also left + disabled in the device tree which needs changing as well for this to + actually work. + source "board/toradex/common/Kconfig" endif diff --git a/board/toradex/apalis_t30/apalis_t30.c b/board/toradex/apalis_t30/apalis_t30.c index 28830b6..ace9c5b 100644 --- a/board/toradex/apalis_t30/apalis_t30.c +++ b/board/toradex/apalis_t30/apalis_t30.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2014-2016 + * (C) Copyright 2014-2018 * Marcel Ziswiler */ @@ -13,6 +13,7 @@ #include #include #include +#include #include "../common/tdx-common.h" #include "pinmux-config-apalis_t30.h" @@ -22,6 +23,13 @@ DECLARE_GLOBAL_DATA_PTR; #define PMU_I2C_ADDRESS 0x2D #define MAX_I2C_RETRY 3 +#ifdef CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT +#define PEX_PERST_N TEGRA_GPIO(S, 7) /* Apalis GPIO7 */ +#define RESET_MOCI_CTRL TEGRA_GPIO(I, 4) + +static int pci_reset_status; +#endif /* CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT */ + int arch_misc_init(void) { if (readl(NV_PA_BASE_SRAM + NVBOOTINFOTABLE_BOOTTYPE) == @@ -106,6 +114,53 @@ int tegra_pcie_board_init(void) return err; } +#ifdef CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT + gpio_request(PEX_PERST_N, "PEX_PERST_N"); + gpio_request(RESET_MOCI_CTRL, "RESET_MOCI_CTRL"); +#endif /* CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT */ + return 0; } + +void tegra_pcie_board_port_reset(struct tegra_pcie_port *port) +{ + int index = tegra_pcie_port_index_of_port(port); + + if (index == 2) { /* I210 Gigabit Ethernet Controller (On-module) */ + tegra_pcie_port_reset(port); + } +#ifdef CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT + /* + * Apalis PCIe aka port 1 and Apalis Type Specific 4 Lane PCIe aka port + * 0 share the same RESET_MOCI therefore only assert it once for both + * ports to avoid losing the previously brought up port again. + */ + else if ((index == 1) || (index == 0)) { + /* only do it once per init cycle */ + if (pci_reset_status % 2 == 0) { + /* + * Reset PLX PEX 8605 PCIe Switch plus PCIe devices on + * Apalis Evaluation Board + */ + gpio_direction_output(PEX_PERST_N, 0); + gpio_direction_output(RESET_MOCI_CTRL, 0); + + /* + * Must be asserted for 100 ms after power and clocks + * are stable + */ + mdelay(100); + + gpio_set_value(PEX_PERST_N, 1); + /* + * Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not + * Guaranteed Until 900 us After PEX_PERST# De-assertion + */ + mdelay(1); + gpio_set_value(RESET_MOCI_CTRL, 1); + } + pci_reset_status++; + } +#endif /* CONFIG_APALIS_T30_PCIE_EVALBOARD_INIT */ +} #endif /* CONFIG_PCI_TEGRA */