From f83cfaa7f24f83c816785e33e605e29e18d76d86 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2021 12:46:39 +0200 Subject: xilinx: zynqmp: Free allocated field for target variable When env_set() is called there is no need to allocate memory for variable which is already saved that's why free it. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 38c910fa5ba..2cb97f42bec 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -735,6 +735,7 @@ int board_late_init(void) env_targets ? env_targets : ""); env_set("boot_targets", new_targets); + free(new_targets); reset_reason(); -- cgit v1.2.3 From e49f2a7f855f84a9b4c3bc0bae9615983bd42715 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 27 Jul 2021 14:05:27 +0200 Subject: xilinx: zynqmp: Change multi_boot() to return value Change multi_boot() to return multiboot value and move print out of this function and let this function to be used by other functions without duplicating message. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 2cb97f42bec..eb67116d5b4 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -350,9 +350,7 @@ static int multi_boot(void) multiboot = readl(&csu_base->multi_boot); - printf("Multiboot:\t%d\n", multiboot); - - return 0; + return multiboot; } #define PS_SYSMON_ANALOG_BUS_VAL 0x3210 @@ -392,7 +390,7 @@ int board_init(void) #endif if (current_el() == 3) - multi_boot(); + printf("Multiboot:\t%d\n", multi_boot()); return 0; } -- cgit v1.2.3 From 3d238435b216976d8a7dacd2cfddf3ba4c0d2f74 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 27 Jul 2021 16:17:31 +0200 Subject: xilinx: zynqmp: use zynqmp_mmio_read() in multi_boot() When U-Boot runs in EL2 there is no access to csu_base registers that's why this has to be done via firmware interface to find out multi boot register value. Till now this function is called only from SPL in EL3. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index eb67116d5b4..1b0356c84c5 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -346,9 +346,12 @@ int board_early_init_f(void) static int multi_boot(void) { - u32 multiboot; + u32 multiboot = 0; + int ret; - multiboot = readl(&csu_base->multi_boot); + ret = zynqmp_mmio_read((ulong)&csu_base->multi_boot, &multiboot); + if (ret) + return -EINVAL; return multiboot; } -- cgit v1.2.3 From 7c113be55103e7e3bbcb000661eafbdc03a13fe5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2021 12:43:53 +0200 Subject: xilinx: zynqmp: Config non zero SYS_SPI_U_BOOT_OFFS This variable is pointing to offset is qspi where u-boot image is placed. In our case it is location of u-boot.itb file. Offset is the same as is used by Xilinx Zynq SoC. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index ab09502f972..73972a0dc9a 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SYS_MEMTEST_START=0x00000000 CONFIG_SYS_MEMTEST_END=0x00001000 +CONFIG_SYS_SPI_U_BOOT_OFFS=0x100000 CONFIG_DM_GPIO=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu100-revC" CONFIG_SPL=y -- cgit v1.2.3 From b86f43de0be0c511358a7caeab5d935a64eb9599 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 27 Jul 2021 16:19:18 +0200 Subject: xilinx: zynqmp: Add support for runtime dfu_alt_info setup The main reason for this to be implemented is capsule update. Two memories are supported and tested which is MMC FAT based and QSPI based. For creating capsule these commands are used: ./tools/mkeficapsule --raw spl/boot.bin --index 1 capsule1.bin ./tools/mkeficapsule --raw u-boot.itb --index 2 capsule2.bin Then transfer to SD card where these commands run: load mmc 0 10000000 capsule1.bin efidebug capsule update -v 10000000 load mmc 0 10000000 capsule2.bin efidebug capsule update -v 10000000 Depends on the boot device used are binaries loaded to qspi or mmc fat partition. Also multiboot register is handled to make sure that the same location(id) is used as image which is upgraded. Two locations are used by purpose for SPL flow. If only boot.bin is used create only one capsule. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 54 ++++++++++++++++++++++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 1 + 2 files changed, 55 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 1b0356c84c5..27bb2b056c5 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -818,3 +820,55 @@ enum env_location env_get_location(enum env_operation op, int prio) return ENVL_NOWHERE; } } + +#if defined(CONFIG_SET_DFU_ALT_INFO) + +#define DFU_ALT_BUF_LEN SZ_1K + +void set_dfu_alt_info(char *interface, char *devstr) +{ + u8 multiboot; + int bootseq = 0; + + ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); + + if (env_get("dfu_alt_info")) + return; + + memset(buf, 0, sizeof(buf)); + + multiboot = multi_boot(); + debug("Multiboot: %d\n", multiboot); + + switch (zynqmp_get_bootmode()) { + case EMMC_MODE: + case SD_MODE: + case SD1_LSHFT_MODE: + case SD_MODE1: + bootseq = mmc_get_env_dev(); + if (!multiboot) + snprintf(buf, DFU_ALT_BUF_LEN, + "mmc %d:1=boot.bin fat %d 1;" + "u-boot.itb fat %d 1", + bootseq, bootseq, bootseq); + else + snprintf(buf, DFU_ALT_BUF_LEN, + "mmc %d:1=boot%04d.bin fat %d 1;" + "u-boot.itb fat %d 1", + bootseq, multiboot, bootseq, bootseq); + break; + case QSPI_MODE_24BIT: + case QSPI_MODE_32BIT: + snprintf(buf, DFU_ALT_BUF_LEN, + "sf 0:0=boot.bin raw %x 0x1500000;" + "u-boot.itb raw 0x%x 0x500000", + multiboot * SZ_32K, CONFIG_SYS_SPI_U_BOOT_OFFS); + break; + default: + return; + } + + env_set("dfu_alt_info", buf); + puts("DFU alt info setting: done\n"); +} +#endif diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 73972a0dc9a..40a87ca9044 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -94,6 +94,7 @@ CONFIG_DFU_NAND=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y CONFIG_DFU_MTD=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_SYS_DFU_DATA_BUF_SIZE=0x1800000 CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_FLASH=y -- cgit v1.2.3 From 31431dd466e7a3520ff780b893b5ca2279939c27 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 30 Jul 2021 07:59:29 +0200 Subject: firmware: xilinx: Use explicit values for all enum values Based on discussion at https://lore.kernel.org/r/20200318125003.GA2727094@kroah.com we got recommendation to use explicit values for all enum values. The patch is following this recommendation. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/daeb67ded45d8a8f6a96717d1fb9c84439dd2ae8.1612361627.git.michal.simek@xilinx.com --- include/zynqmp_firmware.h | 93 +++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index f6f82bf8828..669af6765ce 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -10,54 +10,59 @@ enum pm_api_id { PM_GET_API_VERSION = 1, - PM_SET_CONFIGURATION, - PM_GET_NODE_STATUS, - PM_GET_OPERATING_CHARACTERISTIC, - PM_REGISTER_NOTIFIER, - PM_REQUEST_SUSPEND, - PM_SELF_SUSPEND, - PM_FORCE_POWERDOWN, - PM_ABORT_SUSPEND, - PM_REQUEST_WAKEUP, - PM_SET_WAKEUP_SOURCE, - PM_SYSTEM_SHUTDOWN, - PM_REQUEST_NODE, - PM_RELEASE_NODE, - PM_SET_REQUIREMENT, - PM_SET_MAX_LATENCY, - PM_RESET_ASSERT, - PM_RESET_GET_STATUS, - PM_MMIO_WRITE, - PM_MMIO_READ, - PM_PM_INIT_FINALIZE, - PM_FPGA_LOAD, - PM_FPGA_GET_STATUS, - PM_GET_CHIPID, + PM_SET_CONFIGURATION = 2, + PM_GET_NODE_STATUS = 3, + PM_GET_OPERATING_CHARACTERISTIC = 4, + PM_REGISTER_NOTIFIER = 5, + /* API for suspending */ + PM_REQUEST_SUSPEND = 6, + PM_SELF_SUSPEND = 7, + PM_FORCE_POWERDOWN = 8, + PM_ABORT_SUSPEND = 9, + PM_REQUEST_WAKEUP = 10, + PM_SET_WAKEUP_SOURCE = 11, + PM_SYSTEM_SHUTDOWN = 12, + PM_REQUEST_NODE = 13, + PM_RELEASE_NODE = 14, + PM_SET_REQUIREMENT = 15, + PM_SET_MAX_LATENCY = 16, + /* Direct control API functions: */ + PM_RESET_ASSERT = 17, + PM_RESET_GET_STATUS = 18, + PM_MMIO_WRITE = 19, + PM_MMIO_READ = 20, + PM_PM_INIT_FINALIZE = 21, + PM_FPGA_LOAD = 22, + PM_FPGA_GET_STATUS = 23, + PM_GET_CHIPID = 24, + /* ID 25 is been used by U-boot to process secure boot images */ + /* Secure library generic API functions */ PM_SECURE_SHA = 26, - PM_SECURE_RSA, - PM_PINCTRL_REQUEST, - PM_PINCTRL_RELEASE, - PM_PINCTRL_GET_FUNCTION, - PM_PINCTRL_SET_FUNCTION, - PM_PINCTRL_CONFIG_PARAM_GET, - PM_PINCTRL_CONFIG_PARAM_SET, - PM_IOCTL, - PM_QUERY_DATA, - PM_CLOCK_ENABLE, - PM_CLOCK_DISABLE, - PM_CLOCK_GETSTATE, - PM_CLOCK_SETDIVIDER, - PM_CLOCK_GETDIVIDER, - PM_CLOCK_SETRATE, - PM_CLOCK_GETRATE, - PM_CLOCK_SETPARENT, - PM_CLOCK_GETPARENT, - PM_SECURE_IMAGE, + PM_SECURE_RSA = 27, + PM_PINCTRL_REQUEST = 28, + PM_PINCTRL_RELEASE = 29, + PM_PINCTRL_GET_FUNCTION = 30, + PM_PINCTRL_SET_FUNCTION = 31, + PM_PINCTRL_CONFIG_PARAM_GET = 32, + PM_PINCTRL_CONFIG_PARAM_SET = 33, + PM_IOCTL = 34, + PM_QUERY_DATA = 35, + PM_CLOCK_ENABLE = 36, + PM_CLOCK_DISABLE = 37, + PM_CLOCK_GETSTATE = 38, + PM_CLOCK_SETDIVIDER = 39, + PM_CLOCK_GETDIVIDER = 40, + PM_CLOCK_SETRATE = 41, + PM_CLOCK_GETRATE = 42, + PM_CLOCK_SETPARENT = 43, + PM_CLOCK_GETPARENT = 44, + PM_SECURE_IMAGE = 45, PM_FPGA_READ = 46, - PM_SECURE_AES, + PM_SECURE_AES = 47, PM_CLOCK_PLL_GETPARAM = 49, + /* PM_REGISTER_ACCESS API */ PM_REGISTER_ACCESS = 52, - PM_EFUSE_ACCESS, + PM_EFUSE_ACCESS = 53, PM_FEATURE_CHECK = 63, PM_API_MAX, }; -- cgit v1.2.3 From 23a328769a2638e87131198ad1e93000f69d6393 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 29 Jul 2021 12:57:12 +0200 Subject: dm: rtc: uclass: Add flag to control sequence numbering RTCs are using aliases for sequences. That's why enable DM_UC_FLAG_SEQ_ALIAS for exact RTC indentification. The same flag is used by a lot of other uclasses like mmc, pci, serial, spi, timer, tpm, etc. Signed-off-by: Michal Simek --- drivers/rtc/rtc-uclass.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index be6a2ddb667..321b8732ed9 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -176,6 +176,7 @@ int rtc_write32(struct udevice *dev, unsigned int reg, u32 value) UCLASS_DRIVER(rtc) = { .name = "rtc", .id = UCLASS_RTC, + .flags = DM_UC_FLAG_SEQ_ALIAS, #if !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, #endif -- cgit v1.2.3 From a1ae55ee7f8df911649a0cfa5eba3ea88bae92ab Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 29 Jul 2021 12:59:12 +0200 Subject: cmd: date: rtc: Update command to read the first RTC with seq 0 RTCs are using sequence number defined in aliases node. Date command with DM_RTC enabled is looking for the first RTC with index 0. But when RTC_EMULATION is enabled it gets likely most of the time index 0 even when system has rtc0 device via aliases node and gets sequence number 0. That's why extend the code to look for sequence 0 number first. If this fails continue to use existing device with index 0. Signed-off-by: Michal Simek --- cmd/date.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/date.c b/cmd/date.c index e377cfe165e..149ca426e8c 100644 --- a/cmd/date.c +++ b/cmd/date.c @@ -41,10 +41,13 @@ static int do_date(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_DM_RTC struct udevice *dev; - rcode = uclass_get_device(UCLASS_RTC, 0, &dev); + rcode = uclass_get_device_by_seq(UCLASS_RTC, 0, &dev); if (rcode) { - printf("Cannot find RTC: err=%d\n", rcode); - return CMD_RET_FAILURE; + rcode = uclass_get_device(UCLASS_RTC, 0, &dev); + if (rcode) { + printf("Cannot find RTC: err=%d\n", rcode); + return CMD_RET_FAILURE; + } } #elif defined(CONFIG_SYS_I2C_LEGACY) old_bus = i2c_get_bus_num(); -- cgit v1.2.3 From 1f065e8fea3043578b60e6f39ff16928c463b92e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 29 Jul 2021 10:39:08 +0200 Subject: rtc: zynqmp: Add support for ZynqMP RTC The whole driver logic is taken from Linux kernel but only set/get/reset functions are implemented. When device is power off RTC is power out of battery. Signed-off-by: Michal Simek --- MAINTAINERS | 1 + drivers/rtc/Kconfig | 7 +++ drivers/rtc/Makefile | 1 + drivers/rtc/zynqmp_rtc.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 drivers/rtc/zynqmp_rtc.c diff --git a/MAINTAINERS b/MAINTAINERS index 776ff703b9b..483a4584080 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -600,6 +600,7 @@ F: drivers/mtd/nand/raw/zynq_nand.c F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c +F: drivers/rtc/zynqmp_rtc.c F: drivers/spi/zynq_qspi.c F: drivers/spi/zynq_spi.c F: drivers/timer/cadence-ttc.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cbdfddb80f6..b6692e62df1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -195,4 +195,11 @@ config RTC_DAVINCI Say "yes" here to support the on chip real time clock present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. +config RTC_ZYNQMP + bool "Enable ZynqMP RTC driver" + depends on ARCH_ZYNQMP + help + Say "yes" here to support the on chip real time clock + present on Xilinx ZynqMP SoC. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 331a49ab599..d621be62284 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_RTC_STM32) += stm32_rtc.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o obj-$(CONFIG_RTC_ABX80X) += abx80x.o +obj-$(CONFIG_RTC_ZYNQMP) += zynqmp_rtc.o diff --git a/drivers/rtc/zynqmp_rtc.c b/drivers/rtc/zynqmp_rtc.c new file mode 100644 index 00000000000..ab9b93ca979 --- /dev/null +++ b/drivers/rtc/zynqmp_rtc.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021, Xilinx, Inc. + */ + +#define LOG_CATEGORY UCLASS_RTC + +#include +#include +#include +#include + +/* RTC Registers */ +#define RTC_SET_TM_WR 0x00 +#define RTC_SET_TM_RD 0x04 +#define RTC_CALIB_WR 0x08 +#define RTC_CUR_TM 0x10 +#define RTC_INT_STS 0x20 +#define RTC_CTRL 0x40 + +#define RTC_INT_SEC BIT(0) +#define RTC_BATT_EN BIT(31) +#define RTC_CALIB_DEF 0x198233 +#define RTC_CALIB_MASK 0x1FFFFF + +struct zynqmp_rtc_priv { + fdt_addr_t base; + unsigned int calibval; +}; + +static int zynqmp_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + u32 status; + unsigned long read_time; + + status = readl(priv->base + RTC_INT_STS); + + if (status & RTC_INT_SEC) { + /* + * RTC has updated the CURRENT_TIME with the time written into + * SET_TIME_WRITE register. + */ + read_time = readl(priv->base + RTC_CUR_TM); + } else { + /* + * Time written in SET_TIME_WRITE has not yet updated into + * the seconds read register, so read the time from the + * SET_TIME_WRITE instead of CURRENT_TIME register. + * Since we add +1 sec while writing, we need to -1 sec while + * reading. + */ + read_time = readl(priv->base + RTC_SET_TM_RD) - 1; + } + + rtc_to_tm(read_time, tm); + + return 0; +} + +static int zynqmp_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + unsigned long new_time = 0; + + if (tm) + /* + * The value written will be updated after 1 sec into the + * seconds read register, so we need to program time +1 sec + * to get the correct time on read. + */ + new_time = rtc_mktime(tm) + 1; + + /* + * Writing into calibration register will clear the Tick Counter and + * force the next second to be signaled exactly in 1 second period + */ + priv->calibval &= RTC_CALIB_MASK; + writel(priv->calibval, (priv->base + RTC_CALIB_WR)); + + writel(new_time, priv->base + RTC_SET_TM_WR); + + /* + * Clear the rtc interrupt status register after setting the + * time. During a read_time function, the code should read the + * RTC_INT_STATUS register and if bit 0 is still 0, it means + * that one second has not elapsed yet since RTC was set and + * the current time should be read from SET_TIME_READ register; + * otherwise, CURRENT_TIME register is read to report the time + */ + writel(RTC_INT_SEC, priv->base + RTC_INT_STS); + + return 0; +} + +static int zynqmp_rtc_reset(struct udevice *dev) +{ + return zynqmp_rtc_set(dev, NULL); +} + +static int zynqmp_rtc_init(struct udevice *dev) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + u32 rtc_ctrl; + + /* Enable RTC switch to battery when VCC_PSAUX is not available */ + rtc_ctrl = readl(priv->base + RTC_CTRL); + rtc_ctrl |= RTC_BATT_EN; + writel(rtc_ctrl, priv->base + RTC_CTRL); + + /* + * Based on crystal freq of 33.330 KHz + * set the seconds counter and enable, set fractions counter + * to default value suggested as per design spec + * to correct RTC delay in frequency over period of time. + */ + priv->calibval &= RTC_CALIB_MASK; + writel(priv->calibval, (priv->base + RTC_CALIB_WR)); + + return 0; +} + +static int zynqmp_rtc_probe(struct udevice *dev) +{ + struct zynqmp_rtc_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->calibval = dev_read_u32_default(dev, "calibration", + RTC_CALIB_DEF); + + ret = zynqmp_rtc_init(dev); + + return ret; +} + +static const struct rtc_ops zynqmp_rtc_ops = { + .get = zynqmp_rtc_get, + .set = zynqmp_rtc_set, + .reset = zynqmp_rtc_reset, +}; + +static const struct udevice_id zynqmp_rtc_ids[] = { + { .compatible = "xlnx,zynqmp-rtc" }, + { } +}; + +U_BOOT_DRIVER(rtc_zynqmp) = { + .name = "rtc-zynqmp", + .id = UCLASS_RTC, + .probe = zynqmp_rtc_probe, + .of_match = zynqmp_rtc_ids, + .ops = &zynqmp_rtc_ops, + .priv_auto = sizeof(struct zynqmp_rtc_priv), +}; -- cgit v1.2.3 From 8396700c330d9149812192297a4418e0d5cc4409 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 29 Jul 2021 11:42:11 +0200 Subject: xilinx: zynqmp: Enable CMD_RTC command with Zynqmp RTC driver Enable RTC command to be able to check available. And also enable ZynqMP RTC driver to be possible to use by default. Here is the list when both drivers are enabled: ZynqMP> rtc list RTC #0 - rtc_emul RTC #1 - rtc@ffa60000 Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 40a87ca9044..43ab4e7bd99 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -60,6 +60,7 @@ CONFIG_CMD_TFTPPUT=y CONFIG_CMD_BMP=y CONFIG_CMD_CACHE=y CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_RTC=y CONFIG_CMD_TIME=y CONFIG_CMD_GETTIME=y CONFIG_CMD_TIMER=y @@ -151,6 +152,7 @@ CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_RTC=y CONFIG_RTC_EMULATION=y +CONFIG_RTC_ZYNQMP=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_ARM_DCC=y -- cgit v1.2.3 From 3f123b74242bc076ba6cae6d45a11bd5da1d977f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 30 Jul 2021 08:00:10 +0200 Subject: reset: zynqmp: Add reset controller for ZynqMP SoC Add firmware based reset controller for Xilinx ZynqMP SoC to let other drivers to call reset functions. Driver is only tested on Xilinx ZynqMP but support for Xilinx Versal can be simply added. That's why reset_id and nr_reset are assigned in probe folder. Driver is inpired by driver from Linux kernel. Signed-off-by: Michal Simek --- MAINTAINERS | 1 + drivers/reset/Kconfig | 9 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-zynqmp.c | 100 +++++++++++++++++++++++++++++++++ include/zynqmp_firmware.h | 131 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 drivers/reset/reset-zynqmp.c diff --git a/MAINTAINERS b/MAINTAINERS index 483a4584080..868d4e145ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -600,6 +600,7 @@ F: drivers/mtd/nand/raw/zynq_nand.c F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c +F: drivers/reset/reset-zynqmp.c F: drivers/rtc/zynqmp_rtc.c F: drivers/spi/zynq_qspi.c F: drivers/spi/zynq_spi.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a42b3f0077c..d73daf5e318 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -197,4 +197,13 @@ config RESET_SCMI Enable this option if you want to support reset controller devices exposed by a SCMI agent based on SCMI reset domain protocol communication with a SCMI server. + +config RESET_ZYNQMP + bool "Reset Driver for Xilinx ZynqMP SoC's" + depends on DM_RESET && ZYNQMP_FIRMWARE + help + Support for reset controller on Xilinx ZynqMP SoC. Driver is only + passing request via Xilinx firmware interface to TF-A and PMU + firmware. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8a0f5280761..d69486bdeb9 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o +obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c new file mode 100644 index 00000000000..57652346738 --- /dev/null +++ b/drivers/reset/reset-zynqmp.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Xilinx, Inc. - Michal Simek + */ + +#define LOG_CATEGORY UCLASS_RESET + +#include +#include +#include +#include +#include + +#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START) +#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START + +struct zynqmp_reset_priv { + u32 reset_id; + u32 nr_reset; +}; + +static int zynqmp_pm_reset_assert(const u32 reset, + const enum zynqmp_pm_reset_action assert_flag) +{ + return xilinx_pm_request(PM_RESET_ASSERT, reset, assert_flag, 0, 0, + NULL); +} + +static int zynqmp_reset_assert(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_ASSERT); +} + +static int zynqmp_reset_deassert(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_RELEASE); +} + +static int zynqmp_reset_request(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->id, priv->nr_reset); + + if (rst->id > priv->nr_reset) + return -EINVAL; + + return 0; +} + +static int zynqmp_reset_free(struct reset_ctl *rst) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->id, priv->nr_reset); + + return 0; +} + +static int zynqmp_reset_probe(struct udevice *dev) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(dev); + + priv->reset_id = ZYNQMP_RESET_ID; + priv->nr_reset = ZYNQMP_NR_RESETS; + return 0; +} + +const struct reset_ops zynqmp_reset_ops = { + .request = zynqmp_reset_request, + .rfree = zynqmp_reset_free, + .rst_assert = zynqmp_reset_assert, + .rst_deassert = zynqmp_reset_deassert, +}; + +static const struct udevice_id zynqmp_reset_ids[] = { + { .compatible = "xlnx,zynqmp-reset" }, + { } +}; + +U_BOOT_DRIVER(zynqmp_reset) = { + .name = "zynqmp_reset", + .id = UCLASS_RESET, + .of_match = zynqmp_reset_ids, + .ops = &zynqmp_reset_ops, + .probe = zynqmp_reset_probe, + .priv_auto = sizeof(struct zynqmp_reset_priv), +}; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 669af6765ce..e2ec8f6b5a5 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -84,6 +84,137 @@ enum pm_query_id { PM_QID_CLOCK_GET_MAX_DIVISOR = 13, }; +enum zynqmp_pm_reset_action { + PM_RESET_ACTION_RELEASE = 0, + PM_RESET_ACTION_ASSERT = 1, + PM_RESET_ACTION_PULSE = 2, +}; + +enum zynqmp_pm_reset { + ZYNQMP_PM_RESET_START = 1000, + ZYNQMP_PM_RESET_PCIE_CFG = ZYNQMP_PM_RESET_START, + ZYNQMP_PM_RESET_PCIE_BRIDGE = 1001, + ZYNQMP_PM_RESET_PCIE_CTRL = 1002, + ZYNQMP_PM_RESET_DP = 1003, + ZYNQMP_PM_RESET_SWDT_CRF = 1004, + ZYNQMP_PM_RESET_AFI_FM5 = 1005, + ZYNQMP_PM_RESET_AFI_FM4 = 1006, + ZYNQMP_PM_RESET_AFI_FM3 = 1007, + ZYNQMP_PM_RESET_AFI_FM2 = 1008, + ZYNQMP_PM_RESET_AFI_FM1 = 1009, + ZYNQMP_PM_RESET_AFI_FM0 = 1010, + ZYNQMP_PM_RESET_GDMA = 1011, + ZYNQMP_PM_RESET_GPU_PP1 = 1012, + ZYNQMP_PM_RESET_GPU_PP0 = 1013, + ZYNQMP_PM_RESET_GPU = 1014, + ZYNQMP_PM_RESET_GT = 1015, + ZYNQMP_PM_RESET_SATA = 1016, + ZYNQMP_PM_RESET_ACPU3_PWRON = 1017, + ZYNQMP_PM_RESET_ACPU2_PWRON = 1018, + ZYNQMP_PM_RESET_ACPU1_PWRON = 1019, + ZYNQMP_PM_RESET_ACPU0_PWRON = 1020, + ZYNQMP_PM_RESET_APU_L2 = 1021, + ZYNQMP_PM_RESET_ACPU3 = 1022, + ZYNQMP_PM_RESET_ACPU2 = 1023, + ZYNQMP_PM_RESET_ACPU1 = 1024, + ZYNQMP_PM_RESET_ACPU0 = 1025, + ZYNQMP_PM_RESET_DDR = 1026, + ZYNQMP_PM_RESET_APM_FPD = 1027, + ZYNQMP_PM_RESET_SOFT = 1028, + ZYNQMP_PM_RESET_GEM0 = 1029, + ZYNQMP_PM_RESET_GEM1 = 1030, + ZYNQMP_PM_RESET_GEM2 = 1031, + ZYNQMP_PM_RESET_GEM3 = 1032, + ZYNQMP_PM_RESET_QSPI = 1033, + ZYNQMP_PM_RESET_UART0 = 1034, + ZYNQMP_PM_RESET_UART1 = 1035, + ZYNQMP_PM_RESET_SPI0 = 1036, + ZYNQMP_PM_RESET_SPI1 = 1037, + ZYNQMP_PM_RESET_SDIO0 = 1038, + ZYNQMP_PM_RESET_SDIO1 = 1039, + ZYNQMP_PM_RESET_CAN0 = 1040, + ZYNQMP_PM_RESET_CAN1 = 1041, + ZYNQMP_PM_RESET_I2C0 = 1042, + ZYNQMP_PM_RESET_I2C1 = 1043, + ZYNQMP_PM_RESET_TTC0 = 1044, + ZYNQMP_PM_RESET_TTC1 = 1045, + ZYNQMP_PM_RESET_TTC2 = 1046, + ZYNQMP_PM_RESET_TTC3 = 1047, + ZYNQMP_PM_RESET_SWDT_CRL = 1048, + ZYNQMP_PM_RESET_NAND = 1049, + ZYNQMP_PM_RESET_ADMA = 1050, + ZYNQMP_PM_RESET_GPIO = 1051, + ZYNQMP_PM_RESET_IOU_CC = 1052, + ZYNQMP_PM_RESET_TIMESTAMP = 1053, + ZYNQMP_PM_RESET_RPU_R50 = 1054, + ZYNQMP_PM_RESET_RPU_R51 = 1055, + ZYNQMP_PM_RESET_RPU_AMBA = 1056, + ZYNQMP_PM_RESET_OCM = 1057, + ZYNQMP_PM_RESET_RPU_PGE = 1058, + ZYNQMP_PM_RESET_USB0_CORERESET = 1059, + ZYNQMP_PM_RESET_USB1_CORERESET = 1060, + ZYNQMP_PM_RESET_USB0_HIBERRESET = 1061, + ZYNQMP_PM_RESET_USB1_HIBERRESET = 1062, + ZYNQMP_PM_RESET_USB0_APB = 1063, + ZYNQMP_PM_RESET_USB1_APB = 1064, + ZYNQMP_PM_RESET_IPI = 1065, + ZYNQMP_PM_RESET_APM_LPD = 1066, + ZYNQMP_PM_RESET_RTC = 1067, + ZYNQMP_PM_RESET_SYSMON = 1068, + ZYNQMP_PM_RESET_AFI_FM6 = 1069, + ZYNQMP_PM_RESET_LPD_SWDT = 1070, + ZYNQMP_PM_RESET_FPD = 1071, + ZYNQMP_PM_RESET_RPU_DBG1 = 1072, + ZYNQMP_PM_RESET_RPU_DBG0 = 1073, + ZYNQMP_PM_RESET_DBG_LPD = 1074, + ZYNQMP_PM_RESET_DBG_FPD = 1075, + ZYNQMP_PM_RESET_APLL = 1076, + ZYNQMP_PM_RESET_DPLL = 1077, + ZYNQMP_PM_RESET_VPLL = 1078, + ZYNQMP_PM_RESET_IOPLL = 1079, + ZYNQMP_PM_RESET_RPLL = 1080, + ZYNQMP_PM_RESET_GPO3_PL_0 = 1081, + ZYNQMP_PM_RESET_GPO3_PL_1 = 1082, + ZYNQMP_PM_RESET_GPO3_PL_2 = 1083, + ZYNQMP_PM_RESET_GPO3_PL_3 = 1084, + ZYNQMP_PM_RESET_GPO3_PL_4 = 1085, + ZYNQMP_PM_RESET_GPO3_PL_5 = 1086, + ZYNQMP_PM_RESET_GPO3_PL_6 = 1087, + ZYNQMP_PM_RESET_GPO3_PL_7 = 1088, + ZYNQMP_PM_RESET_GPO3_PL_8 = 1089, + ZYNQMP_PM_RESET_GPO3_PL_9 = 1090, + ZYNQMP_PM_RESET_GPO3_PL_10 = 1091, + ZYNQMP_PM_RESET_GPO3_PL_11 = 1092, + ZYNQMP_PM_RESET_GPO3_PL_12 = 1093, + ZYNQMP_PM_RESET_GPO3_PL_13 = 1094, + ZYNQMP_PM_RESET_GPO3_PL_14 = 1095, + ZYNQMP_PM_RESET_GPO3_PL_15 = 1096, + ZYNQMP_PM_RESET_GPO3_PL_16 = 1097, + ZYNQMP_PM_RESET_GPO3_PL_17 = 1098, + ZYNQMP_PM_RESET_GPO3_PL_18 = 1099, + ZYNQMP_PM_RESET_GPO3_PL_19 = 1100, + ZYNQMP_PM_RESET_GPO3_PL_20 = 1101, + ZYNQMP_PM_RESET_GPO3_PL_21 = 1102, + ZYNQMP_PM_RESET_GPO3_PL_22 = 1103, + ZYNQMP_PM_RESET_GPO3_PL_23 = 1104, + ZYNQMP_PM_RESET_GPO3_PL_24 = 1105, + ZYNQMP_PM_RESET_GPO3_PL_25 = 1106, + ZYNQMP_PM_RESET_GPO3_PL_26 = 1107, + ZYNQMP_PM_RESET_GPO3_PL_27 = 1108, + ZYNQMP_PM_RESET_GPO3_PL_28 = 1109, + ZYNQMP_PM_RESET_GPO3_PL_29 = 1110, + ZYNQMP_PM_RESET_GPO3_PL_30 = 1111, + ZYNQMP_PM_RESET_GPO3_PL_31 = 1112, + ZYNQMP_PM_RESET_RPU_LS = 1113, + ZYNQMP_PM_RESET_PS_ONLY = 1114, + ZYNQMP_PM_RESET_PL = 1115, + ZYNQMP_PM_RESET_PS_PL0 = 1116, + ZYNQMP_PM_RESET_PS_PL1 = 1117, + ZYNQMP_PM_RESET_PS_PL2 = 1118, + ZYNQMP_PM_RESET_PS_PL3 = 1119, + ZYNQMP_PM_RESET_END = ZYNQMP_PM_RESET_PS_PL3 +}; + #define PM_SIP_SVC 0xc2000000 #define ZYNQMP_PM_VERSION_MAJOR 1 -- cgit v1.2.3 From 5ab5d9a44283e90a41185c744be0a11934348970 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Mon, 2 Aug 2021 23:20:40 -0600 Subject: mmc: zynq_sdhci: Return errors from arasan_sdhci_set_tapdelay Change return type of arasan_sdhci_set_tapdelay() to int, to facilitate returning errors. Get return values from input and output set clock phase functions inside arasan_sdhci_set_tapdelay() and return those errors. Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Reviewed-by: Jaehoon Chung Signed-off-by: Michal Simek --- drivers/mmc/zynq_sdhci.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index ba87ee8dd5b..1ecc2ec6690 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -422,7 +422,7 @@ static int sdhci_versal_sampleclk_set_phase(struct sdhci_host *host, return 0; } -static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) +static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) { struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); struct arasan_sdhci_clk_data *clk_data = &priv->clk_data; @@ -431,18 +431,31 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) u8 timing = mode2timing[mmc->selected_mode]; u32 iclk_phase = clk_data->clk_phase_in[timing]; u32 oclk_phase = clk_data->clk_phase_out[timing]; + int ret; dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing); if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { - sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); - sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase); + ret = sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); + if (ret) + return ret; + + ret = sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase); + if (ret) + return ret; } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) && device_is_compatible(dev, "xlnx,versal-8.9a")) { - sdhci_versal_sampleclk_set_phase(host, iclk_phase); - sdhci_versal_sdcardclk_set_phase(host, oclk_phase); + ret = sdhci_versal_sampleclk_set_phase(host, iclk_phase); + if (ret) + return ret; + + ret = sdhci_versal_sdcardclk_set_phase(host, oclk_phase); + if (ret) + return ret; } + + return 0; } static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing, -- cgit v1.2.3 From 16b593bec7b965044b6157c54b89669894fc2d54 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Mon, 2 Aug 2021 23:20:41 -0600 Subject: mmc: sdhci: Change prototype of set_delay to return errors set_delay() has return type as void. If there are any errors while setting tapdelay's it won't be able to return them. Change the prototype of set_delay() in sdhci_ops structure and return the errors from wherever it is called. Signed-off-by: Ashok Reddy Soma Reviewed-by: Jaehoon Chung Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 10 ++++++++-- include/sdhci.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index eea4701d8af..2f78da61beb 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -366,6 +366,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; + int ret; /* Wait max 20 ms */ timeout = 200; @@ -386,8 +387,13 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (clock == 0) return 0; - if (host->ops && host->ops->set_delay) - host->ops->set_delay(host); + if (host->ops && host->ops->set_delay) { + ret = host->ops->set_delay(host); + if (ret) { + printf("%s: Error while setting tap delay\n", __func__); + return ret; + } + } if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { /* diff --git a/include/sdhci.h b/include/sdhci.h index 0ae9471ad74..44a0d84e5ab 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -268,7 +268,7 @@ struct sdhci_ops { int (*set_ios_post)(struct sdhci_host *host); void (*set_clock)(struct sdhci_host *host, u32 div); int (*platform_execute_tuning)(struct mmc *host, u8 opcode); - void (*set_delay)(struct sdhci_host *host); + int (*set_delay)(struct sdhci_host *host); int (*deferred_probe)(struct sdhci_host *host); }; -- cgit v1.2.3 From 42e01bf20ab4f812a1048c8fb354e75f9e50c2f5 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 2 Aug 2021 23:20:42 -0600 Subject: zynqmp_firmware: Add zynqmp firmware related enums Add enums for pm node id's, pm ioctl id's, tapdelay types, dll reset types Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- include/zynqmp_firmware.h | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index e2ec8f6b5a5..0b068d7da29 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -67,6 +67,99 @@ enum pm_api_id { PM_API_MAX, }; +enum pm_node_id { + NODE_UNKNOWN = 0, + NODE_APU = 1, + NODE_APU_0 = 2, + NODE_APU_1 = 3, + NODE_APU_2 = 4, + NODE_APU_3 = 5, + NODE_RPU = 6, + NODE_RPU_0 = 7, + NODE_RPU_1 = 8, + NODE_PLD = 9, + NODE_FPD = 10, + NODE_OCM_BANK_0 = 11, + NODE_OCM_BANK_1 = 12, + NODE_OCM_BANK_2 = 13, + NODE_OCM_BANK_3 = 14, + NODE_TCM_0_A = 15, + NODE_TCM_0_B = 16, + NODE_TCM_1_A = 17, + NODE_TCM_1_B = 18, + NODE_L2 = 19, + NODE_GPU_PP_0 = 20, + NODE_GPU_PP_1 = 21, + NODE_USB_0 = 22, + NODE_USB_1 = 23, + NODE_TTC_0 = 24, + NODE_TTC_1 = 25, + NODE_TTC_2 = 26, + NODE_TTC_3 = 27, + NODE_SATA = 28, + NODE_ETH_0 = 29, + NODE_ETH_1 = 30, + NODE_ETH_2 = 31, + NODE_ETH_3 = 32, + NODE_UART_0 = 33, + NODE_UART_1 = 34, + NODE_SPI_0 = 35, + NODE_SPI_1 = 36, + NODE_I2C_0 = 37, + NODE_I2C_1 = 38, + NODE_SD_0 = 39, + NODE_SD_1 = 40, + NODE_DP = 41, + NODE_GDMA = 42, + NODE_ADMA = 43, + NODE_NAND = 44, + NODE_QSPI = 45, + NODE_GPIO = 46, + NODE_CAN_0 = 47, + NODE_CAN_1 = 48, + NODE_EXTERN = 49, + NODE_APLL = 50, + NODE_VPLL = 51, + NODE_DPLL = 52, + NODE_RPLL = 53, + NODE_IOPLL = 54, + NODE_DDR = 55, + NODE_IPI_APU = 56, + NODE_IPI_RPU_0 = 57, + NODE_GPU = 58, + NODE_PCIE = 59, + NODE_PCAP = 60, + NODE_RTC = 61, + NODE_LPD = 62, + NODE_VCU = 63, + NODE_IPI_RPU_1 = 64, + NODE_IPI_PL_0 = 65, + NODE_IPI_PL_1 = 66, + NODE_IPI_PL_2 = 67, + NODE_IPI_PL_3 = 68, + NODE_PL = 69, + NODE_GEM_TSU = 70, + NODE_SWDT_0 = 71, + NODE_SWDT_1 = 72, + NODE_CSU = 73, + NODE_PJTAG = 74, + NODE_TRACE = 75, + NODE_TESTSCAN = 76, + NODE_PMU = 77, + NODE_MAX = 78, +}; + +enum tap_delay_type { + PM_TAPDELAY_INPUT = 0, + PM_TAPDELAY_OUTPUT = 1, +}; + +enum dll_reset_type { + PM_DLL_RESET_ASSERT = 0, + PM_DLL_RESET_RELEASE = 1, + PM_DLL_RESET_PULSE = 2, +}; + enum pm_query_id { PM_QID_INVALID = 0, PM_QID_CLOCK_GET_NAME = 1, @@ -215,6 +308,40 @@ enum zynqmp_pm_reset { ZYNQMP_PM_RESET_END = ZYNQMP_PM_RESET_PS_PL3 }; +enum pm_ioctl_id { + IOCTL_GET_RPU_OPER_MODE = 0, + IOCTL_SET_RPU_OPER_MODE = 1, + IOCTL_RPU_BOOT_ADDR_CONFIG = 2, + IOCTL_TCM_COMB_CONFIG = 3, + IOCTL_SET_TAPDELAY_BYPASS = 4, + IOCTL_SET_SGMII_MODE = 5, + IOCTL_SD_DLL_RESET = 6, + IOCTL_SET_SD_TAPDELAY = 7, + IOCTL_SET_PLL_FRAC_MODE = 8, + IOCTL_GET_PLL_FRAC_MODE = 9, + IOCTL_SET_PLL_FRAC_DATA = 10, + IOCTL_GET_PLL_FRAC_DATA = 11, + IOCTL_WRITE_GGS = 12, + IOCTL_READ_GGS = 13, + IOCTL_WRITE_PGGS = 14, + IOCTL_READ_PGGS = 15, + /* IOCTL for ULPI reset */ + IOCTL_ULPI_RESET = 16, + /* Set healthy bit value*/ + IOCTL_SET_BOOT_HEALTH_STATUS = 17, + IOCTL_AFI = 18, + /* Probe counter read/write */ + IOCTL_PROBE_COUNTER_READ = 19, + IOCTL_PROBE_COUNTER_WRITE = 20, + IOCTL_OSPI_MUX_SELECT = 21, + /* IOCTL for USB power request */ + IOCTL_USB_SET_STATE = 22, + /* IOCTL to get last reset reason */ + IOCTL_GET_LAST_RESET_REASON = 23, + /* AIE ISR Clear */ + IOCTL_AIE_ISR_CLEAR = 24, +}; + #define PM_SIP_SVC 0xc2000000 #define ZYNQMP_PM_VERSION_MAJOR 1 -- cgit v1.2.3 From d04498255559dfc002ad71816dfb37437d29f635 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Mon, 2 Aug 2021 23:20:43 -0600 Subject: mmc: zynq_sdhci: Add xilinx_pm_request() method to set tapdelays Currently xilinx sdhci driver is using zynqmp_mmio_write() to set tapdelay values and DLL resets. Continue to use this for SPL and mini U-Boot where U-Boot will be executed at EL3 level. Use firmware call xilinx_pm_request() using appropriate arguments to set input/output tapdelays and also for DLL resets in regular flow(EL2). Host driver should explicitly request DLL reset before ITAP (assert DLL) and after OTAP (release DLL) to avoid issues in some cases. Also handle error return where possible. Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Jaehoon Chung --- board/xilinx/zynqmp/tap_delays.c | 148 +++++++++++++++++++++------------------ drivers/mmc/zynq_sdhci.c | 73 +++++++++++++++---- include/zynqmp_tap_delay.h | 25 +++++-- 3 files changed, 159 insertions(+), 87 deletions(-) diff --git a/board/xilinx/zynqmp/tap_delays.c b/board/xilinx/zynqmp/tap_delays.c index d16bbb8eff9..514f86a29ae 100644 --- a/board/xilinx/zynqmp/tap_delays.c +++ b/board/xilinx/zynqmp/tap_delays.c @@ -8,94 +8,108 @@ #include #include #include +#include #include #include +#include #define SD_DLL_CTRL 0xFF180358 #define SD_ITAP_DLY 0xFF180314 #define SD_OTAP_DLY 0xFF180318 -#define SD0_DLL_RST_MASK 0x00000004 -#define SD0_DLL_RST 0x00000004 -#define SD1_DLL_RST_MASK 0x00040000 -#define SD1_DLL_RST 0x00040000 -#define SD0_ITAPCHGWIN_MASK 0x00000200 -#define SD0_ITAPCHGWIN 0x00000200 -#define SD1_ITAPCHGWIN_MASK 0x02000000 -#define SD1_ITAPCHGWIN 0x02000000 -#define SD0_ITAPDLYENA_MASK 0x00000100 -#define SD0_ITAPDLYENA 0x00000100 -#define SD1_ITAPDLYENA_MASK 0x01000000 -#define SD1_ITAPDLYENA 0x01000000 -#define SD0_ITAPDLYSEL_MASK 0x000000FF -#define SD1_ITAPDLYSEL_MASK 0x00FF0000 -#define SD0_OTAPDLYSEL_MASK 0x0000003F -#define SD1_OTAPDLYSEL_MASK 0x003F0000 +#define SD0_DLL_RST BIT(2) +#define SD1_DLL_RST BIT(18) +#define SD0_ITAPCHGWIN BIT(9) +#define SD1_ITAPCHGWIN BIT(25) +#define SD0_ITAPDLYENA BIT(8) +#define SD1_ITAPDLYENA BIT(24) +#define SD0_ITAPDLYSEL_MASK GENMASK(7, 0) +#define SD1_ITAPDLYSEL_MASK GENMASK(23, 16) +#define SD0_OTAPDLYSEL_MASK GENMASK(5, 0) +#define SD1_OTAPDLYSEL_MASK GENMASK(21, 16) -void zynqmp_dll_reset(u8 deviceid) +int zynqmp_dll_reset(u8 node_id, u32 type) { - /* Issue DLL Reset */ - if (deviceid == 0) - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, - SD0_DLL_RST); - else - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, - SD1_DLL_RST); + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) + return zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST, + type == PM_DLL_RESET_ASSERT ? + SD0_DLL_RST : 0); - mdelay(1); - - /* Release DLL Reset */ - if (deviceid == 0) - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0); - else - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0); + return zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST, + type == PM_DLL_RESET_ASSERT ? + SD1_DLL_RST : 0); + } else { + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SD_DLL_RESET, type, 0, NULL); + } } -void arasan_zynqmp_set_in_tapdelay(u8 deviceid, u32 itap_delay) +int arasan_zynqmp_set_in_tapdelay(u8 node_id, u32 itap_delay) { - if (deviceid == 0) { - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, SD0_DLL_RST); + int ret; - /* Program ITAP delay */ - zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, - SD0_ITAPCHGWIN); - zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK, - SD0_ITAPDLYENA); - zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK, itap_delay); - zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, 0x0); + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) { + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, + SD0_ITAPCHGWIN); + if (ret) + return ret; - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0); - } else { - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, SD1_DLL_RST); + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA, + SD0_ITAPDLYENA); + if (ret) + return ret; - /* Program ITAP delay */ - zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, - SD1_ITAPCHGWIN); - zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK, - SD1_ITAPDLYENA); - zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, - (itap_delay << 16)); - zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, 0x0); + ret = zynqmp_mmio_write(SD_ITAP_DLY, + SD0_ITAPDLYSEL_MASK, + itap_delay); + if (ret) + return ret; - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0); - } -} + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, 0); + if (ret) + return ret; + } + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, + SD1_ITAPCHGWIN); + if (ret) + return ret; -void arasan_zynqmp_set_out_tapdelay(u8 deviceid, u32 otap_delay) -{ - if (deviceid == 0) { - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, SD0_DLL_RST); + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA, + SD1_ITAPDLYENA); + if (ret) + return ret; - /* Program OTAP delay */ - zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, otap_delay); + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, + (itap_delay << 16)); + if (ret) + return ret; - zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0); + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, 0); + if (ret) + return ret; } else { - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, SD1_DLL_RST); + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SET_SD_TAPDELAY, + PM_TAPDELAY_INPUT, itap_delay, NULL); + } + + return 0; +} - /* Program OTAP delay */ - zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, - (otap_delay << 16)); +int arasan_zynqmp_set_out_tapdelay(u8 node_id, u32 otap_delay) +{ + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) + return zynqmp_mmio_write(SD_OTAP_DLY, + SD0_OTAPDLYSEL_MASK, + otap_delay); - zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0); + return zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + (otap_delay << 16)); + } else { + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SET_SD_TAPDELAY, + PM_TAPDELAY_OUTPUT, otap_delay, NULL); } } diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 1ecc2ec6690..8397f242553 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -18,6 +18,7 @@ #include #include #include +#include #define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 #define SDHCI_ARASAN_ITAPDLY_SEL_MASK GENMASK(7, 0) @@ -75,26 +76,40 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_TIMING_MMC_HS200, }; -static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) +static int arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 node_id) { - u16 clk; + struct mmc *mmc = (struct mmc *)host->mmc; + struct udevice *dev = mmc->dev; unsigned long timeout; + int ret; + u16 clk; clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk &= ~(SDHCI_CLOCK_CARD_EN); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); /* Issue DLL Reset */ - zynqmp_dll_reset(deviceid); + ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_ASSERT); + if (ret) { + dev_err(dev, "dll_reset assert failed with err: %d\n", ret); + return ret; + } + + /* Allow atleast 1ms delay for proper DLL reset */ + mdelay(1); + ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_RELEASE); + if (ret) { + dev_err(dev, "dll_reset release failed with err: %d\n", ret); + return ret; + } /* Wait max 20 ms */ timeout = 100; while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - dev_err(mmc_dev(host->mmc), - ": Internal clock never stabilised.\n"); - return; + dev_err(dev, ": Internal clock never stabilised.\n"); + return -EBUSY; } timeout--; udelay(1000); @@ -102,6 +117,8 @@ static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + return 0; } static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) @@ -112,12 +129,11 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) struct sdhci_host *host; struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev); char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT; - u8 deviceid; + u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0; debug("%s\n", __func__); host = priv->host; - deviceid = priv->deviceid; ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; @@ -125,7 +141,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) mdelay(1); - arasan_zynqmp_dll_reset(host, deviceid); + arasan_zynqmp_dll_reset(host, node_id); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); @@ -171,7 +187,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) } udelay(1); - arasan_zynqmp_dll_reset(host, deviceid); + arasan_zynqmp_dll_reset(host, node_id); /* Enable only interrupts served by the SD controller */ sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, @@ -194,10 +210,13 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host, int degrees) { - struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); struct mmc *mmc = (struct mmc *)host->mmc; + struct udevice *dev = mmc->dev; + struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev); + u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0; u8 tap_delay, tap_max = 0; int timing = mode2timing[mmc->selected_mode]; + int ret; /* * This is applicable for SDHCI_SPEC_300 and above @@ -233,7 +252,19 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host, /* Limit output tap_delay value to 6 bits */ tap_delay &= SDHCI_ARASAN_OTAPDLY_SEL_MASK; - arasan_zynqmp_set_out_tapdelay(priv->deviceid, tap_delay); + /* Set the Clock Phase */ + ret = arasan_zynqmp_set_out_tapdelay(node_id, tap_delay); + if (ret) { + dev_err(dev, "Error setting output Tap Delay\n"); + return ret; + } + + /* Release DLL Reset */ + ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_RELEASE); + if (ret) { + dev_err(dev, "dll_reset release failed with err: %d\n", ret); + return ret; + } return 0; } @@ -250,10 +281,13 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host, static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host, int degrees) { - struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); struct mmc *mmc = (struct mmc *)host->mmc; + struct udevice *dev = mmc->dev; + struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev); + u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0; u8 tap_delay, tap_max = 0; int timing = mode2timing[mmc->selected_mode]; + int ret; /* * This is applicable for SDHCI_SPEC_300 and above @@ -263,6 +297,13 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host, if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300) return 0; + /* Assert DLL Reset */ + ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_ASSERT); + if (ret) { + dev_err(dev, "dll_reset assert failed with err: %d\n", ret); + return ret; + } + switch (timing) { case MMC_TIMING_MMC_HS: case MMC_TIMING_SD_HS: @@ -289,7 +330,11 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host, /* Limit input tap_delay value to 8 bits */ tap_delay &= SDHCI_ARASAN_ITAPDLY_SEL_MASK; - arasan_zynqmp_set_in_tapdelay(priv->deviceid, tap_delay); + ret = arasan_zynqmp_set_in_tapdelay(node_id, tap_delay); + if (ret) { + dev_err(dev, "Error setting Input Tap Delay\n"); + return ret; + } return 0; } diff --git a/include/zynqmp_tap_delay.h b/include/zynqmp_tap_delay.h index 1c1e3e7deed..7ef172f0fa6 100644 --- a/include/zynqmp_tap_delay.h +++ b/include/zynqmp_tap_delay.h @@ -8,14 +8,27 @@ #ifndef __ZYNQMP_TAP_DELAY_H__ #define __ZYNQMP_TAP_DELAY_H__ +#include + #ifdef CONFIG_ARCH_ZYNQMP -void zynqmp_dll_reset(u8 deviceid); -void arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay); -void arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay); +int zynqmp_dll_reset(u8 node_id, u32 type); +int arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay); +int arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay); #else -inline void zynqmp_dll_reset(u8 deviceid) {} -inline void arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay) {} -inline void arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay) {} +inline int zynqmp_dll_reset(u8 deviceid, u32 type) +{ + return 0; +} + +inline int arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay) +{ + return 0; +} + +inline int arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay) +{ + return 0; +} #endif #endif -- cgit v1.2.3 From 655d69faaf4bb1e7d3e9c31f07259b61c27e719e Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Mon, 2 Aug 2021 23:20:44 -0600 Subject: mmc: zynq_sdhci: Move setting tapdelay code to driver Move tapdelay function calls to zynq_sdhci.c and make them static inline. zynqmp_tap_delay.h has function prototypes for the functions defined in tap_delays.c, which will not be needed anymore. Remove tap_delays.c and zynqmp_tap_delay.h files. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Jaehoon Chung --- board/xilinx/zynqmp/Makefile | 2 - board/xilinx/zynqmp/tap_delays.c | 115 --------------------------------------- drivers/mmc/zynq_sdhci.c | 108 +++++++++++++++++++++++++++++++++++- include/zynqmp_tap_delay.h | 34 ------------ 4 files changed, 107 insertions(+), 152 deletions(-) delete mode 100644 board/xilinx/zynqmp/tap_delays.c delete mode 100644 include/zynqmp_tap_delay.h diff --git a/board/xilinx/zynqmp/Makefile b/board/xilinx/zynqmp/Makefile index 7d8277ca400..a9140287533 100644 --- a/board/xilinx/zynqmp/Makefile +++ b/board/xilinx/zynqmp/Makefile @@ -44,8 +44,6 @@ $(obj)/pm_cfg_obj.o: $(shell cd $(srctree); readlink -f $(CONFIG_ZYNQMP_SPL_PM_C endif endif -obj-$(CONFIG_MMC_SDHCI_ZYNQ) += tap_delays.o - ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CMD_ZYNQMP) += cmds.o endif diff --git a/board/xilinx/zynqmp/tap_delays.c b/board/xilinx/zynqmp/tap_delays.c deleted file mode 100644 index 514f86a29ae..00000000000 --- a/board/xilinx/zynqmp/tap_delays.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Xilinx ZynqMP SoC Tap Delay Programming - * - * Copyright (C) 2018 Xilinx, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define SD_DLL_CTRL 0xFF180358 -#define SD_ITAP_DLY 0xFF180314 -#define SD_OTAP_DLY 0xFF180318 -#define SD0_DLL_RST BIT(2) -#define SD1_DLL_RST BIT(18) -#define SD0_ITAPCHGWIN BIT(9) -#define SD1_ITAPCHGWIN BIT(25) -#define SD0_ITAPDLYENA BIT(8) -#define SD1_ITAPDLYENA BIT(24) -#define SD0_ITAPDLYSEL_MASK GENMASK(7, 0) -#define SD1_ITAPDLYSEL_MASK GENMASK(23, 16) -#define SD0_OTAPDLYSEL_MASK GENMASK(5, 0) -#define SD1_OTAPDLYSEL_MASK GENMASK(21, 16) - -int zynqmp_dll_reset(u8 node_id, u32 type) -{ - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { - if (node_id == NODE_SD_0) - return zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST, - type == PM_DLL_RESET_ASSERT ? - SD0_DLL_RST : 0); - - return zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST, - type == PM_DLL_RESET_ASSERT ? - SD1_DLL_RST : 0); - } else { - return xilinx_pm_request(PM_IOCTL, (u32)node_id, - IOCTL_SD_DLL_RESET, type, 0, NULL); - } -} - -int arasan_zynqmp_set_in_tapdelay(u8 node_id, u32 itap_delay) -{ - int ret; - - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { - if (node_id == NODE_SD_0) { - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, - SD0_ITAPCHGWIN); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA, - SD0_ITAPDLYENA); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, - SD0_ITAPDLYSEL_MASK, - itap_delay); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, 0); - if (ret) - return ret; - } - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, - SD1_ITAPCHGWIN); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA, - SD1_ITAPDLYENA); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, - (itap_delay << 16)); - if (ret) - return ret; - - ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, 0); - if (ret) - return ret; - } else { - return xilinx_pm_request(PM_IOCTL, (u32)node_id, - IOCTL_SET_SD_TAPDELAY, - PM_TAPDELAY_INPUT, itap_delay, NULL); - } - - return 0; -} - -int arasan_zynqmp_set_out_tapdelay(u8 node_id, u32 otap_delay) -{ - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { - if (node_id == NODE_SD_0) - return zynqmp_mmio_write(SD_OTAP_DLY, - SD0_OTAPDLYSEL_MASK, - otap_delay); - - return zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, - (otap_delay << 16)); - } else { - return xilinx_pm_request(PM_IOCTL, (u32)node_id, - IOCTL_SET_SD_TAPDELAY, - PM_TAPDELAY_OUTPUT, otap_delay, NULL); - } -} diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 8397f242553..9a1693940a7 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include #define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 @@ -31,6 +31,20 @@ #define SDHCI_TUNING_LOOP_COUNT 40 #define MMC_BANK2 0x2 +#define SD_DLL_CTRL 0xFF180358 +#define SD_ITAP_DLY 0xFF180314 +#define SD_OTAP_DLY 0xFF180318 +#define SD0_DLL_RST BIT(2) +#define SD1_DLL_RST BIT(18) +#define SD0_ITAPCHGWIN BIT(9) +#define SD1_ITAPCHGWIN BIT(25) +#define SD0_ITAPDLYENA BIT(8) +#define SD1_ITAPDLYENA BIT(24) +#define SD0_ITAPDLYSEL_MASK GENMASK(7, 0) +#define SD1_ITAPDLYSEL_MASK GENMASK(23, 16) +#define SD0_OTAPDLYSEL_MASK GENMASK(5, 0) +#define SD1_OTAPDLYSEL_MASK GENMASK(21, 16) + struct arasan_sdhci_clk_data { int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; @@ -49,6 +63,12 @@ struct arasan_sdhci_priv { u8 no_1p8; }; +/* For Versal platforms zynqmp_mmio_write() won't be available */ +__weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) +{ + return 0; +} + #if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) /* Default settings for ZynqMP Clock Phases */ static const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, @@ -76,6 +96,92 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_TIMING_MMC_HS200, }; +static inline int arasan_zynqmp_set_in_tapdelay(u8 node_id, u32 itap_delay) +{ + int ret; + + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) { + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, + SD0_ITAPCHGWIN); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA, + SD0_ITAPDLYENA); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK, + itap_delay); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, 0); + if (ret) + return ret; + } + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, + SD1_ITAPCHGWIN); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA, + SD1_ITAPDLYENA); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, + (itap_delay << 16)); + if (ret) + return ret; + + ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, 0); + if (ret) + return ret; + } else { + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SET_SD_TAPDELAY, + PM_TAPDELAY_INPUT, itap_delay, NULL); + } + + return 0; +} + +static inline int arasan_zynqmp_set_out_tapdelay(u8 node_id, u32 otap_delay) +{ + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) + return zynqmp_mmio_write(SD_OTAP_DLY, + SD0_OTAPDLYSEL_MASK, + otap_delay); + + return zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + (otap_delay << 16)); + } else { + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SET_SD_TAPDELAY, + PM_TAPDELAY_OUTPUT, otap_delay, NULL); + } +} + +static inline int zynqmp_dll_reset(u8 node_id, u32 type) +{ + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (node_id == NODE_SD_0) + return zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST, + type == PM_DLL_RESET_ASSERT ? + SD0_DLL_RST : 0); + + return zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST, + type == PM_DLL_RESET_ASSERT ? + SD1_DLL_RST : 0); + } else { + return xilinx_pm_request(PM_IOCTL, (u32)node_id, + IOCTL_SD_DLL_RESET, type, 0, NULL); + } +} + static int arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 node_id) { struct mmc *mmc = (struct mmc *)host->mmc; diff --git a/include/zynqmp_tap_delay.h b/include/zynqmp_tap_delay.h deleted file mode 100644 index 7ef172f0fa6..00000000000 --- a/include/zynqmp_tap_delay.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Xilinx ZynqMP SoC Tap Delay Programming - * - * Copyright (C) 2018 Xilinx, Inc. - */ - -#ifndef __ZYNQMP_TAP_DELAY_H__ -#define __ZYNQMP_TAP_DELAY_H__ - -#include - -#ifdef CONFIG_ARCH_ZYNQMP -int zynqmp_dll_reset(u8 node_id, u32 type); -int arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay); -int arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay); -#else -inline int zynqmp_dll_reset(u8 deviceid, u32 type) -{ - return 0; -} - -inline int arasan_zynqmp_set_in_tapdelay(u8 device_id, u32 itap_delay) -{ - return 0; -} - -inline int arasan_zynqmp_set_out_tapdelay(u8 device_id, u32 otap_delay) -{ - return 0; -} -#endif - -#endif -- cgit v1.2.3 From b6f44082d5cd2ea2758f09df4e364ded6f81323a Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 2 Aug 2021 23:20:45 -0600 Subject: mmc: zynq_sdhci: Wait till sd card detect state is stable As per SD spec when SD host controller is reset, it takes 1000msec to detect the card state. In case, if we enable the sd bus voltage & card detect state is not stable, then host controller will disable the sd bus voltage. In case of warm/subsystem reboot, due to unstable card detect state host controller is disabling the sd bus voltage to sd card causing sd card timeout error. So we wait for a maximum of 1000msec to get the card detect state stable before we enable the sd bus voltage. This current fix is workaround for now, this needs to be analysed further. Zynqmp platform should behave the same as Versal, but we did not encounter this issue as of now. So we are fixing it for Versal only. Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Reviewed-by: Jaehoon Chung Signed-off-by: Michal Simek --- drivers/mmc/zynq_sdhci.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 9a1693940a7..4a877b4ce8c 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -776,6 +776,25 @@ static int arasan_sdhci_probe(struct udevice *dev) return ret; upriv->mmc = host->mmc; + /* + * WORKAROUND: Versal platforms have an issue with card detect state. + * Due to this, host controller is switching off voltage to sd card + * causing sd card timeout error. Workaround this by adding a wait for + * 1000msec till the card detect state gets stable. + */ + if (IS_ENABLED(CONFIG_ARCH_VERSAL)) { + u32 timeout = 1000; + + while (((sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_STATE_STABLE) == 0) && timeout--) { + mdelay(1); + } + if (!timeout) { + dev_err(dev, "Sdhci card detect state not stable\n"); + return -ETIMEDOUT; + } + } + return sdhci_probe(dev); } -- cgit v1.2.3 From 3ae330c1776223722e3f582fc95c51c318d57a8f Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Mon, 2 Aug 2021 23:20:46 -0600 Subject: mmc: zynq_sdhci: Use set_control_reg from sdhci.c Since set_control_reg is available in sdhci.c, use it and remove arasan_sdhci_set_control_reg(). Signed-off-by: Ashok Reddy Soma Reviewed-by: Jaehoon Chung Signed-off-by: Michal Simek --- drivers/mmc/zynq_sdhci.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 4a877b4ce8c..c94825dceb9 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -690,29 +690,10 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) "clk-phase-mmc-hs400"); } -static void arasan_sdhci_set_control_reg(struct sdhci_host *host) -{ - struct mmc *mmc = (struct mmc *)host->mmc; - u32 reg; - - if (!IS_SD(mmc)) - return; - - if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); - reg |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); - } - - if (mmc->selected_mode > SD_HS && - mmc->selected_mode <= MMC_HS_200) - sdhci_set_uhs_timing(host); -} - static const struct sdhci_ops arasan_ops = { .platform_execute_tuning = &arasan_sdhci_execute_tuning, .set_delay = &arasan_sdhci_set_tapdelay, - .set_control_reg = &arasan_sdhci_set_control_reg, + .set_control_reg = &sdhci_set_control_reg, }; #endif -- cgit v1.2.3 From 055dfdc257c99b2195e22493d986dd3b45939f80 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 09:18:17 +0200 Subject: arm64: zynqmp: Disable WDT_CDNS driver by default Do not enable watchdog driver in default zynqmp configuration. The reason is that not all distributions are handling watchdog properly and then expires and system resets. If someone needs watchdog in their design please enable it by hand. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 43ab4e7bd99..38b8f8c8b41 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -191,7 +191,6 @@ CONFIG_BMP_16BPP=y CONFIG_BMP_24BPP=y CONFIG_BMP_32BPP=y CONFIG_WDT=y -CONFIG_WDT_CDNS=y CONFIG_PANIC_HANG=y CONFIG_TPM=y CONFIG_SPL_GZIP=y -- cgit v1.2.3 From 18bfe9cf5a590210485e442e1af7a1dff5ae87f4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 29 Jul 2021 14:22:05 +0200 Subject: xilinx: zynqmp: Initialize usb and scsi via preboot Based on thread https://lists.denx.de/pipermail/u-boot/2021-June/451828.html especially "Overall we have a deficiency in the UEFI implementation in that we cannot deal with block devices added or removed after initialization." there is a need to deal with removable media as usb/scsi/sata. That's why bridge this gap in EFI implementation by resetting usb and scsi resets to get all disks before efi_init_obj_list() is called. In our standard boot flow, where we use distro boot, order is fixed as "jtag mmc0 mmc1 qspi0 nand0 usb0 usb1 scsi0 pxe dhcp" with prioritizing boot device added by commit 2882b39d564b ("arm64: zynqmp: Setup the first boot_target at run time"). When device has ESP partition all devices should be detected because then efi_disk_register() in efi_init_obj_list() is called only once. The first such a device is sd/emmc(mmc0/mmc1) and then disks on usb/sata are not handled at all. The commit 6bb577dbb30f ("arm64: zynqmp: Disable EFI_CAPSULE_ON_DISK_EARLY") also pointed out on this issue but detection of removable media wasn't solved that's why do it now via preboot command. I have tested cases without usb and scsi and there is no problem with calling resets without devices itself. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 38b8f8c8b41..348a6039675 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -22,6 +22,7 @@ CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 CONFIG_USE_PREBOOT=y +CONFIG_PREBOOT="run scsi_init;usb start" # CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_EARLY_INIT_R=y -- cgit v1.2.3 From 4cec057ff96e22019291894c1c3d526dfa57c415 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 11:12:56 +0200 Subject: arm64: zynqmp: Fix node name for ds35/36 leds By dt-binding specs led nodes should have -led suffix that's why add it. Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-sm-k26-revA.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/zynqmp-sm-k26-revA.dts b/arch/arm/dts/zynqmp-sm-k26-revA.dts index b613ab23425..7289badc2d7 100644 --- a/arch/arm/dts/zynqmp-sm-k26-revA.dts +++ b/arch/arm/dts/zynqmp-sm-k26-revA.dts @@ -60,13 +60,13 @@ leds { compatible = "gpio-leds"; - ds35 { + ds35-led { label = "heartbeat"; gpios = <&gpio 7 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - ds36 { + ds36-led { label = "vbus_det"; gpios = <&gpio 8 GPIO_ACTIVE_HIGH>; default-state = "on"; -- cgit v1.2.3 From 464f6558ca7daab476336fcf6b7e3ec0b7fc1e92 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 11:12:29 +0200 Subject: arm64: zynqmp: Fix header alignment on kv260 boards Fix header alignment. Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-sck-kv-g-revA.dts | 8 ++++---- arch/arm/dts/zynqmp-sck-kv-g-revB.dts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/dts/zynqmp-sck-kv-g-revA.dts b/arch/arm/dts/zynqmp-sck-kv-g-revA.dts index 4e8086c82f2..22602d8c33f 100644 --- a/arch/arm/dts/zynqmp-sck-kv-g-revA.dts +++ b/arch/arm/dts/zynqmp-sck-kv-g-revA.dts @@ -12,10 +12,10 @@ * Michal Simek */ - #include - #include - #include - #include +#include +#include +#include +#include /dts-v1/; /plugin/; diff --git a/arch/arm/dts/zynqmp-sck-kv-g-revB.dts b/arch/arm/dts/zynqmp-sck-kv-g-revB.dts index 048d5665c57..df054e152a7 100644 --- a/arch/arm/dts/zynqmp-sck-kv-g-revB.dts +++ b/arch/arm/dts/zynqmp-sck-kv-g-revB.dts @@ -7,10 +7,10 @@ * Michal Simek */ - #include - #include - #include - #include +#include +#include +#include +#include /dts-v1/; /plugin/; -- cgit v1.2.3 From 1759a3128823942beb48be1306a8d11191aab0f9 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 5 Aug 2021 08:28:46 +0200 Subject: arm64: zynqmp: Update comment style sm-k26 Trivial style patch. Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-sm-k26-revA.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/zynqmp-sm-k26-revA.dts b/arch/arm/dts/zynqmp-sm-k26-revA.dts index 7289badc2d7..e274100a9bc 100644 --- a/arch/arm/dts/zynqmp-sm-k26-revA.dts +++ b/arch/arm/dts/zynqmp-sm-k26-revA.dts @@ -183,7 +183,7 @@ }; }; -&sdhci0 { /* MIO13-23 - 16GB emmc MTFC16GAPALBH-IT - U133A*/ +&sdhci0 { /* MIO13-23 - 16GB emmc MTFC16GAPALBH-IT - U133A */ status = "okay"; non-removable; disable-wp; -- cgit v1.2.3 From bc353102a090b93452e9652029d184bc24b4701e Mon Sep 17 00:00:00 2001 From: Raju Kumar Pothuraju Date: Thu, 1 Jul 2021 14:15:11 +0530 Subject: xilinx: Add jedec compatible string for QSPI (Zynq/ZynqMP) Add missing "jedec, spi-nor" compatible string for QSPI flash node. Spi-nor framework uses this compatibility string to probe & initialize flash. With missing compatibility string we are observing below error: Zynq> sf probe 0 0 0 jedec_spi_nor spi_flash@0:0: unrecognized JEDEC id bytes: 00, 00, 00 Failed to initialize SPI flash at 0:0 (error -2) Signed-off-by: Raju Kumar Pothuraju Signed-off-by: Michal Simek --- arch/arm/dts/zynq-cc108.dts | 2 +- arch/arm/dts/zynq-cse-qspi.dtsi | 2 +- arch/arm/dts/zynq-topic-miami.dts | 2 +- arch/arm/dts/zynqmp-topic-miamimp-xilinx-xdp-v1r1.dts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/zynq-cc108.dts b/arch/arm/dts/zynq-cc108.dts index 64d73ecbc59..036106e2212 100644 --- a/arch/arm/dts/zynq-cc108.dts +++ b/arch/arm/dts/zynq-cc108.dts @@ -58,7 +58,7 @@ is-dual = <0>; num-cs = <1>; flash@0 { /* 16 MB */ - compatible = "n25q128a11"; + compatible = "n25q128a11", "jedec,spi-nor"; reg = <0x0>; spi-max-frequency = <50000000>; spi-tx-bus-width = <1>; diff --git a/arch/arm/dts/zynq-cse-qspi.dtsi b/arch/arm/dts/zynq-cse-qspi.dtsi index eb0e29e6cb6..38410eeca88 100644 --- a/arch/arm/dts/zynq-cse-qspi.dtsi +++ b/arch/arm/dts/zynq-cse-qspi.dtsi @@ -60,7 +60,7 @@ #size-cells = <0>; num-cs = <1>; flash0: flash@0 { - compatible = "n25q128a11"; + compatible = "n25q128a11", "jedec,spi-nor"; reg = <0x0>; spi-tx-bus-width = <1>; spi-rx-bus-width = <4>; diff --git a/arch/arm/dts/zynq-topic-miami.dts b/arch/arm/dts/zynq-topic-miami.dts index ab6bde95fed..c4ec56138e1 100644 --- a/arch/arm/dts/zynq-topic-miami.dts +++ b/arch/arm/dts/zynq-topic-miami.dts @@ -36,7 +36,7 @@ is-dual = <0>; num-cs = <1>; flash@0 { - compatible = "st,m25p80", "n25q256a"; + compatible = "st,m25p80", "n25q256a", "jedec,spi-nor"; m25p,fast-read; reg = <0x0>; spi-tx-bus-width = <1>; diff --git a/arch/arm/dts/zynqmp-topic-miamimp-xilinx-xdp-v1r1.dts b/arch/arm/dts/zynqmp-topic-miamimp-xilinx-xdp-v1r1.dts index 6ec96e0e8c9..300e2ebe96e 100644 --- a/arch/arm/dts/zynqmp-topic-miamimp-xilinx-xdp-v1r1.dts +++ b/arch/arm/dts/zynqmp-topic-miamimp-xilinx-xdp-v1r1.dts @@ -58,7 +58,7 @@ status = "okay"; is-dual = <1>; flash@0 { - compatible = "st,m25p80", "n25q256a"; + compatible = "st,m25p80", "n25q256a", "jedec,spi-nor"; m25p,fast-read; reg = <0x0>; spi-tx-bus-width = <1>; -- cgit v1.2.3 From b9c4e8d439ddce576e569acb0880d36002e71448 Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Fri, 6 Aug 2021 01:41:46 -0600 Subject: ARM: zynq: Replace 'io-standard' with 'power-source' property Replace 'io-standard' property with 'power-source' property in all zynq dts files to be in sync with Zynq Pinctrl driver. Signed-off-by: Sai Krishna Potthuri Signed-off-by: Michal Simek --- arch/arm/dts/zynq-zc702.dts | 22 +++++++++++----------- arch/arm/dts/zynq-zc706.dts | 18 +++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/arch/arm/dts/zynq-zc702.dts b/arch/arm/dts/zynq-zc702.dts index 4474f4bfd7b..57a47409b91 100644 --- a/arch/arm/dts/zynq-zc702.dts +++ b/arch/arm/dts/zynq-zc702.dts @@ -213,7 +213,7 @@ conf { groups = "can0_9_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-rx { @@ -236,7 +236,7 @@ conf { groups = "ethernet0_0_grp"; slew-rate = <0>; - io-standard = <4>; + power-source = <4>; }; conf-rx { @@ -259,7 +259,7 @@ conf-mdio { groups = "mdio0_0_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; bias-disable; }; }; @@ -277,7 +277,7 @@ "gpio0_10_grp", "gpio0_11_grp", "gpio0_12_grp", "gpio0_13_grp", "gpio0_14_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-pull-up { @@ -301,7 +301,7 @@ groups = "i2c0_10_grp"; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; }; @@ -314,7 +314,7 @@ conf { groups = "gpio0_50_grp", "gpio0_51_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; }; @@ -327,7 +327,7 @@ conf { groups = "sdio0_2_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; bias-disable; }; @@ -341,7 +341,7 @@ bias-high-impedance; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; mux-wp { @@ -354,7 +354,7 @@ bias-high-impedance; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; }; @@ -367,7 +367,7 @@ conf { groups = "uart1_10_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-rx { @@ -390,7 +390,7 @@ conf { groups = "usb0_0_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-rx { diff --git a/arch/arm/dts/zynq-zc706.dts b/arch/arm/dts/zynq-zc706.dts index 84729e9feba..87308c0333d 100644 --- a/arch/arm/dts/zynq-zc706.dts +++ b/arch/arm/dts/zynq-zc706.dts @@ -151,7 +151,7 @@ conf { groups = "ethernet0_0_grp"; slew-rate = <0>; - io-standard = <4>; + power-source = <4>; }; conf-rx { @@ -174,7 +174,7 @@ conf-mdio { groups = "mdio0_0_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; bias-disable; }; }; @@ -188,7 +188,7 @@ conf { groups = "gpio0_7_grp", "gpio0_46_grp", "gpio0_47_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-pull-up { @@ -212,7 +212,7 @@ groups = "i2c0_10_grp"; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; }; @@ -225,7 +225,7 @@ conf { groups = "sdio0_2_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; bias-disable; }; @@ -239,7 +239,7 @@ bias-high-impedance; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; mux-wp { @@ -252,7 +252,7 @@ bias-high-impedance; bias-pull-up; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; }; @@ -265,7 +265,7 @@ conf { groups = "uart1_10_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-rx { @@ -288,7 +288,7 @@ conf { groups = "usb0_0_grp"; slew-rate = <0>; - io-standard = <1>; + power-source = <1>; }; conf-rx { -- cgit v1.2.3 From 0df062bf04c1a530a831ed65f2a53f90645addde Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 13:30:19 +0200 Subject: ARM: zynq: Wire single qspi on couple of boards Single configuration is working fine and no issue to enable it. Signed-off-by: Michal Simek --- arch/arm/dts/zynq-zc702.dts | 8 ++++++++ arch/arm/dts/zynq-zc706.dts | 8 ++++++++ arch/arm/dts/zynq-zc770-xm010.dts | 8 ++++++++ arch/arm/dts/zynq-zc770-xm013.dts | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/arch/arm/dts/zynq-zc702.dts b/arch/arm/dts/zynq-zc702.dts index 57a47409b91..f2e05a55b95 100644 --- a/arch/arm/dts/zynq-zc702.dts +++ b/arch/arm/dts/zynq-zc702.dts @@ -409,6 +409,14 @@ &qspi { u-boot,dm-pre-reloc; status = "okay"; + num-cs = <1>; + flash@0 { + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <50000000>; + }; }; &sdhci0 { diff --git a/arch/arm/dts/zynq-zc706.dts b/arch/arm/dts/zynq-zc706.dts index 87308c0333d..cb919e40533 100644 --- a/arch/arm/dts/zynq-zc706.dts +++ b/arch/arm/dts/zynq-zc706.dts @@ -307,6 +307,14 @@ &qspi { u-boot,dm-pre-reloc; status = "okay"; + num-cs = <1>; + flash@0 { + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <50000000>; + }; }; &sdhci0 { diff --git a/arch/arm/dts/zynq-zc770-xm010.dts b/arch/arm/dts/zynq-zc770-xm010.dts index c547d7921d9..002ff9f7f48 100644 --- a/arch/arm/dts/zynq-zc770-xm010.dts +++ b/arch/arm/dts/zynq-zc770-xm010.dts @@ -62,6 +62,14 @@ &qspi { status = "okay"; + num-cs = <1>; + flash@0 { + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <50000000>; + }; }; &sdhci0 { diff --git a/arch/arm/dts/zynq-zc770-xm013.dts b/arch/arm/dts/zynq-zc770-xm013.dts index 7218ee3ad8e..455c8a96105 100644 --- a/arch/arm/dts/zynq-zc770-xm013.dts +++ b/arch/arm/dts/zynq-zc770-xm013.dts @@ -61,6 +61,14 @@ &qspi { status = "okay"; + num-cs = <1>; + flash@0 { + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <50000000>; + }; }; &spi0 { -- cgit v1.2.3 From c2b7244322444ab3f3eb56890192cb02ba200534 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 13:30:11 +0200 Subject: ARM: zynq: Enable smcc and nor for zc770-xm012 Enable cfi flash on zc770-xm012 configuration. Signed-off-by: Michal Simek --- arch/arm/dts/zynq-zc770-xm012.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/dts/zynq-zc770-xm012.dts b/arch/arm/dts/zynq-zc770-xm012.dts index 0d001c91610..ccf76e79841 100644 --- a/arch/arm/dts/zynq-zc770-xm012.dts +++ b/arch/arm/dts/zynq-zc770-xm012.dts @@ -53,6 +53,15 @@ }; }; +&nor0 { + status = "okay"; + bank-width = <1>; +}; + +&smcc { + status = "okay"; +}; + &spi1 { status = "okay"; num-cs = <4>; -- cgit v1.2.3 From 1031a11d71d48df0f738d4e4e744d025ce7e7aad Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 14:09:32 +0200 Subject: xilinx: Disable ARCH_FIXUP_FDT_MEMORY Based on DT spec you can have one memory node which multiple ranges or multiple nodes. fdt_fixup_memory_banks() is not implemented in a correct way when multiple memory nodes are present because all ranges are put it to the first memory node found. And next memory nodes are kept in DT which ends up in the same range specification in the same DT. Here is what it is happening. Origin DT. memory@0 { device_type = "memory"; reg = <0x0 0x0 0x0 0x80000000>; }; memory@800000000 { device_type = "memory"; reg = <0x8 0x00000000 0x0 0x80000000>; }; After fdt_fixup_memory_banks() memory@0 { device_type = "memory"; reg = <0x0 0x0 0x0 0x80000000>, <0x8 0x00000000 0x0 0x80000000>; }; memory@800000000 { device_type = "memory"; reg = <0x8 0x00000000 0x0 0x80000000>; }; As is visible memory@0 node got second range but there is still memory@800000000 node present and 2G range is listed twice. The solution can't be that second node is removed because it can be referenced already that's why it is better for us to disable this option for now. Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 + configs/xilinx_zynq_virt_defconfig | 1 + configs/xilinx_zynqmp_virt_defconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index e67905178de..c894d32a925 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -13,6 +13,7 @@ CONFIG_COUNTER_FREQUENCY=100000000 CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_BOOTDELAY=5 CONFIG_USE_PREBOOT=y # CONFIG_DISPLAY_CPUINFO is not set diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index b4c7f11505c..573a10fe221 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -23,6 +23,7 @@ CONFIG_SPL_LOAD_FIT=y CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 # CONFIG_USE_SPL_FIT_GENERATOR is not set CONFIG_LEGACY_IMAGE_FORMAT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_USE_PREBOOT=y CONFIG_SPL_STACK_R=y CONFIG_SPL_FPGA=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 348a6039675..a1b189c4c69 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -21,6 +21,7 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_USE_PREBOOT=y CONFIG_PREBOOT="run scsi_init;usb start" # CONFIG_DISPLAY_CPUINFO is not set -- cgit v1.2.3 From 5e1a3be6674ba9945ad28291cb6d8e511db6eb92 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 10 Aug 2021 09:21:54 +0200 Subject: fdt_support: Add kernel-doc for fdt_fixup_memory_banks() Add kernel-doc description for fdt_fixup_memory_banks() because it is implemented in one specific way and this information should be available for others to decide if their SoC conforms to it. If you don't want U-Boot to update your memory DT layout please disable CONFIG_ARCH_FIXUP_FDT_MEMORY. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- common/fdt_support.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/common/fdt_support.c b/common/fdt_support.c index 4341d84bd5e..8992ac5d3fc 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -420,6 +420,24 @@ static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, #else #define MEMORY_BANKS_MAX 4 #endif + +/** + * fdt_fixup_memory_banks - Update DT memory node + * @blob: Pointer to DT blob + * @start: Pointer to memory start addresses array + * @size: Pointer to memory sizes array + * @banks: Number of memory banks + * + * Return: 0 on success, negative value on failure + * + * Based on the passed number of banks and arrays, the function is able to + * update existing DT memory nodes to match run time detected/changed memory + * configuration. Implementation is handling one specific case with only one + * memory node where multiple tuples could be added/updated. + * The case where multiple memory nodes with a single tuple (base, size) are + * used, this function is only updating the first memory node without removing + * others. + */ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) { int err, nodeoffset; -- cgit v1.2.3 From a890a53ad2cdda973959947619245832203cd7f3 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 10 Aug 2021 06:50:18 -0600 Subject: soc: xilinx: zynqmp: Add soc_xilinx_zynqmp driver soc_xilinx_zynqmp driver allows identification of family & revision of zynqmp SoC. This driver is selected by CONFIG_SOC_XILINX_ZYNQMP. Add this config to xilinx_zynqmp_virt_defconfig file. Probe this driver using platdata U_BOOT_DEVICE structure which is specified in mach-zynqmp/cpu.c. Signed-off-by: T Karthik Reddy Reviewed-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- MAINTAINERS | 1 + arch/arm/Kconfig | 1 + arch/arm/mach-zynqmp/cpu.c | 5 ++ arch/arm/mach-zynqmp/include/mach/hardware.h | 3 ++ configs/xilinx_zynqmp_virt_defconfig | 1 + drivers/soc/Kconfig | 8 +++ drivers/soc/Makefile | 1 + drivers/soc/soc_xilinx_zynqmp.c | 78 ++++++++++++++++++++++++++++ 8 files changed, 98 insertions(+) create mode 100644 drivers/soc/soc_xilinx_zynqmp.c diff --git a/MAINTAINERS b/MAINTAINERS index 868d4e145ca..af5a1fedf1d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -602,6 +602,7 @@ F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c F: drivers/reset/reset-zynqmp.c F: drivers/rtc/zynqmp_rtc.c +F: drivers/soc/soc_xilinx_zynqmp.c F: drivers/spi/zynq_qspi.c F: drivers/spi/zynq_spi.c F: drivers/timer/cadence-ttc.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3a745ce126a..3e8a31f8ad5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1133,6 +1133,7 @@ config ARCH_ZYNQMP select SPL_SEPARATE_BSS if SPL select SUPPORT_SPL select ZYNQMP_IPI + select SOC_DEVICE imply BOARD_LATE_INIT imply CMD_DM imply ENV_VARS_UBOOT_RUNTIME_CONFIG diff --git a/arch/arm/mach-zynqmp/cpu.c b/arch/arm/mach-zynqmp/cpu.c index 29743cae5aa..26e285c24fe 100644 --- a/arch/arm/mach-zynqmp/cpu.c +++ b/arch/arm/mach-zynqmp/cpu.c @@ -15,6 +15,7 @@ #include #include #include +#include #define ZYNQ_SILICON_VER_MASK 0xF000 #define ZYNQ_SILICON_VER_SHIFT 12 @@ -218,3 +219,7 @@ int zynqmp_mmio_read(const u32 address, u32 *value) return ret; } + +U_BOOT_DRVINFO(soc_xilinx_zynqmp) = { + .name = "soc_xilinx_zynqmp", +}; diff --git a/arch/arm/mach-zynqmp/include/mach/hardware.h b/arch/arm/mach-zynqmp/include/mach/hardware.h index 37764990707..eebf38551c2 100644 --- a/arch/arm/mach-zynqmp/include/mach/hardware.h +++ b/arch/arm/mach-zynqmp/include/mach/hardware.h @@ -69,6 +69,9 @@ struct iou_scntr_secure { #define iou_scntr_secure ((struct iou_scntr_secure *)ZYNQMP_IOU_SCNTR_SECURE) +#define ZYNQMP_PS_VERSION 0xFFCA0044 +#define ZYNQMP_PS_VER_MASK GENMASK(1, 0) + /* Bootmode setting values */ #define BOOT_MODES_MASK 0x0000000F #define QSPI_MODE_24BIT 0x00000001 diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index a1b189c4c69..2d06da3c4d8 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -160,6 +160,7 @@ CONFIG_DM_SCSI=y CONFIG_ARM_DCC=y CONFIG_XILINX_UARTLITE=y CONFIG_ZYNQ_SERIAL=y +CONFIG_SOC_XILINX_ZYNQMP=y CONFIG_SPI=y CONFIG_ZYNQ_SPI=y CONFIG_ZYNQMP_GQSPI=y diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 864d00a8853..17fb4c4d65e 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -16,6 +16,14 @@ config SOC_DEVICE_TI_K3 This allows Texas Instruments Keystone 3 SoCs to identify specifics about the SoC in use. +config SOC_XILINX_ZYNQMP + bool "Enable SoC Device ID driver for Xilinx ZynqMP" + depends on SOC_DEVICE && ARCH_ZYNQMP + help + Enable this option to select SoC device id driver for Xilinx ZynqMP. + This allows other drivers to verify the SoC familiy & revision + using matching SoC attributes. + source "drivers/soc/ti/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 9ef20ca5066..9b26573c71c 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SOC_TI) += ti/ obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o obj-$(CONFIG_SOC_DEVICE_TI_K3) += soc_ti_k3.o obj-$(CONFIG_SANDBOX) += soc_sandbox.o +obj-$(CONFIG_SOC_XILINX_ZYNQMP) += soc_xilinx_zynqmp.o diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c new file mode 100644 index 00000000000..7d33ce2163d --- /dev/null +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx ZynqMP SOC driver + * + * Copyright (C) 2021 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Zynqmp has 4 silicon revisions + * v0 -> 0(XCZU9EG-ES1) + * v1 -> 1(XCZU3EG-ES1, XCZU15EG-ES1) + * v2 -> 2(XCZU7EV-ES1, XCZU9EG-ES2, XCZU19EG-ES1) + * v3 -> 3(Production Level) + */ +static const char zynqmp_family[] = "ZynqMP"; + +struct soc_xilinx_zynqmp_priv { + const char *family; + char revision; +}; + +static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size) +{ + struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); + + return snprintf(buf, size, "%s", priv->family); +} + +static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size) +{ + struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); + + return snprintf(buf, size, "v%d", priv->revision); +} + +static const struct soc_ops soc_xilinx_zynqmp_ops = { + .get_family = soc_xilinx_zynqmp_get_family, + .get_revision = soc_xilinx_zynqmp_get_revision, +}; + +static int soc_xilinx_zynqmp_probe(struct udevice *dev) +{ + struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); + u32 ret_payload[4]; + int ret; + + priv->family = zynqmp_family; + + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3 || + !IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) + ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]); + else + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, + ret_payload); + if (ret < 0) + return ret; + + priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK; + + return 0; +} + +U_BOOT_DRIVER(soc_xilinx_zynqmp) = { + .name = "soc_xilinx_zynqmp", + .id = UCLASS_SOC, + .ops = &soc_xilinx_zynqmp_ops, + .probe = soc_xilinx_zynqmp_probe, + .priv_auto = sizeof(struct soc_xilinx_zynqmp_priv), + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.2.3 From 42e20f52d9a4c76f4740ef6310edaa820028e070 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 10 Aug 2021 06:50:19 -0600 Subject: soc: xilinx: versal: Add soc_xilinx_versal driver soc_xilinx_versal driver allows identification of family & revision of versal SoC. This driver is selected by CONFIG_SOC_XILINX_VERSAL. Probe this driver using platdata U_BOOT_DEVICE structure which is defined at mach-versal/cpu.c. Add this config to xilinx_versal_virt_defconfig & xilinx_versal_mini_ospi_defconfig file to select this driver. Signed-off-by: T Karthik Reddy Reviewed-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- MAINTAINERS | 1 + arch/arm/Kconfig | 1 + arch/arm/mach-versal/cpu.c | 5 ++ arch/arm/mach-versal/include/mach/hardware.h | 4 ++ configs/xilinx_versal_virt_defconfig | 1 + drivers/soc/Kconfig | 8 +++ drivers/soc/Makefile | 1 + drivers/soc/soc_xilinx_versal.c | 76 ++++++++++++++++++++++++++++ 8 files changed, 97 insertions(+) create mode 100644 drivers/soc/soc_xilinx_versal.c diff --git a/MAINTAINERS b/MAINTAINERS index af5a1fedf1d..4cf0c33c5d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -546,6 +546,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-microblaze.git F: arch/arm/mach-versal/ F: drivers/net/xilinx_axi_mrmac.* +F: drivers/soc/soc_xilinx_versal.c F: drivers/watchdog/xilinx_wwdt.c N: (? #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -120,3 +121,7 @@ int arm_reserve_mmu(void) return 0; } #endif + +U_BOOT_DRVINFO(soc_xilinx_versal) = { + .name = "soc_xilinx_versal", +}; diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h index 9af5afd3f3f..7b728ac1101 100644 --- a/arch/arm/mach-versal/include/mach/hardware.h +++ b/arch/arm/mach-versal/include/mach/hardware.h @@ -65,6 +65,10 @@ struct crp_regs { #define crp_base ((struct crp_regs *)VERSAL_CRP_BASEADDR) +#define VERSAL_PS_PMC_VERSION 0xF11A0004 +#define VERSAL_PS_VER_MASK GENMASK(7, 0) +#define VERSAL_PS_VER_SHIFT 12 + /* Bootmode setting values */ #define BOOT_MODES_MASK 0x0000000F #define QSPI_MODE_24BIT 0x00000001 diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index c894d32a925..15fa5b9900c 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -96,6 +96,7 @@ CONFIG_ZYNQ_GEM=y CONFIG_ARM_DCC=y CONFIG_PL01X_SERIAL=y CONFIG_XILINX_UARTLITE=y +CONFIG_SOC_XILINX_VERSAL=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_ZYNQ_SPI=y diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 17fb4c4d65e..292dc41b6fa 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -24,6 +24,14 @@ config SOC_XILINX_ZYNQMP This allows other drivers to verify the SoC familiy & revision using matching SoC attributes. +config SOC_XILINX_VERSAL + bool "Enable SoC Device ID driver for Xilinx Versal" + depends on SOC_DEVICE && ARCH_VERSAL + help + Enable this option to select SoC device id driver for Xilinx Versal. + This allows other drivers to verify the SoC familiy & revision using + matching SoC attributes. + source "drivers/soc/ti/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 9b26573c71c..031fa7612f4 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o obj-$(CONFIG_SOC_DEVICE_TI_K3) += soc_ti_k3.o obj-$(CONFIG_SANDBOX) += soc_sandbox.o obj-$(CONFIG_SOC_XILINX_ZYNQMP) += soc_xilinx_zynqmp.o +obj-$(CONFIG_SOC_XILINX_VERSAL) += soc_xilinx_versal.o diff --git a/drivers/soc/soc_xilinx_versal.c b/drivers/soc/soc_xilinx_versal.c new file mode 100644 index 00000000000..f8bcd9ab404 --- /dev/null +++ b/drivers/soc/soc_xilinx_versal.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Versal SOC driver + * + * Copyright (C) 2021 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include + +/* + * v1 -> 0x10 - ES1 + * v2 -> 0x20 - Production + */ +static const char versal_family[] = "Versal"; + +struct soc_xilinx_versal_priv { + const char *family; + char revision; +}; + +static int soc_xilinx_versal_get_family(struct udevice *dev, char *buf, int size) +{ + struct soc_xilinx_versal_priv *priv = dev_get_priv(dev); + + return snprintf(buf, size, "%s", priv->family); +} + +static int soc_xilinx_versal_get_revision(struct udevice *dev, char *buf, int size) +{ + struct soc_xilinx_versal_priv *priv = dev_get_priv(dev); + + return snprintf(buf, size, "v%d", priv->revision); +} + +static const struct soc_ops soc_xilinx_versal_ops = { + .get_family = soc_xilinx_versal_get_family, + .get_revision = soc_xilinx_versal_get_revision, +}; + +static int soc_xilinx_versal_probe(struct udevice *dev) +{ + struct soc_xilinx_versal_priv *priv = dev_get_priv(dev); + u32 ret_payload[4]; + int ret; + + priv->family = versal_family; + + if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, + ret_payload); + if (ret) + return ret; + } else { + ret_payload[2] = readl(VERSAL_PS_PMC_VERSION); + if (!ret_payload[2]) + return -EINVAL; + } + + priv->revision = ret_payload[2] >> VERSAL_PS_VER_SHIFT; + + return 0; +} + +U_BOOT_DRIVER(soc_xilinx_versal) = { + .name = "soc_xilinx_versal", + .id = UCLASS_SOC, + .ops = &soc_xilinx_versal_ops, + .probe = soc_xilinx_versal_probe, + .priv_auto = sizeof(struct soc_xilinx_versal_priv), + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.2.3 From 80c0d38a560cd991907340799fb55a6d75dd997f Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 10 Aug 2021 06:50:20 -0600 Subject: xilinx: common: Add function to print SoC info Add print_cpuinfo() to print SoC info like family & revision. This function depends on CONFIG_DISPLAY_CPUINFO config. Signed-off-by: T Karthik Reddy Reviewed-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 92b61d83ca4..90c87bab5cf 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "fru.h" @@ -440,3 +441,28 @@ int __maybe_unused board_fit_config_name_match(const char *name) return -1; } + +#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_ARCH_ZYNQ) +int print_cpuinfo(void) +{ + struct udevice *soc; + char name[SOC_MAX_STR_SIZE]; + int ret; + + ret = soc_get(&soc); + if (ret) { + printf("CPU: UNKNOWN\n"); + return 0; + } + + ret = soc_get_family(soc, name, SOC_MAX_STR_SIZE); + if (ret) + printf("CPU: %s\n", name); + + ret = soc_get_revision(soc, name, SOC_MAX_STR_SIZE); + if (ret) + printf("Silicon: %s\n", name); + + return 0; +} +#endif -- cgit v1.2.3 From 57b2a43607216b42b5f80451c9bf89e7214e9af9 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 10 Aug 2021 06:50:21 -0600 Subject: xilinx: Enable config to display cpuinfo Enable CONFIG_DISPLAY_CPUINFO to display SoC family & revision. Signed-off-by: T Karthik Reddy Reviewed-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 - configs/xilinx_zynqmp_virt_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index 15fa5b9900c..590a2171c11 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -16,7 +16,6 @@ CONFIG_FIT_VERBOSE=y # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_BOOTDELAY=5 CONFIG_USE_PREBOOT=y -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SYS_PROMPT="Versal> " CONFIG_CMD_BOOTMENU=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 2d06da3c4d8..b0f569f8d44 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -24,7 +24,6 @@ CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set CONFIG_USE_PREBOOT=y CONFIG_PREBOOT="run scsi_init;usb start" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_FPGA=y -- cgit v1.2.3 From a84d3b6c563445e9626d77f1504b707f054f77cf Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 1 Jul 2021 11:44:51 +0200 Subject: cmd: pwm: Remove additional pwm description The first name is taken from command name that's why shouldn't be listed in help. And commands shouldn't be listed with <> which means value but value itself is command name. Also add description for commands to make it clear what it does. Before pwm pwm pwm ... After: pwm invert - invert polarity pwm config - config PWM pwm enable - enable PWM output pwm disable - disable PWM output Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- cmd/pwm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/pwm.c b/cmd/pwm.c index 87d840a2b9b..7947e61aeed 100644 --- a/cmd/pwm.c +++ b/cmd/pwm.c @@ -108,7 +108,8 @@ static int do_pwm(struct cmd_tbl *cmdtp, int flag, int argc, U_BOOT_CMD(pwm, 6, 0, do_pwm, "control pwm channels", - "pwm \n" - "pwm \n" - "pwm \n" + "invert - invert polarity\n" + "pwm config - config PWM\n" + "pwm enable - enable PWM output\n" + "pwm disable - eisable PWM output\n" "Note: All input values are in decimal"); -- cgit v1.2.3 From aa5fb3de23dd05e6da3e3cf7fc20eea983a9dab9 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 11 Aug 2021 12:01:25 +0200 Subject: cmd: boot: Update reset usage message The commit 573a3811edc8 ("sysreset: psci: support system reset in a generic way with PSCI") has added support for warm reset via PSCI but this hasn't been reflected in usage message and user has to look at the code how to run it. That's why update usage text to make this clear. Here is full help with updated usage: ZynqMP> help reset reset - Perform RESET of the CPU Usage: reset - cold boot without level specifier reset -w - warm reset if implemented Signed-off-by: Michal Simek Reviewed-by: Igor Opaniuk --- cmd/boot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/boot.c b/cmd/boot.c index fab294e622b..be67a5980de 100644 --- a/cmd/boot.c +++ b/cmd/boot.c @@ -58,7 +58,8 @@ U_BOOT_CMD( U_BOOT_CMD( reset, 2, 0, do_reset, "Perform RESET of the CPU", - "" + "- cold boot without level specifier\n" + "reset -w - warm reset if implemented" ); #ifdef CONFIG_CMD_POWEROFF -- cgit v1.2.3 From afb08a86340872df3dfa1c918cd194f2e01c7b6c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2021 12:25:49 +0200 Subject: xilinx: zynqmp: Add debug messages for boot mode Add debug messages to see HW boot mode and also alternative boot mode in logs directly. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 27bb2b056c5..e43177ea4e4 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -518,6 +518,9 @@ static u8 __maybe_unused zynqmp_get_bootmode(void) if (ret) return -EINVAL; + debug("HW boot mode: %x\n", reg & BOOT_MODES_MASK); + debug("ALT boot mode: %x\n", reg >> BOOT_MODE_ALT_SHIFT); + if (reg >> BOOT_MODE_ALT_SHIFT) reg >>= BOOT_MODE_ALT_SHIFT; -- cgit v1.2.3 From e32d8916594cf64f38645acc860ec73ec242fe0d Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Tue, 10 Aug 2021 00:16:12 -0600 Subject: watchdog: versal: Include header file needed for dev_ functions dev_dbg, dev_err and dev_warn seems to be moved to different header file. Include dm/device_compat.h file to compile properly. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- drivers/watchdog/xilinx_wwdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c index 11b30ae85df..c8e6c60cdd2 100644 --- a/drivers/watchdog/xilinx_wwdt.c +++ b/drivers/watchdog/xilinx_wwdt.c @@ -14,6 +14,7 @@ #include #include #include +#include #include /* Refresh Register Masks */ -- cgit v1.2.3 From 57bcae88fec16291272f6e0548ff7f094f9ee796 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 4 Dec 2020 10:37:38 +0100 Subject: arm64: zynqmp: Enable sha1sum command Enable it for TPM usage. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index b0f569f8d44..ea65563a1f2 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -38,6 +38,7 @@ CONFIG_CMD_THOR_DOWNLOAD=y CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_MEMTEST=y CONFIG_SYS_ALT_MEMTEST=y +CONFIG_CMD_SHA1SUM=y CONFIG_CMD_BIND=y CONFIG_CMD_CLK=y CONFIG_CMD_DFU=y -- cgit v1.2.3 From edd530651a0045c53b18fde413db7fd8dc3693be Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 21 Jan 2021 14:02:30 +0100 Subject: xilinx: zynqmp: Enable gpio-key/button driver Enable button uclass and also gpio-key driver by default. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index ea65563a1f2..f516ab62d3c 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -89,6 +89,8 @@ CONFIG_NETCONSOLE=y CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_SCSI_AHCI=y CONFIG_SATA_CEVA=y +CONFIG_BUTTON=y +CONFIG_BUTTON_GPIO=y CONFIG_CLK_ZYNQMP=y CONFIG_DFU_TFTP=y CONFIG_DFU_TIMEOUT=y -- cgit v1.2.3 From 530560b6f8eb06f89ee6d940701a24747bf12d2b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 12 Aug 2021 11:03:49 +0200 Subject: xilinx: fru: Replace spaces with \0 in detected name FRU spec expected \0 for unused symbols but unfortunately a lot of boards are using spaces instead of \0. That's why after saving it to desc->name name is checked again and all spaces are converted to \0. This will ensure that names can be used for string manipulations like concatenation. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 90c87bab5cf..1458b31c21a 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -168,7 +168,7 @@ static bool xilinx_detect_legacy(u8 *buffer) static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, struct xilinx_board_description *desc) { - int ret, eeprom_size; + int i, ret, eeprom_size; u8 *fru_content; /* FIXME this is shortcut - if eeprom type is wrong it will fail */ @@ -207,6 +207,10 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, sizeof(desc->manufacturer)); strncpy(desc->name, (char *)fru_data.brd.product_name, sizeof(desc->name)); + for (i = 0; i < sizeof(desc->name); i++) { + if (desc->name[i] == ' ') + desc->name[i] = '\0'; + } strncpy(desc->revision, (char *)fru_data.brd.rev, sizeof(desc->revision)); strncpy(desc->serial, (char *)fru_data.brd.serial_number, -- cgit v1.2.3 From 57f710320fcd18bb5deaa9654dbce4da4de9d987 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Jul 2021 09:55:59 +0200 Subject: xilinx: Use variable for passing board_name Use variable which points to DEVICE_TREE by default. The reason for this change is to enable DTB_RESELECT and MULTI_DTB_FIT where board detection can be used for change DTB at run time. That's why there must be reference in board_fit_config_name_match() via variable instead of hardcoding it which is sufficient for that use case. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 1458b31c21a..db9705c1b7e 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -436,11 +436,13 @@ int board_late_init_xilinx(void) } #endif +static char *board_name = DEVICE_TREE; + int __maybe_unused board_fit_config_name_match(const char *name) { - debug("%s: Check %s, default %s\n", __func__, name, DEVICE_TREE); + debug("%s: Check %s, default %s\n", __func__, name, board_name); - if (!strcmp(name, DEVICE_TREE)) + if (!strcmp(name, board_name)) return 0; return -1; -- cgit v1.2.3 From d9c93c9e2c53e5b624e79b9ba244f84b5c73544b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 12 Aug 2021 12:30:36 +0200 Subject: xilinx: common: Change board_info[] handling Origin code was allocating only pointers to struct xilinx_board_description and there was separate allocation for structure self and freeing in case of failure. The code is directly allocating space for all structures by one calloc to simlify logic. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index db9705c1b7e..44c8aa5eefb 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -68,7 +68,7 @@ struct xilinx_board_description { }; static int highest_id = -1; -static struct xilinx_board_description **board_info; +static struct xilinx_board_description *board_info; #define XILINX_I2C_DETECTION_BITS sizeof(struct fru_common_hdr) @@ -280,7 +280,7 @@ static int xilinx_read_eeprom_single(char *name, __maybe_unused int xilinx_read_eeprom(void) { - int id, ret; + int id; char name_buf[8]; /* 8 bytes should be enough for nvmem+number */ struct xilinx_board_description *desc; @@ -289,7 +289,7 @@ __maybe_unused int xilinx_read_eeprom(void) if (highest_id < 0) return -EINVAL; - board_info = calloc(1, sizeof(desc) * highest_id); + board_info = calloc(1, sizeof(*desc) * (highest_id + 1)); if (!board_info) return -ENOMEM; @@ -300,21 +300,10 @@ __maybe_unused int xilinx_read_eeprom(void) snprintf(name_buf, sizeof(name_buf), "nvmem%d", id); /* Alloc structure */ - desc = board_info[id]; - if (!desc) { - desc = calloc(1, sizeof(*desc)); - if (!desc) - return -ENOMEM; - - board_info[id] = desc; - } + desc = &board_info[id]; /* Ignoring return value for supporting multiple chips */ - ret = xilinx_read_eeprom_single(name_buf, desc); - if (ret) { - free(desc); - board_info[id] = NULL; - } + xilinx_read_eeprom_single(name_buf, desc); } /* @@ -400,7 +389,7 @@ int board_late_init_xilinx(void) ret |= env_set_addr("bootm_size", (void *)bootm_size); for (id = 0; id <= highest_id; id++) { - desc = board_info[id]; + desc = &board_info[id]; if (desc && desc->header == EEPROM_HEADER_MAGIC) { if (desc->manufacturer[0]) ret |= env_set_by_index("manufacturer", id, -- cgit v1.2.3 From b262863bf8881542b7fad73563b3d6827df3f4b7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 13 Aug 2021 09:17:10 +0200 Subject: xilinx: common: Free allocated structure There is no need to keep fru_content around. Free this space. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 44c8aa5eefb..2aecb14d8e2 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -185,8 +185,7 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, eeprom_size); if (ret) { debug("%s: I2C EEPROM read failed\n", __func__); - free(fru_content); - return ret; + goto end; } printf("Xilinx I2C FRU format at %s:\n", name); @@ -194,12 +193,13 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, ret = fru_display(0); if (ret) { printf("FRU format decoding failed.\n"); - return ret; + goto end; } if (desc->header == EEPROM_HEADER_MAGIC) { debug("Information already filled\n"); - return -EINVAL; + ret = -EINVAL; + goto end; } /* It is clear that FRU was captured and structures were filled */ @@ -217,7 +217,9 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, sizeof(desc->serial)); desc->header = EEPROM_HEADER_MAGIC; - return 0; +end: + free(fru_content); + return ret; } static bool xilinx_detect_fru(u8 *buffer) -- cgit v1.2.3 From 88232532728c91d69a1f5efb219f6cd7fc030461 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Jul 2021 09:59:59 +0200 Subject: xilinx: Add support for generic board detection Add support for changing DT at run time. It is done via board_detection() which returns platform_id and platform_version which can be used via board_name_decode() to compose board_local_name string which corresponds with DT which is should be used. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 2aecb14d8e2..92874272893 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -463,3 +463,34 @@ int print_cpuinfo(void) return 0; } #endif + +#if CONFIG_IS_ENABLED(DTB_RESELECT) +char * __maybe_unused __weak board_name_decode(void) +{ + return NULL; +} + +bool __maybe_unused __weak board_detection(void) +{ + return false; +} + +int embedded_dtb_select(void) +{ + if (board_detection()) { + char *board_local_name; + + board_local_name = board_name_decode(); + if (board_local_name) { + board_name = board_local_name; + debug("Detected name: %s\n", board_name); + + /* Time to change DTB on fly */ + /* Both ways should work here */ + /* fdtdec_resetup(&rescan); */ + fdtdec_setup(); + } + } + return 0; +} +#endif -- cgit v1.2.3 From 5bd5ee02b23be2062c5e0c194355534eaa7e7854 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Aug 2021 11:07:59 +0200 Subject: xilinx: zynqmp: Check that DT is 64bit aligned DT needs to be 64bit aligned. If it is not fdt64_to_cpu will fail when try to read information about reserved memory. The system ends in exception without any clue what's going it. That's why detect not aligned DT and panic to show where the issue is coming from. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index e43177ea4e4..ea15e62eb21 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -470,6 +470,9 @@ ulong board_get_usable_ram_top(ulong total_size) phys_addr_t reg; struct lmb lmb; + if (!IS_ALIGNED((ulong)gd->fdt_blob, 0x8)) + panic("Not 64bit aligned DT location: %p\n", gd->fdt_blob); + /* found enough not-reserved memory to relocated U-Boot */ lmb_init(&lmb); lmb_add(&lmb, gd->ram_base, gd->ram_size); -- cgit v1.2.3 From 570c4636808e77a18ccd8865b2654fff08f13328 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Aug 2021 11:09:37 +0200 Subject: Makefile: Align fit-dtb.blob and u-boot.itb by 64bits Enabling MULTI_DTB_FIT and DTB_RESELECT can end up with multi DTBs in FIT image placed and aligned only by 32bits (4bytes). Based on device tree specification: "Specifically, the memory reservation block shall be aligned to an 8-byte boundary and the structure block to a 4-byte boundary." is 64bit (8bytes) alignment required. That's why make sure that fit-dtb.blob and u-boot.itb as our primary target images for Xilinx ZynqMP are all 64bit aligned. Signed-off-by: Michal Simek Reviewed-by: Andre Przywara --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 269e353a28a..0de909123cf 100644 --- a/Makefile +++ b/Makefile @@ -1169,6 +1169,8 @@ MKIMAGEFLAGS_fit-dtb.blob = -f auto -A $(ARCH) -T firmware -C none -O u-boot \ -a 0 -e 0 -E \ $(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) -d /dev/null +MKIMAGEFLAGS_fit-dtb.blob += -B 0x8 + ifneq ($(EXT_DTB),) u-boot-fit-dtb.bin: u-boot-nodtb.bin $(EXT_DTB) $(call if_changed,cat) @@ -1431,6 +1433,7 @@ MKIMAGEFLAGS_u-boot.itb = else MKIMAGEFLAGS_u-boot.itb = -E endif +MKIMAGEFLAGS_u-boot.itb += -B 0x8 ifdef U_BOOT_ITS u-boot.itb: u-boot-nodtb.bin \ -- cgit v1.2.3 From f28a22d55a5d2f08ad4befb5f27fd00eebc2b85d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Aug 2021 11:29:41 +0200 Subject: arm64: dts: Make sure that all DTBs are 64bit aligned Start of DTB should be 64bit aligned that's why also make sure that end is also 64bit aligned. It is not required but it is nice thing to do. Signed-off-by: Michal Simek --- arch/arm/dts/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 537c96bf5b3..4d60022e43c 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1127,7 +1127,7 @@ dtb-$(CONFIG_TARGET_EA_LPC3250DEVKITV2) += lpc3250-ea3250.dtb targets += $(dtb-y) # Add any required device tree compiler flags here -DTC_FLAGS += +DTC_FLAGS += -a 0x8 PHONY += dtbs dtbs: $(addprefix $(obj)/, $(dtb-y)) -- cgit v1.2.3 From e69213611ea74e9c40ef0454142a1f6dc5589268 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Aug 2021 12:02:57 +0200 Subject: xilinx: zynqmp: Generate different u-boot.itb for MULTI_DTB_FIT When MULTI_DTB_FIT is enabled fit-dtb.blob fit image is created which contain all DTBs listed by CONFIG_OF_LIST. And with DTB_RELESELECT there is a need to handle it as one file with DTBs in it not as separate DTBs in u-boot.its/itb. That's why extend mkimage_fit_atf.sh to generate u-boot.itb correctly. Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/mkimage_fit_atf.sh | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/arm/mach-zynqmp/mkimage_fit_atf.sh b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh index 592be7f6706..feb3a6260a3 100755 --- a/arch/arm/mach-zynqmp/mkimage_fit_atf.sh +++ b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh @@ -111,6 +111,51 @@ cat << __TEE __TEE fi +MULTI_DTB=`awk '/CONFIG_MULTI_DTB_FIT / { print $3 }' include/generated/autoconf.h` + +if [ 1"$MULTI_DTB" -eq 11 ]; then + cat << __FDT_IMAGE_EOF + fdt_1 { + description = "Multi DTB fit image"; + data = /incbin/("fit-dtb.blob"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + $DTB_LOAD + hash { + algo = "md5"; + }; + }; + }; + configurations { + default = "config_1"; +__FDT_IMAGE_EOF + +if [ ! -f $BL31 ]; then +cat << __CONF_SECTION1_EOF + config_1 { + description = "Multi DTB without TF-A"; + firmware = "uboot"; + loadables = "fdt_1"; + }; +__CONF_SECTION1_EOF +else +cat << __CONF_SECTION1_EOF + config_1 { + description = "Multi DTB with TF-A"; + firmware = "atf"; + loadables = "uboot", "fdt_1"; + }; +__CONF_SECTION1_EOF +fi + +cat << __ITS_EOF + }; +}; +__ITS_EOF + +else + DEFAULT=1 cnt=1 for dtname in $DT @@ -181,3 +226,5 @@ cat << __ITS_EOF }; }; __ITS_EOF + +fi -- cgit v1.2.3 From 52ff1626cf4c414c7a2423c443618017eb6e773c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 11 Aug 2021 14:23:54 +0200 Subject: xilinx: common: Enabling generic function for DT reselection U-Boot support board detection at run time and based on it change DT. This feature is implemented for SOM Kria platforms which contain two eeproms which contain information about SOM module and CC (Carrier card). Full U-Boot starts with minimal DT file defined by CONFIG_DEFAULT_DEVICE_TREE which is available in multi DTB fit image. It is using default setup of board_name variable initializaed to DEVICE_TREE which corresponds to CONFIG_DEFAULT_DEVICE_TREE option. When DTB_RESELECT is enabled board_detection() is called. Keep it your mind that this code is called before relocation. board_detection() is calling xilinx_read_eeprom() which fills board_info (xilinx_board_description) structure which are parsed in board_name_decode(). Based on DT configuration and amount of nvmemX aliases name of the board is composed by concatenating CONFIG_SYS_BOARD "-" "-rev" "-" "-rev" . If CC is not present or more are available it keeps going. When board name is composed and returned from board_name_decode() it is assigned to board_name variable which is used by board_fit_config_name_match() which is called via fdtdec_setup() when it goes over config options in multi dtb FIT image. From practical point of view multi DTB image is key point here which has to contain configs for detected combinations. Unfortunately as of now they have to be full DTBs and DTBOs are not supported. That's why configuration like: config_X { description = "zynqmp-board-cc"; fdt = "board", "cc"; }; needs to be squashed together with: fdtoverlay -o zynqmp-board-cc -i arch/arm/dts/zynqmp-board.dtb \ arch/arm/dts/zynqmp-cc.dtbo and only one dtb is in fit: config_X { description = "zynqmp-board-cc"; fdt = "board-cc"; }; For creating multi DTBs fit image use mkimage -E, e.g.: mkimage -E -f all.its all.dtb When DTB_RESELECT is enabled xilinx_read_eeprom() is called before relocation and it uses calloc for getting a buffer. Because this is dynamic memory it is not relocated that's why xilinx_read_eeprom() is called again as the part of board_init(). This second read with calloc buffer placed in proper position board_late_init_xilinx() can setup u-boot variables as before. Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-sm-k26-revA.dts | 3 ++ board/xilinx/common/board.c | 84 ++++++++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/arch/arm/dts/zynqmp-sm-k26-revA.dts b/arch/arm/dts/zynqmp-sm-k26-revA.dts index e274100a9bc..5f55df28f33 100644 --- a/arch/arm/dts/zynqmp-sm-k26-revA.dts +++ b/arch/arm/dts/zynqmp-sm-k26-revA.dts @@ -204,17 +204,20 @@ &i2c1 { status = "okay"; + u-boot,dm-pre-reloc; clock-frequency = <400000>; scl-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; sda-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>; eeprom: eeprom@50 { /* u46 - also at address 0x58 */ + u-boot,dm-pre-reloc; compatible = "st,24c64", "atmel,24c64"; /* st m24c64 */ reg = <0x50>; /* WP pin EE_WP_EN connected to slg7x644092@68 */ }; eeprom_cc: eeprom@51 { /* required by spec - also at address 0x59 */ + u-boot,dm-pre-reloc; compatible = "st,24c64", "atmel,24c64"; /* st m24c64 */ reg = <0x51>; }; diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 92874272893..9006bd3b4d2 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "fru.h" @@ -188,12 +189,14 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, goto end; } - printf("Xilinx I2C FRU format at %s:\n", name); fru_capture((unsigned long)fru_content); - ret = fru_display(0); - if (ret) { - printf("FRU format decoding failed.\n"); - goto end; + if (gd->flags & GD_FLG_RELOC || (_DEBUG && CONFIG_IS_ENABLED(DTB_RESELECT))) { + printf("Xilinx I2C FRU format at %s:\n", name); + ret = fru_display(0); + if (ret) { + printf("FRU format decoding failed.\n"); + goto end; + } } if (desc->header == EEPROM_HEADER_MAGIC) { @@ -465,13 +468,82 @@ int print_cpuinfo(void) #endif #if CONFIG_IS_ENABLED(DTB_RESELECT) +#define MAX_NAME_LENGTH 50 + char * __maybe_unused __weak board_name_decode(void) { + char *board_local_name; + struct xilinx_board_description *desc; + int i, id; + + board_local_name = calloc(1, MAX_NAME_LENGTH); + if (!board_info) + return NULL; + + for (id = 0; id <= highest_id; id++) { + desc = &board_info[id]; + + /* No board description */ + if (!desc) + goto error; + + /* Board is not detected */ + if (desc->header != EEPROM_HEADER_MAGIC) + continue; + + /* The first string should be soc name */ + if (!id) + strcat(board_local_name, CONFIG_SYS_BOARD); + + /* + * For two purpose here: + * soc_name- eg: zynqmp- + * and between base board and CC eg: ..revA-sck... + */ + strcat(board_local_name, "-"); + + if (desc->name[0]) { + /* For DT composition name needs to be lowercase */ + for (i = 0; i < sizeof(desc->name); i++) + desc->name[i] = tolower(desc->name[i]); + + strcat(board_local_name, desc->name); + } + if (desc->revision[0]) { + strcat(board_local_name, "-rev"); + + /* And revision needs to be uppercase */ + for (i = 0; i < sizeof(desc->revision); i++) + desc->revision[i] = toupper(desc->revision[i]); + + strcat(board_local_name, desc->revision); + } + } + + /* + * Longer strings will end up with buffer overflow and potential + * attacks that's why check it + */ + if (strlen(board_local_name) >= MAX_NAME_LENGTH) + panic("Board name can't be determined\n"); + + if (strlen(board_local_name)) + return board_local_name; + +error: + free(board_local_name); return NULL; } bool __maybe_unused __weak board_detection(void) { + if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM)) { + int ret; + + ret = xilinx_read_eeprom(); + return !ret ? true : false; + } + return false; } @@ -483,7 +555,7 @@ int embedded_dtb_select(void) board_local_name = board_name_decode(); if (board_local_name) { board_name = board_local_name; - debug("Detected name: %s\n", board_name); + printf("Detected name: %s\n", board_name); /* Time to change DTB on fly */ /* Both ways should work here */ -- cgit v1.2.3 From 060fa0e11bde87a22898b2c152b701e25dcfe0db Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Aug 2021 14:17:37 +0200 Subject: xilinx: zynqmp: Update descriptions for u-boot.its Use TF-A instead of ATF in description. And update generic description with removing ATF because also configurations without it are supported. Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/mkimage_fit_atf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-zynqmp/mkimage_fit_atf.sh b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh index feb3a6260a3..72a8a3eb771 100755 --- a/arch/arm/mach-zynqmp/mkimage_fit_atf.sh +++ b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh @@ -57,7 +57,7 @@ cat << __HEADER_EOF /dts-v1/; / { - description = "Configuration to load ATF before U-Boot"; + description = "Configuration for Xilinx ZynqMP SoC"; images { uboot { @@ -78,7 +78,7 @@ __HEADER_EOF if [ -f $BL31 ]; then cat << __ATF atf { - description = "ARM Trusted Firmware"; + description = "Trusted Firmware-A"; data = /incbin/("$BL31"); type = "firmware"; os = "arm-trusted-firmware"; -- cgit v1.2.3 From 229cb5c6ba3469cbc4a0bcc69389fe61c51fd3b4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 24 Aug 2021 14:56:47 +0200 Subject: xilinx: zynqmp: Enable stack relocation to DDR There is no space in OCM for SPL stack because the space in OCM is occupied by TF-A. That's why move relocate stack to DDR to 0x18000000 address and also enable SPL_SIZE_LIMIT not to be more then 0xfffea000 which is default address for TFA. It is good to summarize current DDR usage in SPL flow. 0-0x80000 is used for BSS (CONFIG_SPL_BSS_START_ADDR, CONFIG_SPL_BSS_MAX_SIZE) 0x100000 is used for DTB passing address (CONFIG_XILINX_OF_BOARD_DTB_ADDR) 0x17fffe70 - CONFIG_SPL_STACK_R_ADDR - is used for GD 0x18000000 is used for SPL stack (CONFIG_SPL_STACK_R_ADDR) 0x20000000-0x21000000 is used for SPL malloc area (CONFIG_SYS_SPL_MALLOC_START, CONFIG_SYS_SPL_MALLOC_SIZE) Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index f516ab62d3c..7ccce6f541c 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -8,6 +8,9 @@ CONFIG_SYS_MEMTEST_END=0x00001000 CONFIG_SYS_SPI_U_BOOT_OFFS=0x100000 CONFIG_DM_GPIO=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu100-revC" +CONFIG_SPL_STACK_R_ADDR=0x18000000 +CONFIG_SPL_SIZE_LIMIT=0x2a000 +CONFIG_SPL_SIZE_LIMIT_PROVIDE_STACK=0x0 CONFIG_SPL=y CONFIG_SPL_SPI_FLASH_SUPPORT=y CONFIG_SPL_SPI_SUPPORT=y @@ -26,6 +29,7 @@ CONFIG_USE_PREBOOT=y CONFIG_PREBOOT="run scsi_init;usb start" CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_EARLY_INIT_R=y +CONFIG_SPL_STACK_R=y CONFIG_SPL_FPGA=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y -- cgit v1.2.3