From 57213c5f3711254934736637b59989c9b7ba7f2b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Apr 2018 12:36:48 +0200 Subject: [PATCH 01/31] arm: zynq: Enable debug_uart_init in spl when enabled In past this code was commented and was used for debug purpose. But there is no reason not to enabled it based on macros. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/spl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index 48e3d8d..83297d6 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -17,11 +17,12 @@ void board_init_f(ulong dummy) ps7_init(); arch_cpu_init(); - /* - * The debug UART can be used from this point: - * debug_uart_init(); - * printch('x'); - */ + +#ifdef CONFIG_DEBUG_UART + /* Uart debug for sure */ + debug_uart_init(); + puts("Debug uart enabled\n"); /* or printch() */ +#endif } #ifdef CONFIG_SPL_BOARD_INIT From 4aba5fb857c1b0067226dbd457d51ac2b2825427 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 17 Jan 2018 10:56:22 -0300 Subject: [PATCH 02/31] arm: zynq: Rework FPGA initialization This commit moves the FPGA descriptor definition to mach-zynq, where it makes more sense. Based on patches from Ariel D'Alessandro and Ezequiel Garcia Signed-off-by: Michal Simek --- arch/arm/Kconfig | 1 + arch/arm/mach-zynq/cpu.c | 66 +++++++++++++++++++++++++++++- board/xilinx/zynq/board.c | 63 ----------------------------- configs/zynq_cse_qspi_defconfig | 1 + include/zynqpl.h | 89 ++++++++++++++++------------------------- 5 files changed, 101 insertions(+), 119 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2bbb86c..a7618f9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -821,6 +821,7 @@ config ARCH_ZYNQ imply CMD_CLK imply FAT_WRITE imply CMD_SPL + imply ARCH_EARLY_INIT_R config ARCH_ZYNQMP bool "Xilinx ZynqMP based platform" diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index df4eec8..7853785 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -4,14 +4,45 @@ * Copyright (C) 2012 Xilinx, Inc. All rights reserved. */ #include +#include #include #include -#include #include +#include +#include #define ZYNQ_SILICON_VER_MASK 0xF0000000 #define ZYNQ_SILICON_VER_SHIFT 28 +#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ + (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) +xilinx_desc fpga = { + .family = xilinx_zynq, + .iface = devcfg, + .operations = &zynq_op, +}; +#endif + +static const struct { + u8 idcode; +#if defined(CONFIG_FPGA) + u32 fpga_size; +#endif + char *devicename; +} zynq_fpga_descs[] = { + ZYNQ_DESC(7Z007S), + ZYNQ_DESC(7Z010), + ZYNQ_DESC(7Z012S), + ZYNQ_DESC(7Z014S), + ZYNQ_DESC(7Z015), + ZYNQ_DESC(7Z020), + ZYNQ_DESC(7Z030), + ZYNQ_DESC(7Z035), + ZYNQ_DESC(7Z045), + ZYNQ_DESC(7Z100), + { /* Sentinel */ }, +}; + int arch_cpu_init(void) { zynq_slcr_unlock(); @@ -59,3 +90,36 @@ void enable_caches(void) dcache_enable(); } #endif + +static int __maybe_unused cpu_desc_id(void) +{ + u32 idcode; + u8 i; + + idcode = zynq_slcr_get_idcode(); + for (i = 0; zynq_fpga_descs[i].idcode; i++) { + if (zynq_fpga_descs[i].idcode == idcode) + return i; + } + + return -ENODEV; +} + +#if defined(CONFIG_ARCH_EARLY_INIT_R) +int arch_early_init_r(void) +{ +#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ + (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) + int cpu_id = cpu_desc_id(); + + if (cpu_id < 0) + return 0; + + fpga.size = zynq_fpga_descs[cpu_id].fpga_size; + fpga.name = zynq_fpga_descs[cpu_id].devicename; + fpga_init(); + fpga_add(fpga_xilinx, &fpga); +#endif + return 0; +} +#endif diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index fe36cf7..e58c587 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -17,23 +17,6 @@ DECLARE_GLOBAL_DATA_PTR; -#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) -static xilinx_desc fpga; - -/* It can be done differently */ -static xilinx_desc fpga007s = XILINX_XC7Z007S_DESC(0x7); -static xilinx_desc fpga010 = XILINX_XC7Z010_DESC(0x10); -static xilinx_desc fpga012s = XILINX_XC7Z012S_DESC(0x12); -static xilinx_desc fpga014s = XILINX_XC7Z014S_DESC(0x14); -static xilinx_desc fpga015 = XILINX_XC7Z015_DESC(0x15); -static xilinx_desc fpga020 = XILINX_XC7Z020_DESC(0x20); -static xilinx_desc fpga030 = XILINX_XC7Z030_DESC(0x30); -static xilinx_desc fpga035 = XILINX_XC7Z035_DESC(0x35); -static xilinx_desc fpga045 = XILINX_XC7Z045_DESC(0x45); -static xilinx_desc fpga100 = XILINX_XC7Z100_DESC(0x100); -#endif - #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) static struct udevice *watchdog_dev; #endif @@ -52,46 +35,6 @@ int board_early_init_f(void) int board_init(void) { -#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) - u32 idcode; - - idcode = zynq_slcr_get_idcode(); - - switch (idcode) { - case XILINX_ZYNQ_7007S: - fpga = fpga007s; - break; - case XILINX_ZYNQ_7010: - fpga = fpga010; - break; - case XILINX_ZYNQ_7012S: - fpga = fpga012s; - break; - case XILINX_ZYNQ_7014S: - fpga = fpga014s; - break; - case XILINX_ZYNQ_7015: - fpga = fpga015; - break; - case XILINX_ZYNQ_7020: - fpga = fpga020; - break; - case XILINX_ZYNQ_7030: - fpga = fpga030; - break; - case XILINX_ZYNQ_7035: - fpga = fpga035; - break; - case XILINX_ZYNQ_7045: - fpga = fpga045; - break; - case XILINX_ZYNQ_7100: - fpga = fpga100; - break; - } -#endif - #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { puts("Watchdog: Not found!\n"); @@ -101,12 +44,6 @@ int board_init(void) } # endif -#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) - fpga_init(); - fpga_add(fpga_xilinx, &fpga); -#endif - return 0; } diff --git a/configs/zynq_cse_qspi_defconfig b/configs/zynq_cse_qspi_defconfig index 9d4c79f..88049d2 100644 --- a/configs/zynq_cse_qspi_defconfig +++ b/configs/zynq_cse_qspi_defconfig @@ -12,6 +12,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=-1 # CONFIG_USE_BOOTCOMMAND is not set # CONFIG_DISPLAY_CPUINFO is not set +# CONFIG_ARCH_EARLY_INIT_R is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/include/zynqpl.h b/include/zynqpl.h index 9c63c01..cdfd8a2 100644 --- a/include/zynqpl.h +++ b/include/zynqpl.h @@ -11,23 +11,18 @@ #include -#if defined(CONFIG_FPGA_ZYNQPL) extern struct xilinx_fpga_op zynq_op; -# define FPGA_ZYNQPL_OPS &zynq_op -#else -# define FPGA_ZYNQPL_OPS NULL -#endif -#define XILINX_ZYNQ_7007S 0x3 -#define XILINX_ZYNQ_7010 0x2 -#define XILINX_ZYNQ_7012S 0x1c -#define XILINX_ZYNQ_7014S 0x8 -#define XILINX_ZYNQ_7015 0x1b -#define XILINX_ZYNQ_7020 0x7 -#define XILINX_ZYNQ_7030 0xc -#define XILINX_ZYNQ_7035 0x12 -#define XILINX_ZYNQ_7045 0x11 -#define XILINX_ZYNQ_7100 0x16 +#define XILINX_ZYNQ_XC7Z007S 0x3 +#define XILINX_ZYNQ_XC7Z010 0x2 +#define XILINX_ZYNQ_XC7Z012S 0x1c +#define XILINX_ZYNQ_XC7Z014S 0x8 +#define XILINX_ZYNQ_XC7Z015 0x1b +#define XILINX_ZYNQ_XC7Z020 0x7 +#define XILINX_ZYNQ_XC7Z030 0xc +#define XILINX_ZYNQ_XC7Z035 0x12 +#define XILINX_ZYNQ_XC7Z045 0x11 +#define XILINX_ZYNQ_XC7Z100 0x16 /* Device Image Sizes */ #define XILINX_XC7Z007S_SIZE 16669920/8 @@ -41,45 +36,29 @@ extern struct xilinx_fpga_op zynq_op; #define XILINX_XC7Z045_SIZE 106571232/8 #define XILINX_XC7Z100_SIZE 139330784/8 -/* Descriptor Macros */ -#define XILINX_XC7Z007S_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z007S_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z007s" } - -#define XILINX_XC7Z010_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z010_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z010" } - -#define XILINX_XC7Z012S_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z012S_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z012s" } - -#define XILINX_XC7Z014S_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z014S_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z014s" } - -#define XILINX_XC7Z015_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z015_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z015" } - -#define XILINX_XC7Z020_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z020_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z020" } - -#define XILINX_XC7Z030_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z030_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z030" } - -#define XILINX_XC7Z035_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z035_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z035" } - -#define XILINX_XC7Z045_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z045_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z045" } - -#define XILINX_XC7Z100_DESC(cookie) \ -{ xilinx_zynq, devcfg, XILINX_XC7Z100_SIZE, NULL, cookie, FPGA_ZYNQPL_OPS, \ - "7z100" } +/* Device Names */ +#define XILINX_XC7Z007S_NAME "7z007s" +#define XILINX_XC7Z010_NAME "7z010" +#define XILINX_XC7Z012S_NAME "7z012s" +#define XILINX_XC7Z014S_NAME "7z014s" +#define XILINX_XC7Z015_NAME "7z015" +#define XILINX_XC7Z020_NAME "7z020" +#define XILINX_XC7Z030_NAME "7z030" +#define XILINX_XC7Z035_NAME "7z035" +#define XILINX_XC7Z045_NAME "7z045" +#define XILINX_XC7Z100_NAME "7z100" + +#if defined(CONFIG_FPGA) +#define ZYNQ_DESC(name) { \ + .idcode = XILINX_ZYNQ_XC##name, \ + .fpga_size = XILINX_XC##name##_SIZE, \ + .devicename = XILINX_XC##name##_NAME \ + } +#else +#define ZYNQ_DESC(name) { \ + .idcode = XILINX_ZYNQ_XC##name, \ + .devicename = XILINX_XC##name##_NAME \ + } +#endif #endif /* _ZYNQPL_H_ */ From 0b4b82ad1461cc37434e7e0c1de00a61193a95db Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Feb 2018 09:50:07 +0100 Subject: [PATCH 03/31] arm: zynq: Remove checkboard and enable DISPLAY_CPUINFO Now that showing silicon version is part of the CPU info display, let's remove checkboard(). Note that the generic show_board_info() will still show the DT 'model' property. For instance: U-Boot 2018.05-rc2-00025-g611b3ee0159b (Apr 19 2018 - 11:23:12 +0200) CPU: Zynq 7z045 Silicon: v1.0 Model: Zynq ZC706 Development Board I2C: ready Based on patches from Ariel D'Alessandro , and Ezequiel Garcia mini configuration doesn't need to show this information. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/cpu.c | 19 +++++++++++++++++++ board/xilinx/zynq/board.c | 17 ----------------- configs/syzygy_hub_defconfig | 1 - configs/topic_miami_defconfig | 1 - configs/topic_miamilite_defconfig | 1 - configs/topic_miamiplus_defconfig | 1 - configs/zynq_cc108_defconfig | 1 - configs/zynq_microzed_defconfig | 1 - configs/zynq_picozed_defconfig | 1 - configs/zynq_z_turn_defconfig | 1 - configs/zynq_zc702_defconfig | 1 - configs/zynq_zc706_defconfig | 1 - configs/zynq_zc770_xm010_defconfig | 1 - configs/zynq_zc770_xm011_defconfig | 1 - configs/zynq_zc770_xm011_x16_defconfig | 1 - configs/zynq_zc770_xm012_defconfig | 1 - configs/zynq_zc770_xm013_defconfig | 1 - configs/zynq_zed_defconfig | 1 - configs/zynq_zybo_defconfig | 1 - 19 files changed, 19 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index 7853785..a3422cd 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -123,3 +123,22 @@ int arch_early_init_r(void) return 0; } #endif + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + u32 version; + int cpu_id = cpu_desc_id(); + + if (cpu_id < 0) + return 0; + + version = zynq_get_silicon_version() << 1; + if (version > (PCW_SILICON_VERSION_3 << 1)) + version += 1; + + printf("CPU: Zynq %s\n", zynq_fpga_descs[cpu_id].devicename); + printf("Silicon: v%d.%d\n", version >> 1, version & 1); + return 0; +} +#endif diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index e58c587..e4f86d1 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -13,7 +13,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -73,22 +72,6 @@ int board_late_init(void) return 0; } -#ifdef CONFIG_DISPLAY_BOARDINFO -int checkboard(void) -{ - u32 version = zynq_get_silicon_version(); - - version <<= 1; - if (version > (PCW_SILICON_VERSION_3 << 1)) - version += 1; - - puts("Board: Xilinx Zynq\n"); - printf("Silicon: v%d.%d\n", version >> 1, version & 1); - - return 0; -} -#endif - int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) { #if defined(CONFIG_ZYNQ_GEM_EEPROM_ADDR) && \ diff --git a/configs/syzygy_hub_defconfig b/configs/syzygy_hub_defconfig index aef21a8..4ceff11 100644 --- a/configs/syzygy_hub_defconfig +++ b/configs/syzygy_hub_defconfig @@ -13,7 +13,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/topic_miami_defconfig b/configs/topic_miami_defconfig index 1619df3..7ea09ac 100644 --- a/configs/topic_miami_defconfig +++ b/configs/topic_miami_defconfig @@ -11,7 +11,6 @@ CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=0 CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_PROMPT="zynq-uboot> " diff --git a/configs/topic_miamilite_defconfig b/configs/topic_miamilite_defconfig index 5e55ebd..d30843c 100644 --- a/configs/topic_miamilite_defconfig +++ b/configs/topic_miamilite_defconfig @@ -11,7 +11,6 @@ CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=0 CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_PROMPT="zynq-uboot> " diff --git a/configs/topic_miamiplus_defconfig b/configs/topic_miamiplus_defconfig index 39cdb22..9710d95 100644 --- a/configs/topic_miamiplus_defconfig +++ b/configs/topic_miamiplus_defconfig @@ -11,7 +11,6 @@ CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTDELAY=0 CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_PROMPT="zynq-uboot> " diff --git a/configs/zynq_cc108_defconfig b/configs/zynq_cc108_defconfig index f161cf8..7689a21 100644 --- a/configs/zynq_cc108_defconfig +++ b/configs/zynq_cc108_defconfig @@ -11,7 +11,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig index 34939fa..48f223b 100644 --- a/configs/zynq_microzed_defconfig +++ b/configs/zynq_microzed_defconfig @@ -10,7 +10,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_picozed_defconfig b/configs/zynq_picozed_defconfig index 6a841f8..0136502 100644 --- a/configs/zynq_picozed_defconfig +++ b/configs/zynq_picozed_defconfig @@ -6,7 +6,6 @@ CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_DEFAULT_DEVICE_TREE="zynq-picozed" CONFIG_DISTRO_DEFAULTS=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_z_turn_defconfig b/configs/zynq_z_turn_defconfig index c2c478d..c5301d4 100644 --- a/configs/zynq_z_turn_defconfig +++ b/configs/zynq_z_turn_defconfig @@ -11,7 +11,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zc702_defconfig b/configs/zynq_zc702_defconfig index c23dd8f..58b9c30 100644 --- a/configs/zynq_zc702_defconfig +++ b/configs/zynq_zc702_defconfig @@ -13,7 +13,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig index 00042c1..8257614 100644 --- a/configs/zynq_zc706_defconfig +++ b/configs/zynq_zc706_defconfig @@ -13,7 +13,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig index 7713e5a..d6811bb 100644 --- a/configs/zynq_zc770_xm010_defconfig +++ b/configs/zynq_zc770_xm010_defconfig @@ -12,7 +12,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zc770_xm011_defconfig b/configs/zynq_zc770_xm011_defconfig index 3c394bf..1602bce 100644 --- a/configs/zynq_zc770_xm011_defconfig +++ b/configs/zynq_zc770_xm011_defconfig @@ -13,7 +13,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_zc770_xm011_x16_defconfig b/configs/zynq_zc770_xm011_x16_defconfig index 447cc62..37b4c42 100644 --- a/configs/zynq_zc770_xm011_x16_defconfig +++ b/configs/zynq_zc770_xm011_x16_defconfig @@ -13,7 +13,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig index 0a78830..275bb33 100644 --- a/configs/zynq_zc770_xm012_defconfig +++ b/configs/zynq_zc770_xm012_defconfig @@ -12,7 +12,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_PROMPT="Zynq> " diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig index 6659218..e83222d 100644 --- a/configs/zynq_zc770_xm013_defconfig +++ b/configs/zynq_zc770_xm013_defconfig @@ -12,7 +12,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index 13898b3..9ab54ec 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -11,7 +11,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 771d8ca..efb99b5 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -12,7 +12,6 @@ CONFIG_FIT_SIGNATURE=y CONFIG_FIT_VERBOSE=y CONFIG_IMAGE_FORMAT_LEGACY=y CONFIG_BOOTCOMMAND="run $modeboot || run distro_bootcmd" -# CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_STACK_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y From c3898a8891883f1ec3b7c029054927e7be9369a7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Apr 2018 13:32:52 +0200 Subject: [PATCH 04/31] scsi: ceva: Convert driver to use UCLASS_AHCI instead of SCSI In v2018 the patch "dm: ahci: Correct uclass private data" (sha1: bfc1c6b4838501d10aa48c0e92eaf70976f4b2dd) was causing an issue for ceva_sata. But this issue is not in v2018.05-rc1 but still converting to UCLASS_AHCI would make more sense. Signed-off-by: Michal Simek --- drivers/ata/sata_ceva.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c index 1544097..a7d45e8 100644 --- a/drivers/ata/sata_ceva.c +++ b/drivers/ata/sata_ceva.c @@ -72,6 +72,10 @@ #define DRV_NAME "ahci-ceva" #define CEVA_FLAG_BROKEN_GEN2 1 +struct ceva_sata_priv { + ulong base; +}; + static int ceva_init_sata(ulong mmio) { ulong tmp; @@ -110,18 +114,20 @@ static int ceva_init_sata(ulong mmio) return 0; } -static int sata_ceva_probe(struct udevice *dev) +static int sata_ceva_bind(struct udevice *dev) { - int ret; - struct scsi_platdata *plat = dev_get_uclass_platdata(dev); + struct udevice *scsi_dev; + + return ahci_bind_scsi(dev, &scsi_dev); +} - ceva_init_sata(plat->base); +static int sata_ceva_probe(struct udevice *dev) +{ + struct ceva_sata_priv *priv = dev_get_priv(dev); - ret = ahci_init_one_dm(dev); - if (ret) - return ret; + ceva_init_sata(priv->base); - return ahci_start_ports_dm(dev); + return ahci_probe_scsi(dev, priv->base); } static const struct udevice_id sata_ceva_ids[] = { @@ -131,24 +137,22 @@ static const struct udevice_id sata_ceva_ids[] = { static int sata_ceva_ofdata_to_platdata(struct udevice *dev) { - struct scsi_platdata *plat = dev_get_uclass_platdata(dev); + struct ceva_sata_priv *priv = dev_get_priv(dev); - plat->base = devfdt_get_addr(dev); - if (plat->base == FDT_ADDR_T_NONE) + priv->base = devfdt_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; - /* Hardcode number for ceva sata controller */ - plat->max_lun = 1; /* Actually two but untested */ - plat->max_id = 2; - return 0; } U_BOOT_DRIVER(ceva_host_blk) = { .name = "ceva_sata", - .id = UCLASS_SCSI, + .id = UCLASS_AHCI, .of_match = sata_ceva_ids, + .bind = sata_ceva_bind, .ops = &scsi_ops, + .priv_auto_alloc_size = sizeof(struct ceva_sata_priv), .probe = sata_ceva_probe, .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, }; From 04ab29ab257598b0e33785c075c9163ea090e6b7 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Wed, 11 Apr 2018 14:13:05 +0530 Subject: [PATCH 05/31] arm64: zynqmp: Add new defconfig for zc1275 revB This patch enables support zc1275 revB board. It has SD added compared to revA. The same configuration will work for RevC boards aswell. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-zc1275-revB.dts | 79 ++++ .../zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c | 523 +++++++++++++++++++++ configs/xilinx_zynqmp_zc1275_revB_defconfig | 55 +++ include/configs/xilinx_zynqmp_zc1275_revB.h | 16 + 5 files changed, 674 insertions(+) create mode 100644 arch/arm/dts/zynqmp-zc1275-revB.dts create mode 100644 board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c create mode 100644 configs/xilinx_zynqmp_zc1275_revB_defconfig create mode 100644 include/configs/xilinx_zynqmp_zc1275_revB.h diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 3426a98..f7f2436 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -157,6 +157,7 @@ dtb-$(CONFIG_ARCH_ZYNQMP) += \ zynqmp-zc1232-revA.dtb \ zynqmp-zc1254-revA.dtb \ zynqmp-zc1275-revA.dtb \ + zynqmp-zc1275-revB.dtb \ zynqmp-zc1751-xm015-dc1.dtb \ zynqmp-zc1751-xm016-dc2.dtb \ zynqmp-zc1751-xm017-dc3.dtb \ diff --git a/arch/arm/dts/zynqmp-zc1275-revB.dts b/arch/arm/dts/zynqmp-zc1275-revB.dts new file mode 100644 index 0000000..f694fae --- /dev/null +++ b/arch/arm/dts/zynqmp-zc1275-revB.dts @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dts file for Xilinx ZynqMP ZC1275 RevB + * + * (C) Copyright 2018, Xilinx, Inc. + * + * Michal Simek + * Siva Durga Prasad Paladugu + */ + +/dts-v1/; + +#include "zynqmp.dtsi" +#include "zynqmp-clk-ccf.dtsi" + +/ { + model = "ZynqMP ZC1275 RevB"; + compatible = "xlnx,zynqmp-zc1275-revB", "xlnx,zynqmp-zc1275", "xlnx,zynqmp"; + + aliases { + serial0 = &uart0; + serial1 = &dcc; + spi0 = &qspi; + mmc0 = &sdhci1; + }; + + chosen { + bootargs = "earlycon"; + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; +}; + +&dcc { + status = "okay"; +}; + +&qspi { + status = "okay"; + flash@0 { + compatible = "m25p80"; /* 32MB */ + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; /* Based on DC1 spec */ + partition@qspi-fsbl-uboot { /* for testing purpose */ + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; + }; + partition@qspi-linux { /* for testing purpose */ + label = "qspi-linux"; + reg = <0x100000 0x500000>; + }; + partition@qspi-device-tree { /* for testing purpose */ + label = "qspi-device-tree"; + reg = <0x600000 0x20000>; + }; + partition@qspi-rootfs { /* for testing purpose */ + label = "qspi-rootfs"; + reg = <0x620000 0x5E0000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; + no-1-8-v; + xlnx,mio_bank = <1>; +}; diff --git a/board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c new file mode 100644 index 0000000..54cc828 --- /dev/null +++ b/board/xilinx/zynqmp/zynqmp-zc1275-revB/psu_init_gpl.c @@ -0,0 +1,523 @@ +/* + * (c) Copyright 2015 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +static unsigned long psu_pll_init_data(void) +{ + psu_mask_write(0xFF5E0034, 0xFE7FEDEFU, 0x7E4E2C62U); + psu_mask_write(0xFF5E0030, 0x00717F00U, 0x00013C00U); + psu_mask_write(0xFF5E0030, 0x00000008U, 0x00000008U); + psu_mask_write(0xFF5E0030, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF5E0030, 0x00000001U, 0x00000000U); + mask_poll(0xFF5E0040, 0x00000002U); + psu_mask_write(0xFF5E0030, 0x00000008U, 0x00000000U); + psu_mask_write(0xFF5E0048, 0x00003F00U, 0x00000200U); + psu_mask_write(0xFF5E0024, 0xFE7FEDEFU, 0x7E4B0C82U); + psu_mask_write(0xFF5E0020, 0x00717F00U, 0x00015A00U); + psu_mask_write(0xFF5E0020, 0x00000008U, 0x00000008U); + psu_mask_write(0xFF5E0020, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF5E0020, 0x00000001U, 0x00000000U); + mask_poll(0xFF5E0040, 0x00000001U); + psu_mask_write(0xFF5E0020, 0x00000008U, 0x00000000U); + psu_mask_write(0xFF5E0044, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFD1A0024, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A0020, 0x00717F00U, 0x00014200U); + psu_mask_write(0xFD1A0020, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A0020, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A0020, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000001U); + psu_mask_write(0xFD1A0020, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A0048, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFD1A0030, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A002C, 0x00717F00U, 0x00014800U); + psu_mask_write(0xFD1A002C, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A002C, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A002C, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000002U); + psu_mask_write(0xFD1A002C, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A004C, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFD1A003C, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A0038, 0x00717F00U, 0x00014000U); + psu_mask_write(0xFD1A0038, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A0038, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A0038, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000004U); + psu_mask_write(0xFD1A0038, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A0050, 0x00003F00U, 0x00000200U); + + return 1; +} + +static unsigned long psu_clock_init_data(void) +{ + psu_mask_write(0xFF5E0068, 0x013F3F07U, 0x01010C00U); + psu_mask_write(0xFF5E0070, 0x013F3F07U, 0x01010502U); + psu_mask_write(0xFF18030C, 0x00020000U, 0x00000000U); + psu_mask_write(0xFF5E0074, 0x013F3F07U, 0x01010F00U); + psu_mask_write(0xFF5E0120, 0x013F3F07U, 0x01010F00U); + psu_mask_write(0xFF5E0090, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E009C, 0x01003F07U, 0x01000400U); + psu_mask_write(0xFF5E00A4, 0x01003F07U, 0x01000900U); + psu_mask_write(0xFF5E00A8, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E00AC, 0x01003F07U, 0x01000F02U); + psu_mask_write(0xFF5E00B0, 0x01003F07U, 0x01000602U); + psu_mask_write(0xFF5E00B8, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E00C0, 0x013F3F07U, 0x01010A02U); + psu_mask_write(0xFF5E00C4, 0x013F3F07U, 0x01010402U); + psu_mask_write(0xFF5E00C8, 0x013F3F07U, 0x01010802U); + psu_mask_write(0xFF5E0108, 0x013F3F07U, 0x01011D02U); + psu_mask_write(0xFF5E0104, 0x00000007U, 0x00000000U); + psu_mask_write(0xFF5E0128, 0x01003F07U, 0x01000104U); + psu_mask_write(0xFD1A0060, 0x03003F07U, 0x03000100U); + psu_mask_write(0xFD1A0068, 0x01003F07U, 0x01000200U); + psu_mask_write(0xFD1A0080, 0x00003F07U, 0x00000600U); + psu_mask_write(0xFD1A0084, 0x07003F07U, 0x07000203U); + psu_mask_write(0xFD1A00B8, 0x01003F07U, 0x01000203U); + psu_mask_write(0xFD1A00BC, 0x01003F07U, 0x01000203U); + psu_mask_write(0xFD1A00C0, 0x01003F07U, 0x01000202U); + psu_mask_write(0xFD1A00C4, 0x01003F07U, 0x01000502U); + psu_mask_write(0xFD1A00F8, 0x00003F07U, 0x00000200U); + psu_mask_write(0xFF180380, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD610100, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF180300, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF410050, 0x00000001U, 0x00000000U); + + return 1; +} + +static unsigned long psu_ddr_init_data(void) +{ + psu_mask_write(0xFD1A0108, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD070000, 0xE30FBE3DU, 0x81040001U); + psu_mask_write(0xFD070010, 0x8000F03FU, 0x00000030U); + psu_mask_write(0xFD070020, 0x000003F3U, 0x00000100U); + psu_mask_write(0xFD070024, 0xFFFFFFFFU, 0x00800000U); + psu_mask_write(0xFD070030, 0x0000007FU, 0x00000000U); + psu_mask_write(0xFD070034, 0x00FFFF1FU, 0x00403210U); + psu_mask_write(0xFD070050, 0x00F1F1F4U, 0x00210000U); + psu_mask_write(0xFD070054, 0x0FFF0FFFU, 0x00000000U); + psu_mask_write(0xFD070060, 0x00000073U, 0x00000001U); + psu_mask_write(0xFD070064, 0x0FFF83FFU, 0x00308034U); + psu_mask_write(0xFD070070, 0x00000017U, 0x00000010U); + psu_mask_write(0xFD070074, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD0700C4, 0x3F000391U, 0x10000200U); + psu_mask_write(0xFD0700C8, 0x01FF1F3FU, 0x0030051FU); + psu_mask_write(0xFD0700D0, 0xC3FF0FFFU, 0x00020063U); + psu_mask_write(0xFD0700D4, 0x01FF7F0FU, 0x00290000U); + psu_mask_write(0xFD0700D8, 0x0000FF0FU, 0x00000E05U); + psu_mask_write(0xFD0700DC, 0xFFFFFFFFU, 0x05200004U); + psu_mask_write(0xFD0700E0, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0700E4, 0x00FF03FFU, 0x00110004U); + psu_mask_write(0xFD0700E8, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0700EC, 0xFFFF0000U, 0x00000000U); + psu_mask_write(0xFD0700F0, 0x0000003FU, 0x00000010U); + psu_mask_write(0xFD0700F4, 0x00000FFFU, 0x0000066FU); + psu_mask_write(0xFD070100, 0x7F3F7F3FU, 0x07080D07U); + psu_mask_write(0xFD070104, 0x001F1F7FU, 0x0005020BU); + psu_mask_write(0xFD070108, 0x3F3F3F3FU, 0x03030607U); + psu_mask_write(0xFD07010C, 0x3FF3F3FFU, 0x00502006U); + psu_mask_write(0xFD070110, 0x1F0F0F1FU, 0x13020206U); + psu_mask_write(0xFD070114, 0x0F0F3F1FU, 0x03030202U); + psu_mask_write(0xFD070118, 0x0F0F000FU, 0x01010003U); + psu_mask_write(0xFD07011C, 0x00000F0FU, 0x00000303U); + psu_mask_write(0xFD070120, 0x7F7F7F7FU, 0x02020909U); + psu_mask_write(0xFD070124, 0x40070F3FU, 0x0004040DU); + psu_mask_write(0xFD07012C, 0x7F1F031FU, 0x440C011CU); + psu_mask_write(0xFD070130, 0x00030F1FU, 0x00020608U); + psu_mask_write(0xFD070180, 0xF7FF03FFU, 0x80800020U); + psu_mask_write(0xFD070184, 0x3FFFFFFFU, 0x02009896U); + psu_mask_write(0xFD070190, 0x1FBFBF3FU, 0x04828202U); + psu_mask_write(0xFD070194, 0xF31F0F0FU, 0x00020304U); + psu_mask_write(0xFD070198, 0x0FF1F1F1U, 0x07000101U); + psu_mask_write(0xFD07019C, 0x000000F1U, 0x00000021U); + psu_mask_write(0xFD0701A0, 0xC3FF03FFU, 0x00400003U); + psu_mask_write(0xFD0701A4, 0x00FF00FFU, 0x00C800FFU); + psu_mask_write(0xFD0701B0, 0x00000007U, 0x00000000U); + psu_mask_write(0xFD0701B4, 0x00003F3FU, 0x00000000U); + psu_mask_write(0xFD0701C0, 0x00000007U, 0x00000000U); + psu_mask_write(0xFD070200, 0x0000001FU, 0x0000001FU); + psu_mask_write(0xFD070204, 0x001F1F1FU, 0x00080808U); + psu_mask_write(0xFD070208, 0x0F0F0F0FU, 0x00000000U); + psu_mask_write(0xFD07020C, 0x0F0F0F0FU, 0x00000000U); + psu_mask_write(0xFD070210, 0x00000F0FU, 0x00000F0FU); + psu_mask_write(0xFD070214, 0x0F0F0F0FU, 0x070F0707U); + psu_mask_write(0xFD070218, 0x8F0F0F0FU, 0x0F070707U); + psu_mask_write(0xFD07021C, 0x00000F0FU, 0x00000F0FU); + psu_mask_write(0xFD070220, 0x00001F1FU, 0x00000000U); + psu_mask_write(0xFD070224, 0x0F0F0F0FU, 0x07070707U); + psu_mask_write(0xFD070228, 0x0F0F0F0FU, 0x07070707U); + psu_mask_write(0xFD07022C, 0x0000000FU, 0x00000007U); + psu_mask_write(0xFD070240, 0x0F1F0F7CU, 0x06000604U); + psu_mask_write(0xFD070244, 0x00003333U, 0x00000001U); + psu_mask_write(0xFD070250, 0x7FFF3F07U, 0x01002001U); + psu_mask_write(0xFD070264, 0xFF00FFFFU, 0x08000040U); + psu_mask_write(0xFD07026C, 0xFF00FFFFU, 0x08000040U); + psu_mask_write(0xFD070280, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070284, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070288, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD07028C, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070290, 0x0000FFFFU, 0x00000000U); + psu_mask_write(0xFD070294, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070300, 0x00000011U, 0x00000000U); + psu_mask_write(0xFD07030C, 0x80000033U, 0x00000000U); + psu_mask_write(0xFD070320, 0x00000001U, 0x00000000U); + psu_mask_write(0xFD070400, 0x00000111U, 0x00000001U); + psu_mask_write(0xFD070404, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070408, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070490, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070494, 0x0033000FU, 0x0020000BU); + psu_mask_write(0xFD070498, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD0704B4, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0704B8, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070540, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070544, 0x03330F0FU, 0x02000B03U); + psu_mask_write(0xFD070548, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD070564, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070568, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0705F0, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD0705F4, 0x03330F0FU, 0x02000B03U); + psu_mask_write(0xFD0705F8, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD070614, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070618, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0706A0, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD0706A4, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD0706A8, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD0706AC, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD0706B0, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD0706C4, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0706C8, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070750, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070754, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070758, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD07075C, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070760, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD070774, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070778, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070800, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070804, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070808, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD07080C, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070810, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD070F04, 0x000001FFU, 0x00000000U); + psu_mask_write(0xFD070F08, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD070F0C, 0x000001FFU, 0x00000010U); + psu_mask_write(0xFD070F10, 0x000000FFU, 0x0000000FU); + psu_mask_write(0xFD072190, 0x1FBFBF3FU, 0x07828002U); + psu_mask_write(0xFD1A0108, 0x0000000CU, 0x00000000U); + psu_mask_write(0xFD080010, 0xFFFFFFFFU, 0x07001E00U); + psu_mask_write(0xFD080018, 0xFFFFFFFFU, 0x00F05D90U); + psu_mask_write(0xFD08001C, 0xFFFFFFFFU, 0x55AA5480U); + psu_mask_write(0xFD080024, 0xFFFFFFFFU, 0x010100F4U); + psu_mask_write(0xFD080040, 0xFFFFFFFFU, 0x1900C810U); + psu_mask_write(0xFD080044, 0xFFFFFFFFU, 0x4E200708U); + psu_mask_write(0xFD080068, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD080090, 0xFFFFFFFFU, 0x02A04061U); + psu_mask_write(0xFD0800C0, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0800C4, 0xFFFFFFFFU, 0x000000DAU); + psu_mask_write(0xFD080100, 0xFFFFFFFFU, 0x0800040BU); + psu_mask_write(0xFD080110, 0xFFFFFFFFU, 0x040E0A04U); + psu_mask_write(0xFD080114, 0xFFFFFFFFU, 0x28100004U); + psu_mask_write(0xFD080118, 0xFFFFFFFFU, 0x000F0200U); + psu_mask_write(0xFD08011C, 0xFFFFFFFFU, 0x82000800U); + psu_mask_write(0xFD080120, 0xFFFFFFFFU, 0x00682B0AU); + psu_mask_write(0xFD080124, 0xFFFFFFFFU, 0x00152504U); + psu_mask_write(0xFD080128, 0xFFFFFFFFU, 0x00000506U); + psu_mask_write(0xFD080140, 0xFFFFFFFFU, 0x08400020U); + psu_mask_write(0xFD080144, 0xFFFFFFFFU, 0x00000C80U); + psu_mask_write(0xFD080150, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080154, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080180, 0xFFFFFFFFU, 0x00000520U); + psu_mask_write(0xFD080184, 0xFFFFFFFFU, 0x00000004U); + psu_mask_write(0xFD080188, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD08018C, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080190, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080194, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080198, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0801AC, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0801B0, 0xFFFFFFFFU, 0x0000004DU); + psu_mask_write(0xFD0801B4, 0xFFFFFFFFU, 0x00000008U); + psu_mask_write(0xFD0801B8, 0xFFFFFFFFU, 0x0000004DU); + psu_mask_write(0xFD0801D8, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080200, 0xFFFFFFFFU, 0x800081C7U); + psu_mask_write(0xFD080204, 0xFFFFFFFFU, 0x00010236U); + psu_mask_write(0xFD080240, 0xFFFFFFFFU, 0x00141054U); + psu_mask_write(0xFD080250, 0xFFFFFFFFU, 0x00088000U); + psu_mask_write(0xFD080414, 0xFFFFFFFFU, 0x12340800U); + psu_mask_write(0xFD0804F4, 0xFFFFFFFFU, 0x00000005U); + psu_mask_write(0xFD080500, 0xFFFFFFFFU, 0x30000028U); + psu_mask_write(0xFD080508, 0xFFFFFFFFU, 0x0A000000U); + psu_mask_write(0xFD08050C, 0xFFFFFFFFU, 0x00000009U); + psu_mask_write(0xFD080510, 0xFFFFFFFFU, 0x0A000000U); + psu_mask_write(0xFD080520, 0xFFFFFFFFU, 0x0300B0B0U); + psu_mask_write(0xFD080528, 0xFFFFFFFFU, 0xF1032019U); + psu_mask_write(0xFD08052C, 0xFFFFFFFFU, 0x07F001E3U); + psu_mask_write(0xFD080544, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080548, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080558, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD08055C, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080560, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080564, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080680, 0xFFFFFFFFU, 0x0088E858U); + psu_mask_write(0xFD080684, 0xFFFFFFFFU, 0x000077BBU); + psu_mask_write(0xFD080694, 0xFFFFFFFFU, 0x01E10210U); + psu_mask_write(0xFD080698, 0xFFFFFFFFU, 0x01E10000U); + psu_mask_write(0xFD0806A4, 0xFFFFFFFFU, 0x000076BBU); + psu_mask_write(0xFD080700, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080704, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08070C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080710, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080714, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080718, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080800, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080804, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08080C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080810, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080814, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080818, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080900, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080904, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08090C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080910, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080914, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080918, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080A00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080A04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080A0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080A10, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080A14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080A18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080B00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080B04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080B08, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080B0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080B10, 0xFFFFFFFFU, 0x0E00B004U); + psu_mask_write(0xFD080B14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080B18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080C00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080C04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080C08, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080C0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080C10, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080C14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080C18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080D00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080D04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080D08, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080D0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080D10, 0xFFFFFFFFU, 0x0E00B004U); + psu_mask_write(0xFD080D14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080D18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080E00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080E04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080E08, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080E0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080E10, 0xFFFFFFFFU, 0x0E00B00CU); + psu_mask_write(0xFD080E14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080E18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080F00, 0xFFFFFFFFU, 0x40803660U); + psu_mask_write(0xFD080F04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080F08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080F0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080F10, 0xFFFFFFFFU, 0x0C00B000U); + psu_mask_write(0xFD080F14, 0xFFFFFFFFU, 0x09093030U); + psu_mask_write(0xFD080F18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD081400, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD081404, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD08141C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD08142C, 0xFFFFFFFFU, 0x00041800U); + psu_mask_write(0xFD081430, 0xFFFFFFFFU, 0x70000000U); + psu_mask_write(0xFD081440, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD081444, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD08145C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD08146C, 0xFFFFFFFFU, 0x00041800U); + psu_mask_write(0xFD081470, 0xFFFFFFFFU, 0x70000000U); + psu_mask_write(0xFD081480, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD081484, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD08149C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD0814AC, 0xFFFFFFFFU, 0x00041800U); + psu_mask_write(0xFD0814B0, 0xFFFFFFFFU, 0x70000000U); + psu_mask_write(0xFD0814C0, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD0814C4, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD0814DC, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD0814EC, 0xFFFFFFFFU, 0x00041800U); + psu_mask_write(0xFD0814F0, 0xFFFFFFFFU, 0x70000000U); + psu_mask_write(0xFD081500, 0xFFFFFFFFU, 0x15019FFEU); + psu_mask_write(0xFD081504, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD08151C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD08152C, 0xFFFFFFFFU, 0x00041800U); + psu_mask_write(0xFD081530, 0xFFFFFFFFU, 0x70000000U); + psu_mask_write(0xFD0817C4, 0xFFFFFFFFU, 0x06124000U); + psu_mask_write(0xFD0817DC, 0xFFFFFFFFU, 0x012643C4U); + + return 1; +} + +static unsigned long psu_mio_init_data(void) +{ + psu_mask_write(0xFF180000, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180004, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180010, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180014, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180018, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180088, 0x000000FEU, 0x000000C0U); + psu_mask_write(0xFF18008C, 0x000000FEU, 0x000000C0U); + psu_mask_write(0xFF18009C, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800A0, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800A4, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800A8, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800AC, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800B0, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800B4, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800B8, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800BC, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800C0, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800C4, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800C8, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF1800CC, 0x000000FEU, 0x00000010U); + psu_mask_write(0xFF180204, 0x0000007FU, 0x00000002U); + psu_mask_write(0xFF180208, 0x000FFF8CU, 0x00003004U); + psu_mask_write(0xFF180138, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18013C, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180140, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180144, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180148, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18014C, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180154, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180158, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18015C, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180160, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180164, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180168, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180170, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180174, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180178, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF18017C, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180180, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180184, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180200, 0x0000000FU, 0x00000000U); + + return 1; +} + +static unsigned long psu_peripherals_pre_init_data(void) +{ + psu_mask_write(0xFF5E0108, 0x013F3F07U, 0x00012302U); + + return 1; +} + +static unsigned long psu_peripherals_init_data(void) +{ + psu_mask_write(0xFD1A0100, 0x0000807CU, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x001A0000U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x0093C018U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF180390, 0x00000004U, 0x00000004U); + psu_mask_write(0xFF5E0238, 0x00000040U, 0x00000000U); + psu_mask_write(0xFF180310, 0x00008000U, 0x00000000U); + psu_mask_write(0xFF180320, 0x33800000U, 0x02800000U); + psu_mask_write(0xFF18031C, 0x7FFE0000U, 0x64500000U); + psu_mask_write(0xFF180358, 0x00000008U, 0x00000008U); + psu_mask_write(0xFF180324, 0x03C00000U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000200U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000800U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000002U, 0x00000000U); + psu_mask_write(0xFF000034, 0x000000FFU, 0x00000005U); + psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000008FU); + psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); + psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); + psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); + psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); + psu_mask_write(0xFD5C0060, 0x000F000FU, 0x00000000U); + psu_mask_write(0xFFA60040, 0x80000000U, 0x80000000U); + psu_mask_write(0xFF260020, 0xFFFFFFFFU, 0x01FC9F08U); + psu_mask_write(0xFF260000, 0x00000001U, 0x00000001U); + + return 1; +} + +static unsigned long psu_afi_config(void) +{ + psu_mask_write(0xFD1A0100, 0x00001F80U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x00080000U, 0x00000000U); + psu_mask_write(0xFD615000, 0x00000300U, 0x00000200U); + + return 1; +} + +static unsigned long psu_ddr_phybringup_data(void) +{ + unsigned int regval = 0; + unsigned int pll_retry = 10; + unsigned int pll_locked = 0; + + while ((pll_retry > 0) && (!pll_locked)) { + Xil_Out32(0xFD080004, 0x00040010); + Xil_Out32(0xFD080004, 0x00040011); + + while ((Xil_In32(0xFD080030) & 0x1) != 1) + ; + + pll_locked = (Xil_In32(0xFD080030) & 0x80000000) >> 31; + pll_locked &= (Xil_In32(0xFD0807E0) & 0x10000) >> 16; + pll_locked &= (Xil_In32(0xFD0809E0) & 0x10000) >> 16; + pll_locked &= (Xil_In32(0xFD080BE0) & 0x10000) >> 16; + pll_locked &= (Xil_In32(0xFD080DE0) & 0x10000) >> 16; + pll_retry--; + } + Xil_Out32(0xFD0800C0, Xil_In32(0xFD0800C0) | (pll_retry << 16)); + Xil_Out32(0xFD080004U, 0x00040063U); + + while ((Xil_In32(0xFD080030U) & 0x0000000FU) != 0x0000000FU) + ; + prog_reg(0xFD080004U, 0x00000001U, 0x00000000U, 0x00000001U); + + while ((Xil_In32(0xFD080030U) & 0x000000FFU) != 0x0000001FU) + ; + Xil_Out32(0xFD0701B0U, 0x00000001U); + Xil_Out32(0xFD070320U, 0x00000001U); + while ((Xil_In32(0xFD070004U) & 0x0000000FU) != 0x00000001U) + ; + prog_reg(0xFD080014U, 0x00000040U, 0x00000006U, 0x00000001U); + Xil_Out32(0xFD080004, 0x0004FE01); + regval = Xil_In32(0xFD080030); + while (regval != 0x80000FFF) + regval = Xil_In32(0xFD080030); + Xil_Out32(0xFD070180U, 0x00800020U); + Xil_Out32(0xFD070060U, 0x00000000U); + prog_reg(0xFD080014U, 0x00000040U, 0x00000006U, 0x00000000U); + + return 1; +} + +static void init_peripheral(void) +{ + psu_mask_write(0xFD5F0018, 0x8000001FU, 0x8000001FU); +} + +int psu_init(void) +{ + int status = 1; + + status &= psu_mio_init_data(); + status &= psu_peripherals_pre_init_data(); + status &= psu_pll_init_data(); + status &= psu_clock_init_data(); + status &= psu_ddr_init_data(); + status &= psu_ddr_phybringup_data(); + status &= psu_peripherals_init_data(); + init_peripheral(); + + status &= psu_afi_config(); + + if (status == 0) + return 1; + return 0; +} diff --git a/configs/xilinx_zynqmp_zc1275_revB_defconfig b/configs/xilinx_zynqmp_zc1275_revB_defconfig new file mode 100644 index 0000000..b073282 --- /dev/null +++ b/configs/xilinx_zynqmp_zc1275_revB_defconfig @@ -0,0 +1,55 @@ +CONFIG_ARM=y +CONFIG_SYS_CONFIG_NAME="xilinx_zynqmp_zc1275_revB" +CONFIG_ARCH_ZYNQMP=y +CONFIG_SYS_TEXT_BASE=0x8000000 +CONFIG_SYS_MALLOC_F_LEN=0x8000 +# CONFIG_SPL_LIBDISK_SUPPORT is not set +CONFIG_SPL=y +CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1275 revB" +# CONFIG_SPL_FAT_SUPPORT is not set +CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1275-revB" +CONFIG_DEBUG_UART=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_SPL_LOAD_FIT=y +# CONFIG_DISPLAY_CPUINFO is not set +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_SPL_OS_BOOT=y +CONFIG_SPL_RAM_SUPPORT=y +CONFIG_SPL_RAM_DEVICE=y +CONFIG_SPL_ATF=y +CONFIG_SYS_PROMPT="ZynqMP> " +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_CLK=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_FPGA_LOADBP=y +CONFIG_CMD_FPGA_LOADP=y +CONFIG_CMD_MMC=y +# CONFIG_CMD_NET is not set +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_SPL_DM=y +CONFIG_CLK_ZYNQMP=y +CONFIG_FPGA_XILINX=y +CONFIG_FPGA_ZYNQMPPL=y +CONFIG_MISC=y +CONFIG_DM_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ZYNQ=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SF_DUAL_FLASH=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_DEBUG_UART_ZYNQ=y +CONFIG_DEBUG_UART_BASE=0xff000000 +CONFIG_DEBUG_UART_CLOCK=100000000 +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_ZYNQ_SERIAL=y +CONFIG_EFI_LOADER_BOUNCE_BUFFER=y diff --git a/include/configs/xilinx_zynqmp_zc1275_revB.h b/include/configs/xilinx_zynqmp_zc1275_revB.h new file mode 100644 index 0000000..4cebe21 --- /dev/null +++ b/include/configs/xilinx_zynqmp_zc1275_revB.h @@ -0,0 +1,16 @@ +/* + * Configuration for Xilinx ZynqMP zc1275 RevB + * + * (C) Copyright 2018 Xilinx, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_ZYNQMP_ZC1275_REVB_H +#define __CONFIG_ZYNQMP_ZC1275_REVB_H + +#define CONFIG_ZYNQ_SDHCI1 + +#include + +#endif /* __CONFIG_ZYNQMP_ZC1275_REVB_H */ From 83ec537dfb9c1af1f21484f017dc408781eb9466 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Wed, 3 Jan 2018 13:15:29 +0530 Subject: [PATCH 06/31] microblaze: Dont enable UBI support by default This patch removes UBI support from defconfig and it can be enabled from menuconfig as per need. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- configs/microblaze-generic_defconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configs/microblaze-generic_defconfig b/configs/microblaze-generic_defconfig index 2cbabf6..6ba7022 100644 --- a/configs/microblaze-generic_defconfig +++ b/configs/microblaze-generic_defconfig @@ -35,10 +35,6 @@ CONFIG_CMD_TFTPPUT=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y CONFIG_CMD_JFFS2=y -CONFIG_MTDIDS_DEFAULT="nor0=flash-0" -CONFIG_MTDPARTS_DEFAULT="mtdparts=flash-0:256k(u-boot),256k(env),3m(kernel),1m(romfs),1m(cramfs),-(jffs2)" -CONFIG_CMD_UBI=y -# CONFIG_CMD_UBIFS is not set CONFIG_SPL_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_NETCONSOLE=y From 72c37d12214b9ee3760e5ad41465691c0accd62b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 17 Apr 2018 13:40:46 +0200 Subject: [PATCH 07/31] timer: Add Cadence TTC timer counter support This driver was tested on Xilinx ZynqMP SoC. Signed-off-by: Michal Simek --- MAINTAINERS | 1 + drivers/timer/Kconfig | 7 ++++ drivers/timer/Makefile | 1 + drivers/timer/cadence-ttc.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 drivers/timer/cadence-ttc.c diff --git a/MAINTAINERS b/MAINTAINERS index 60d4adf..5b139e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -288,6 +288,7 @@ F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c F: drivers/spi/zynq_qspi.c F: drivers/spi/zynq_spi.c +F: drivers/timer/cadence-ttc.c F: drivers/usb/host/ehci-zynq.c F: drivers/watchdog/cdns_wdt.c F: include/zynqmppl.h diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 2c96896..8a31397 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -52,6 +52,13 @@ config ATMEL_PIT_TIMER it is designed to offer maximum accuracy and efficient management, even for systems with long response time. +config CADENCE_TTC_TIMER + bool "Cadence TTC (Triple Timer Counter)" + depends on TIMER + help + Enables support for the cadence ttc driver. This driver is present + on Xilinx Zynq and ZynqMP SoCs. + config SANDBOX_TIMER bool "Sandbox timer support" depends on SANDBOX && TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index a8b531a..ee2fcb1 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -4,6 +4,7 @@ obj-y += timer-uclass.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o +obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_OMAP_TIMER) += omap-timer.o diff --git a/drivers/timer/cadence-ttc.c b/drivers/timer/cadence-ttc.c new file mode 100644 index 0000000..5b91c8a --- /dev/null +++ b/drivers/timer/cadence-ttc.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Xilinx, Inc. (Michal Simek) + */ + +#include +#include +#include +#include +#include + +#define CNT_CNTRL_RESET BIT(4) + +struct cadence_ttc_regs { + u32 clk_cntrl1; /* 0x0 - Clock Control 1 */ + u32 clk_cntrl2; /* 0x4 - Clock Control 2 */ + u32 clk_cntrl3; /* 0x8 - Clock Control 3 */ + u32 counter_cntrl1; /* 0xC - Counter Control 1 */ + u32 counter_cntrl2; /* 0x10 - Counter Control 2 */ + u32 counter_cntrl3; /* 0x14 - Counter Control 3 */ + u32 counter_val1; /* 0x18 - Counter Control 1 */ + u32 counter_val2; /* 0x1C - Counter Control 2 */ + u32 counter_val3; /* 0x20 - Counter Control 3 */ + u32 reserved[15]; + u32 interrupt_enable1; /* 0x60 - Interrupt Enable 1 */ + u32 interrupt_enable2; /* 0x64 - Interrupt Enable 2 */ + u32 interrupt_enable3; /* 0x68 - Interrupt Enable 3 */ +}; + +struct cadence_ttc_priv { + struct cadence_ttc_regs *regs; +}; + +static int cadence_ttc_get_count(struct udevice *dev, u64 *count) +{ + struct cadence_ttc_priv *priv = dev_get_priv(dev); + + *count = readl(&priv->regs->counter_val1); + + return 0; +} + +static int cadence_ttc_probe(struct udevice *dev) +{ + struct cadence_ttc_priv *priv = dev_get_priv(dev); + + /* Disable interrupts for sure */ + writel(0, &priv->regs->interrupt_enable1); + writel(0, &priv->regs->interrupt_enable2); + writel(0, &priv->regs->interrupt_enable3); + + /* Make sure that clocks are configured properly without prescaller */ + writel(0, &priv->regs->clk_cntrl1); + writel(0, &priv->regs->clk_cntrl2); + writel(0, &priv->regs->clk_cntrl3); + + /* Reset and enable this counter */ + writel(CNT_CNTRL_RESET, &priv->regs->counter_cntrl1); + + return 0; +} + +static int cadence_ttc_ofdata_to_platdata(struct udevice *dev) +{ + struct cadence_ttc_priv *priv = dev_get_priv(dev); + + priv->regs = map_physmem(devfdt_get_addr(dev), + sizeof(struct cadence_ttc_regs), MAP_NOCACHE); + + return 0; +} + +static const struct timer_ops cadence_ttc_ops = { + .get_count = cadence_ttc_get_count, +}; + +static const struct udevice_id cadence_ttc_ids[] = { + { .compatible = "cdns,ttc" }, + {} +}; + +U_BOOT_DRIVER(cadence_ttc) = { + .name = "cadence_ttc", + .id = UCLASS_TIMER, + .of_match = cadence_ttc_ids, + .ofdata_to_platdata = cadence_ttc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct cadence_ttc_priv), + .probe = cadence_ttc_probe, + .ops = &cadence_ttc_ops, + .flags = DM_FLAG_PRE_RELOC, +}; From d93c666c4c4d851c2e6a74aa099e502b3c1255ce Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 18 Apr 2018 12:52:48 +0200 Subject: [PATCH 08/31] serial: zynq: Remove header depedency on arm header structure There is no need to have arm hardware header in this driver. Signed-off-by: Michal Simek --- drivers/serial/serial_zynq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index af9790d..06f0a48 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -14,7 +14,6 @@ #include #include #include -#include #define ZYNQ_UART_SR_TXEMPTY (1 << 3) /* TX FIFO empty */ #define ZYNQ_UART_SR_TXACTIVE (1 << 11) /* TX active */ From 6de7a5b90701fb306b150d0ed32f7b59b51bbbc5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 18 Apr 2018 15:00:43 +0200 Subject: [PATCH 09/31] MAINTAINERS: zynqmp: Point to proper zynqmp folder Point to Zynqmp arm64 cpu folder not to Zynq arm32. Signed-off-by: Michal Simek --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5b139e5..031f7ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -274,7 +274,7 @@ ARM ZYNQMP M: Michal Simek S: Maintained T: git git://git.denx.de/u-boot-microblaze.git -F: arch/arm/mach-zynq/ +F: arch/arm/cpu/armv8/zynqmp/ F: drivers/clk/clk_zynqmp.c F: drivers/fpga/zynqpl.c F: drivers/gpio/zynq_gpio.c From 9ca8388059de8f10e035fbdcaa418ec3caeb0599 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 25 May 2017 14:25:55 +0530 Subject: [PATCH 10/31] nand: zynq: Add support for 16-bit buswidth This patch adds support for 16-bit buswidth by determining the bus width based on mio configuration. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mtd/nand/zynq_nand.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/mtd/nand/zynq_nand.c b/drivers/mtd/nand/zynq_nand.c index efd3c9b..4d0ea9e 100644 --- a/drivers/mtd/nand/zynq_nand.c +++ b/drivers/mtd/nand/zynq_nand.c @@ -16,6 +16,7 @@ #include #include #include +#include /* The NAND flash driver defines */ #define ZYNQ_NAND_CMD_PHASE 1 @@ -83,6 +84,15 @@ #define ZYNQ_NAND_ECC_BUSY (1 << 6) /* ECC block is busy */ #define ZYNQ_NAND_ECC_MASK 0x00FFFFFF /* ECC value mask */ +#define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13 +#define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8 + +enum zynq_nand_bus_width { + NAND_BW_UNKNOWN = -1, + NAND_BW_8BIT, + NAND_BW_16BIT, +}; + #ifndef NAND_CMD_LOCK_TIGHT #define NAND_CMD_LOCK_TIGHT 0x2c #endif @@ -1005,6 +1015,23 @@ static int zynq_nand_device_ready(struct mtd_info *mtd) return 0; } +static int zynq_nand_check_is_16bit_bw_flash(void) +{ + int is_16bit_bw = NAND_BW_UNKNOWN; + int mio_num_8bit = 0, mio_num_16bit = 0; + + mio_num_8bit = zynq_slcr_get_mio_pin_status("nand8"); + if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT) + is_16bit_bw = NAND_BW_8BIT; + + mio_num_16bit = zynq_slcr_get_mio_pin_status("nand16"); + if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT && + mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT) + is_16bit_bw = NAND_BW_16BIT; + + return is_16bit_bw; +} + static int zynq_nand_init(struct nand_chip *nand_chip, int devnum) { struct zynq_nand_info *xnand; @@ -1016,6 +1043,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum) unsigned long ecc_cfg; int ondie_ecc_enabled = 0; int err = -1; + int is_16bit_bw; xnand = calloc(1, sizeof(struct zynq_nand_info)); if (!xnand) { @@ -1045,6 +1073,16 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum) nand_chip->read_buf = zynq_nand_read_buf; nand_chip->write_buf = zynq_nand_write_buf; + is_16bit_bw = zynq_nand_check_is_16bit_bw_flash(); + if (is_16bit_bw == NAND_BW_UNKNOWN) { + printf("%s: Unable detect NAND based on MIO settings\n", + __func__); + goto fail; + } + + if (is_16bit_bw == NAND_BW_16BIT) + nand_chip->options = NAND_BUSWIDTH_16; + nand_chip->bbt_options = NAND_BBT_USE_FLASH; /* Initialize the NAND flash interface on NAND controller */ From 9fdde6c4bbb6840dd175f0c29dfcc791fc0c1d2a Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 25 May 2017 12:15:24 +0530 Subject: [PATCH 11/31] nand: zynq: Send address cycles as per onfi parameter page Send address cycles as per value read from onfi parameter page for Read and write commands instead of using a hard coded value. This may vary for different parts and hence use it from onfi parameter page value. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mtd/nand/zynq_nand.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/zynq_nand.c b/drivers/mtd/nand/zynq_nand.c index 4d0ea9e..e932a58 100644 --- a/drivers/mtd/nand/zynq_nand.c +++ b/drivers/mtd/nand/zynq_nand.c @@ -84,6 +84,9 @@ #define ZYNQ_NAND_ECC_BUSY (1 << 6) /* ECC block is busy */ #define ZYNQ_NAND_ECC_MASK 0x00FFFFFF /* ECC value mask */ +#define ZYNQ_NAND_ROW_ADDR_CYCL_MASK 0x0F +#define ZYNQ_NAND_COL_ADDR_CYCL_MASK 0xF0 + #define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13 #define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8 @@ -778,6 +781,7 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command, { struct nand_chip *chip = mtd->priv; const struct zynq_nand_command_format *curr_cmd = NULL; + u8 addr_cycles = 0; struct zynq_nand_info *xnand = (struct zynq_nand_info *)chip->priv; void *cmd_addr; unsigned long cmd_data = 0; @@ -828,8 +832,18 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command, else end_cmd = curr_cmd->end_cmd; + if (command == NAND_CMD_READ0 || + command == NAND_CMD_SEQIN) { + addr_cycles = chip->onfi_params.addr_cycles & + ZYNQ_NAND_ROW_ADDR_CYCL_MASK; + addr_cycles += ((chip->onfi_params.addr_cycles & + ZYNQ_NAND_COL_ADDR_CYCL_MASK) >> 4); + } else { + addr_cycles = curr_cmd->addr_cycles; + } + cmd_phase_addr = (unsigned long)xnand->nand_base | - (curr_cmd->addr_cycles << ADDR_CYCLES_SHIFT) | + (addr_cycles << ADDR_CYCLES_SHIFT) | (end_cmd_valid << END_CMD_VALID_SHIFT) | (COMMAND_PHASE) | (end_cmd << END_CMD_SHIFT) | From e00656b2a911be40745e6556cb663096f439bc8d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Apr 2018 14:41:11 +0200 Subject: [PATCH 12/31] arm64: zynqmp: Reset FPD Watchdog on zcu100 Low level configuration didn't reset FPD Watchdog that's why accessing it caused u-boot hang. Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp-zcu100-revC/psu_init_gpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/xilinx/zynqmp/zynqmp-zcu100-revC/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu100-revC/psu_init_gpl.c index d83dcd1..e1fdaba 100644 --- a/board/xilinx/zynqmp/zynqmp-zcu100-revC/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-zcu100-revC/psu_init_gpl.c @@ -481,7 +481,7 @@ static unsigned long psu_mio_init_data(void) static unsigned long psu_peripherals_init_data(void) { - psu_mask_write(0xFD1A0100, 0x0001007CU, 0x00000000U); + psu_mask_write(0xFD1A0100, 0x0001807CU, 0x00000000U); psu_mask_write(0xFF5E0238, 0x001A0000U, 0x00000000U); psu_mask_write(0xFF5E023C, 0x0093C018U, 0x00000000U); psu_mask_write(0xFF5E023C, 0x00000FC0U, 0x00000000U); From 5b410deac6023338a658e0085c744b29f9880fbe Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Apr 2018 15:22:04 +0200 Subject: [PATCH 13/31] watchdog: cadence: Show used timeout value Debug message was showing timeout value which was passed to start function but there is a checking if this value can be setup. The patch is moving this debug printf function below checking. Signed-off-by: Michal Simek --- drivers/watchdog/cdns_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/cdns_wdt.c b/drivers/watchdog/cdns_wdt.c index fb045fc..9a07fa1 100644 --- a/drivers/watchdog/cdns_wdt.c +++ b/drivers/watchdog/cdns_wdt.c @@ -142,13 +142,13 @@ static int cdns_wdt_start(struct udevice *dev, u64 timeout, ulong flags) return -1; } - debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout); - if ((timeout < CDNS_WDT_MIN_TIMEOUT) || (timeout > CDNS_WDT_MAX_TIMEOUT)) { timeout = priv->timeout; } + debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout); + if (clk_f <= CDNS_WDT_CLK_75MHZ) { prescaler = CDNS_WDT_PRESCALE_512; ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512; From 4490e013ee4f2a4b9b6ca9224221fed2788b6940 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Apr 2018 15:43:38 +0200 Subject: [PATCH 14/31] arm64: zynqmp: Wire watchdog internals Enable watchdog in full U-Boot. Similar changes were done by: "arm: zynq: Wire watchdog internals" (sha1: e6cc3b25d721c3001019f8b44bfaae2a57255162) Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index ce7c050..4c6f299 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -22,6 +24,10 @@ DECLARE_GLOBAL_DATA_PTR; +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) +static struct udevice *watchdog_dev; +#endif + #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ !defined(CONFIG_SPL_BUILD) static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC; @@ -281,6 +287,11 @@ int board_early_init_f(void) ret = psu_init(); #endif +#if defined(CONFIG_WDT) && !defined(CONFIG_SPL_BUILD) + /* bss is not cleared at time when watchdog_reset() is called */ + watchdog_dev = NULL; +#endif + return ret; } @@ -299,9 +310,40 @@ int board_init(void) } #endif +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + } else { + wdt_start(watchdog_dev, 0, 0); + puts("Watchdog: Started\n"); + } +#endif + return 0; } +#ifdef CONFIG_WATCHDOG +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ +# if !defined(CONFIG_SPL_BUILD) + static ulong next_reset; + ulong now; + + if (!watchdog_dev) + return; + + now = timer_get_us(); + + /* Do not reset the watchdog too often */ + if (now > next_reset) { + wdt_reset(watchdog_dev); + next_reset = now + 1000; + } +# endif +} +#endif + int board_early_init_r(void) { u32 val; From 767afebbcda59f3ccb04f6c94de8cab2fb7905b6 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 19 Apr 2018 15:43:50 +0200 Subject: [PATCH 15/31] arm64: zynqmp: Enable cadence WDT for zcu100 Enable watchdog on zcu100 to make sure if there is a bug in the u-boot there is proper reset. Watchdog expires and PMU fw is informed and based on setting proper action is taken. The patch is enabling reset-on-timeout feature and also fixing fixed clock rate for watchdog where 100MHz is max (and also default) clock value. Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-clk.dtsi | 2 +- arch/arm/dts/zynqmp-zcu100-revC.dts | 1 + configs/xilinx_zynqmp_zcu100_revC_defconfig | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/zynqmp-clk.dtsi b/arch/arm/dts/zynqmp-clk.dtsi index a8664e8..a795efd 100644 --- a/arch/arm/dts/zynqmp-clk.dtsi +++ b/arch/arm/dts/zynqmp-clk.dtsi @@ -219,7 +219,7 @@ }; &watchdog0 { - clocks = <&clk250>; + clocks = <&clk100>; }; &xilinx_drm { diff --git a/arch/arm/dts/zynqmp-zcu100-revC.dts b/arch/arm/dts/zynqmp-zcu100-revC.dts index 9114f98..bcd9c39 100644 --- a/arch/arm/dts/zynqmp-zcu100-revC.dts +++ b/arch/arm/dts/zynqmp-zcu100-revC.dts @@ -332,6 +332,7 @@ &watchdog0 { status = "okay"; + reset-on-timeout; }; &xilinx_ams { diff --git a/configs/xilinx_zynqmp_zcu100_revC_defconfig b/configs/xilinx_zynqmp_zcu100_revC_defconfig index 87b7941..1625ef3 100644 --- a/configs/xilinx_zynqmp_zcu100_revC_defconfig +++ b/configs/xilinx_zynqmp_zcu100_revC_defconfig @@ -80,5 +80,7 @@ CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_WDT=y +CONFIG_WDT_CDNS=y CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y From 0678941ae54b3f1bbd8024c8d74fb282f0c1b590 Mon Sep 17 00:00:00 2001 From: Nitin Jain Date: Fri, 20 Apr 2018 12:30:40 +0530 Subject: [PATCH 16/31] arm64: zynqmp: Setup MMU map for DDR at run time This patch fills the MMU map for DDR at run time based on information read from Device Tree or automatically detected from static configuration. The patch is needed because for systems which has for example 1GB of memory but MMU map is 2GB there could be spurious accesses which was seen in past when mapping is not fitting with actual memory installed. Signed-off-by: Nitin Jain Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- arch/arm/cpu/armv8/zynqmp/cpu.c | 84 +++++++++++++++++----------- arch/arm/include/asm/arch-zynqmp/sys_proto.h | 2 +- board/xilinx/zynqmp/zynqmp.c | 22 +++++++- 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/arch/arm/cpu/armv8/zynqmp/cpu.c b/arch/arm/cpu/armv8/zynqmp/cpu.c index eb0db46..2748d65 100644 --- a/arch/arm/cpu/armv8/zynqmp/cpu.c +++ b/arch/arm/cpu/armv8/zynqmp/cpu.c @@ -15,16 +15,28 @@ DECLARE_GLOBAL_DATA_PTR; -static struct mm_region zynqmp_mem_map[] = { +/* + * Number of filled static entries and also the first empty + * slot in zynqmp_mem_map. + */ +#define ZYNQMP_MEM_MAP_USED 4 + #if !defined(CONFIG_ZYNQMP_NO_DDR) - { - .virt = 0x0UL, - .phys = 0x0UL, - .size = 0x80000000UL, - .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | - PTE_BLOCK_INNER_SHARE - }, +#define DRAM_BANKS CONFIG_NR_DRAM_BANKS +#else +#define DRAM_BANKS 0 #endif + +#if defined(CONFIG_DEFINE_TCM_OCM_MMAP) +#define TCM_MAP 1 +#else +#define TCM_MAP 0 +#endif + +/* +1 is end of list which needs to be empty */ +#define ZYNQMP_MEM_MAP_MAX (ZYNQMP_MEM_MAP_USED + DRAM_BANKS + TCM_MAP + 1) + +static struct mm_region zynqmp_mem_map[ZYNQMP_MEM_MAP_MAX] = { { .virt = 0x80000000UL, .phys = 0x80000000UL, @@ -32,8 +44,7 @@ static struct mm_region zynqmp_mem_map[] = { .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN - }, - { + }, { .virt = 0xf8000000UL, .phys = 0xf8000000UL, .size = 0x07e00000UL, @@ -41,42 +52,51 @@ static struct mm_region zynqmp_mem_map[] = { PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN }, { -#if defined(CONFIG_DEFINE_TCM_OCM_MMAP) - .virt = 0xffe00000UL, - .phys = 0xffe00000UL, - .size = 0x00200000UL, - .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | - PTE_BLOCK_INNER_SHARE - }, { -#endif .virt = 0x400000000UL, .phys = 0x400000000UL, .size = 0x400000000UL, .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN - }, -#if !defined(CONFIG_ZYNQMP_NO_DDR) - { - .virt = 0x800000000UL, - .phys = 0x800000000UL, - .size = 0x800000000UL, - .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | - PTE_BLOCK_INNER_SHARE - }, -#endif - { + }, { .virt = 0x1000000000UL, .phys = 0x1000000000UL, .size = 0xf000000000UL, .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN - }, { - /* List terminator */ - 0, } }; + +void mem_map_fill(void) +{ + int banks = ZYNQMP_MEM_MAP_USED; + +#if defined(CONFIG_DEFINE_TCM_OCM_MMAP) + zynqmp_mem_map[banks].virt = 0xffe00000UL; + zynqmp_mem_map[banks].phys = 0xffe00000UL; + zynqmp_mem_map[banks].size = 0x00200000UL; + zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE; + banks = banks + 1; +#endif + +#if !defined(CONFIG_ZYNQMP_NO_DDR) + for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + /* Zero size means no more DDR that's this is end */ + if (!gd->bd->bi_dram[i].size) + break; + + zynqmp_mem_map[banks].virt = gd->bd->bi_dram[i].start; + zynqmp_mem_map[banks].phys = gd->bd->bi_dram[i].start; + zynqmp_mem_map[banks].size = gd->bd->bi_dram[i].size; + zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE; + banks = banks + 1; + } +#endif +} + struct mm_region *mem_map = zynqmp_mem_map; u64 get_page_table_size(void) diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h index d1db4c3..6056bc6 100644 --- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h +++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h @@ -45,7 +45,7 @@ int invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 *ret_payload); void initialize_tcm(bool mode); - +void mem_map_fill(void); int chip_id(unsigned char id); #endif /* _ASM_ARCH_SYS_PROTO_H */ diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 4c6f299..911cd52 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -405,7 +405,15 @@ unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, #if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) int dram_init_banksize(void) { - return fdtdec_setup_memory_banksize(); + int ret; + + ret = fdtdec_setup_memory_banksize(); + if (ret) + return ret; + + mem_map_fill(); + + return 0; } int dram_init(void) @@ -416,6 +424,18 @@ int dram_init(void) return 0; } #else +int dram_init_banksize(void) +{ +#if defined(CONFIG_NR_DRAM_BANKS) + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = get_effective_memsize(); +#endif + + mem_map_fill(); + + return 0; +} + int dram_init(void) { gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, From 0478b0b9b674da35948d7500b595ae14387068ac Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 25 Apr 2018 11:10:34 +0200 Subject: [PATCH 17/31] arm64: zynqmp: Simplify boot_target variable composition Call calloc for space allocation only at one location and include if/else to sprintf. This will simplify run time device adding based on id aliases. Signed-off-by: Michal Simek Reviewed-by: Alexander Graf --- board/xilinx/zynqmp/zynqmp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 911cd52..57c0d93 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -453,6 +453,7 @@ int board_late_init(void) { u32 reg = 0; u8 bootmode; + int env_targets_len = 0; const char *mode; char *new_targets; char *env_targets; @@ -529,14 +530,13 @@ int board_late_init(void) * and default boot_targets */ env_targets = env_get("boot_targets"); - if (env_targets) { - new_targets = calloc(1, strlen(mode) + - strlen(env_targets) + 2); - sprintf(new_targets, "%s %s", mode, env_targets); - } else { - new_targets = calloc(1, strlen(mode) + 2); - sprintf(new_targets, "%s", mode); - } + if (env_targets) + env_targets_len = strlen(env_targets); + + new_targets = calloc(1, strlen(mode) + env_targets_len + 2); + + sprintf(new_targets, "%s %s", mode, + env_targets ? env_targets : ""); env_set("boot_targets", new_targets); From ffdf528007ddd4ae7527951f6694eb31a9162e88 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 30 Apr 2018 09:26:47 +0200 Subject: [PATCH 18/31] arm64: zynqmp: Show model information instead of custom IDENT_STRING DISPLAY_BOARDINFO in OF case show model identification string from DT. Enable this feature instead of custom IDENT_STRING which does the same thing. Signed-off-by: Michal Simek Reviewed-by: Alexander Graf --- configs/xilinx_zynqmp_zc1232_revA_defconfig | 2 -- configs/xilinx_zynqmp_zc1254_revA_defconfig | 2 -- configs/xilinx_zynqmp_zc1275_revA_defconfig | 2 -- configs/xilinx_zynqmp_zc1275_revB_defconfig | 2 -- configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig | 2 -- configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig | 2 -- configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig | 2 -- configs/xilinx_zynqmp_zc1751_xm018_dc4_defconfig | 2 -- configs/xilinx_zynqmp_zc1751_xm019_dc5_defconfig | 2 -- configs/xilinx_zynqmp_zcu100_revC_defconfig | 2 -- configs/xilinx_zynqmp_zcu102_rev1_0_defconfig | 2 -- configs/xilinx_zynqmp_zcu102_revA_defconfig | 2 -- configs/xilinx_zynqmp_zcu102_revB_defconfig | 2 -- configs/xilinx_zynqmp_zcu104_revA_defconfig | 2 -- configs/xilinx_zynqmp_zcu104_revC_defconfig | 2 -- configs/xilinx_zynqmp_zcu106_revA_defconfig | 2 -- configs/xilinx_zynqmp_zcu111_revA_defconfig | 2 -- 17 files changed, 34 deletions(-) diff --git a/configs/xilinx_zynqmp_zc1232_revA_defconfig b/configs/xilinx_zynqmp_zc1232_revA_defconfig index f4e680d..70dc870 100644 --- a/configs/xilinx_zynqmp_zc1232_revA_defconfig +++ b/configs/xilinx_zynqmp_zc1232_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 # CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1232 revA" # CONFIG_SPL_FAT_SUPPORT is not set CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1232-revA" CONFIG_DEBUG_UART=y @@ -13,7 +12,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zc1254_revA_defconfig b/configs/xilinx_zynqmp_zc1254_revA_defconfig index 77b4ada..09de18d 100644 --- a/configs/xilinx_zynqmp_zc1254_revA_defconfig +++ b/configs/xilinx_zynqmp_zc1254_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 # CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1254 revA" # CONFIG_SPL_FAT_SUPPORT is not set CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1254-revA" CONFIG_DEBUG_UART=y @@ -13,7 +12,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zc1275_revA_defconfig b/configs/xilinx_zynqmp_zc1275_revA_defconfig index 17c1be8..a7e79f5 100644 --- a/configs/xilinx_zynqmp_zc1275_revA_defconfig +++ b/configs/xilinx_zynqmp_zc1275_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 # CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1275 revA" # CONFIG_SPL_FAT_SUPPORT is not set CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1275-revA" CONFIG_DEBUG_UART=y @@ -13,7 +12,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zc1275_revB_defconfig b/configs/xilinx_zynqmp_zc1275_revB_defconfig index b073282..823b503 100644 --- a/configs/xilinx_zynqmp_zc1275_revB_defconfig +++ b/configs/xilinx_zynqmp_zc1275_revB_defconfig @@ -5,7 +5,6 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 # CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1275 revB" # CONFIG_SPL_FAT_SUPPORT is not set CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1275-revB" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig b/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig index 0272eea..3aa3930 100644 --- a/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1751 xm015 dc1" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1751-xm015-dc1" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig b/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig index 2758bfb..1bd52ab 100644 --- a/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig @@ -5,7 +5,6 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 # CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1751 xm016 dc2" # CONFIG_SPL_FAT_SUPPORT is not set CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1751-xm016-dc2" @@ -15,7 +14,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig b/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig index a92361e..e1e7d22 100644 --- a/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1751 xm017 dc3" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1751-xm017-dc3" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zc1751_xm018_dc4_defconfig b/configs/xilinx_zynqmp_zc1751_xm018_dc4_defconfig index 9a6a1e5..7e3f2c2 100644 --- a/configs/xilinx_zynqmp_zc1751_xm018_dc4_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm018_dc4_defconfig @@ -3,7 +3,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1751 xm018 dc4" CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1751-xm018-dc4" CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y @@ -11,7 +10,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zc1751_xm019_dc5_defconfig b/configs/xilinx_zynqmp_zc1751_xm019_dc5_defconfig index 8d6b353..dad2105 100644 --- a/configs/xilinx_zynqmp_zc1751_xm019_dc5_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm019_dc5_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZC1751 xm019 dc5" CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zc1751-xm019-dc5" CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y @@ -12,7 +11,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zcu100_revC_defconfig b/configs/xilinx_zynqmp_zcu100_revC_defconfig index 1625ef3..3dd6ae9 100644 --- a/configs/xilinx_zynqmp_zcu100_revC_defconfig +++ b/configs/xilinx_zynqmp_zcu100_revC_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU100 RevC" CONFIG_ZYNQ_SDHCI_MAX_FREQ=15000000 CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu100-revC" @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig index 68da9dc..8e3bef3 100644 --- a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig +++ b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU102 rev1.0" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu102-rev1.0" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zcu102_revA_defconfig b/configs/xilinx_zynqmp_zcu102_revA_defconfig index 2adba61..94dc62a 100644 --- a/configs/xilinx_zynqmp_zcu102_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU102 revA" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu102-revA" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zcu102_revB_defconfig b/configs/xilinx_zynqmp_zcu102_revB_defconfig index 2310fa8..8889f19 100644 --- a/configs/xilinx_zynqmp_zcu102_revB_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revB_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU102 revB" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu102-revB" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_BOARD_EARLY_INIT_R=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y diff --git a/configs/xilinx_zynqmp_zcu104_revA_defconfig b/configs/xilinx_zynqmp_zcu104_revA_defconfig index 817f789..3d3d941 100644 --- a/configs/xilinx_zynqmp_zcu104_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu104_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU104 revA" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu104-revA" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zcu104_revC_defconfig b/configs/xilinx_zynqmp_zcu104_revC_defconfig index 4be3d83..7c22d7f 100644 --- a/configs/xilinx_zynqmp_zcu104_revC_defconfig +++ b/configs/xilinx_zynqmp_zcu104_revC_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU104 revC" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu104-revC" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zcu106_revA_defconfig b/configs/xilinx_zynqmp_zcu106_revA_defconfig index 8c9a60d..017940e 100644 --- a/configs/xilinx_zynqmp_zcu106_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu106_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU106 revA" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu106-revA" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y diff --git a/configs/xilinx_zynqmp_zcu111_revA_defconfig b/configs/xilinx_zynqmp_zcu111_revA_defconfig index cb4542c..028a7b5 100644 --- a/configs/xilinx_zynqmp_zcu111_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu111_revA_defconfig @@ -4,7 +4,6 @@ CONFIG_ARCH_ZYNQMP=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU111" CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu111-revA" CONFIG_DEBUG_UART=y @@ -14,7 +13,6 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_SPL_LOAD_FIT=y # CONFIG_DISPLAY_CPUINFO is not set -# CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y From e9dbfb32edaf4159e92299346db58041a7baab93 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 13 Apr 2018 14:18:49 +0200 Subject: [PATCH 19/31] tools: zynqmpimage: Add partition read support The zynqmp image format has support for inline partitions which are used by FSBL to describe payloads that are loaded by FSBL itself. While we can't create images that contain partitions (yet), we should still at least be able to examine them and show the user what's inside when we analyze an image created by bootgen. Signed-off-by: Alexander Graf Signed-off-by: Michal Simek --- tools/zynqmpimage.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 2 deletions(-) diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 421558d..e972c68 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -6,6 +6,7 @@ * The following Boot Header format/structures and values are defined in the * following documents: * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) + * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16) * * Expected Header Size = 0x9C0 * Forced as 'little' endian, 32-bit words @@ -62,6 +63,7 @@ #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) +#define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) enum { ENCRYPTION_EFUSE = 0xa5c3c5a3, @@ -79,6 +81,78 @@ struct zynqmp_reginit { #define HEADER_INTERRUPT_VECTORS 8 #define HEADER_REGINITS 256 +struct image_header_table { + uint32_t version; /* 0x00 */ + uint32_t nr_parts; /* 0x04 */ + uint32_t partition_header_offset; /* 0x08, divided by 4 */ + uint32_t image_header_offset; /* 0x0c, divided by 4 */ + uint32_t auth_certificate_offset; /* 0x10 */ + uint32_t boot_device; /* 0x14 */ + uint32_t __reserved1[9]; /* 0x18 - 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +#define PART_ATTR_VEC_LOCATION 0x800000 +#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 +#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 +#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 +#define PART_ATTR_BIG_ENDIAN 0x040000 +#define PART_ATTR_PART_OWNER_MASK 0x030000 +#define PART_ATTR_PART_OWNER_FSBL 0x000000 +#define PART_ATTR_PART_OWNER_UBOOT 0x010000 +#define PART_ATTR_RSA_SIG 0x008000 +#define PART_ATTR_CHECKSUM_MASK 0x007000 +#define PART_ATTR_CHECKSUM_NONE 0x000000 +#define PART_ATTR_CHECKSUM_MD5 0x001000 +#define PART_ATTR_CHECKSUM_SHA2 0x002000 +#define PART_ATTR_CHECKSUM_SHA3 0x003000 +#define PART_ATTR_DEST_CPU_SHIFT 8 +#define PART_ATTR_DEST_CPU_MASK 0x000f00 +#define PART_ATTR_DEST_CPU_NONE 0x000000 +#define PART_ATTR_DEST_CPU_A53_0 0x000100 +#define PART_ATTR_DEST_CPU_A53_1 0x000200 +#define PART_ATTR_DEST_CPU_A53_2 0x000300 +#define PART_ATTR_DEST_CPU_A53_3 0x000400 +#define PART_ATTR_DEST_CPU_R5_0 0x000500 +#define PART_ATTR_DEST_CPU_R5_1 0x000600 +#define PART_ATTR_DEST_CPU_R5_L 0x000700 +#define PART_ATTR_DEST_CPU_PMU 0x000800 +#define PART_ATTR_ENCRYPTED 0x000080 +#define PART_ATTR_DEST_DEVICE_SHIFT 4 +#define PART_ATTR_DEST_DEVICE_MASK 0x000070 +#define PART_ATTR_DEST_DEVICE_NONE 0x000000 +#define PART_ATTR_DEST_DEVICE_PS 0x000010 +#define PART_ATTR_DEST_DEVICE_PL 0x000020 +#define PART_ATTR_DEST_DEVICE_PMU 0x000030 +#define PART_ATTR_DEST_DEVICE_XIP 0x000040 +#define PART_ATTR_A53_EXEC_AARCH32 0x000008 +#define PART_ATTR_TARGET_EL_SHIFT 1 +#define PART_ATTR_TARGET_EL_MASK 0x000006 +#define PART_ATTR_TZ_SECURE 0x000001 + +static const char *dest_cpus[0x10] = { + "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", + "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", + "unknown", "unknown", "unknown" +}; + +struct partition_header { + uint32_t len_enc; /* 0x00, divided by 4 */ + uint32_t len_unenc; /* 0x04, divided by 4 */ + uint32_t len; /* 0x08, divided by 4 */ + uint32_t next_partition_offset; /* 0x0c */ + uint64_t entry_point; /* 0x10 */ + uint64_t load_address; /* 0x18 */ + uint32_t offset; /* 0x20, divided by 4 */ + uint32_t attributes; /* 0x24 */ + uint32_t __reserved1; /* 0x28 */ + uint32_t checksum_offset; /* 0x2c, divided by 4 */ + uint32_t __reserved2; /* 0x30 */ + uint32_t auth_certificate_offset; /* 0x34 */ + uint32_t __reserved3; /* 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + struct zynqmp_header { uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ uint32_t width_detection; /* 0x20 */ @@ -92,7 +166,9 @@ struct zynqmp_header { uint32_t image_stored_size; /* 0x40 */ uint32_t image_attributes; /* 0x44 */ uint32_t checksum; /* 0x48 */ - uint32_t __reserved1[27]; /* 0x4c */ + uint32_t __reserved1[19]; /* 0x4c */ + uint32_t image_header_table_offset; /* 0x98 */ + uint32_t __reserved2[7]; /* 0x9c */ struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ uint32_t __reserved4[66]; /* 0x9c0 */ }; @@ -131,7 +207,7 @@ static void zynqmpimage_default_header(struct zynqmp_header *ptr) return; ptr->width_detection = HEADER_WIDTHDETECTION; - ptr->image_attributes = 0x800; + ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT; ptr->image_identifier = HEADER_IMAGEIDENTIFIER; ptr->encryption = cpu_to_le32(ENCRYPTION_NONE); @@ -172,6 +248,80 @@ static int zynqmpimage_verify_header(unsigned char *ptr, int image_size, return 0; } +static void print_partition(const void *ptr, const struct partition_header *ph) +{ + uint32_t attr = le32_to_cpu(ph->attributes); + unsigned long len = le32_to_cpu(ph->len) * 4; + const char *part_owner; + const char *dest_devs[0x8] = { + "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown", + "unknown" + }; + + switch (attr & PART_ATTR_PART_OWNER_MASK) { + case PART_ATTR_PART_OWNER_FSBL: + part_owner = "FSBL"; + break; + case PART_ATTR_PART_OWNER_UBOOT: + part_owner = "U-Boot"; + break; + default: + part_owner = "Unknown"; + break; + } + + printf("%s payload on CPU %s (%s):\n", part_owner, + dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8], + dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]); + + printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4); + printf(" Size : %lu (0x%lx) bytes\n", len, len); + printf(" Load : 0x%08llx", + (unsigned long long)le64_to_cpu(ph->load_address)); + if (ph->load_address != ph->entry_point) + printf(" (entry=0x%08llx)\n", + (unsigned long long)le64_to_cpu(ph->entry_point)); + else + printf("\n"); + printf(" Attributes : "); + + if (attr & PART_ATTR_VEC_LOCATION) + printf("vec "); + + if (attr & PART_ATTR_ENCRYPTED) + printf("encrypted "); + + switch (attr & PART_ATTR_CHECKSUM_MASK) { + case PART_ATTR_CHECKSUM_MD5: + printf("md5 "); + break; + case PART_ATTR_CHECKSUM_SHA2: + printf("sha2 "); + break; + case PART_ATTR_CHECKSUM_SHA3: + printf("sha3 "); + break; + } + + if (attr & PART_ATTR_BIG_ENDIAN) + printf("BigEndian "); + + if (attr & PART_ATTR_RSA_SIG) + printf("RSA "); + + if (attr & PART_ATTR_A53_EXEC_AARCH32) + printf("AArch32 "); + + if (attr & PART_ATTR_TARGET_EL_MASK) + printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1); + + if (attr & PART_ATTR_TZ_SECURE) + printf("secure "); + printf("\n"); + + printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum)); +} + static void zynqmpimage_print_header(const void *ptr) { struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; @@ -212,6 +362,27 @@ static void zynqmpimage_print_header(const void *ptr) le32_to_cpu(zynqhdr->register_init[i].data)); } + if (zynqhdr->image_header_table_offset) { + struct image_header_table *iht = (void *)ptr + + zynqhdr->image_header_table_offset; + struct partition_header *ph; + uint32_t ph_offset; + uint32_t next; + int i; + + ph_offset = le32_to_cpu(iht->partition_header_offset) * 4; + ph = (void *)ptr + ph_offset; + for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { + next = le32_to_cpu(ph->next_partition_offset) * 4; + + /* Partition 0 is the base image itself */ + if (i) + print_partition(ptr, ph); + + ph = (void *)ptr + next; + } + } + free(dynamic_header); } From e384cdf873f052092016925e1fe4810cdf2c71f9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 13 Apr 2018 14:18:50 +0200 Subject: [PATCH 20/31] tools: zynqmpimage: Move defines to header We will add support for ZynqMP bif input files later, so let's move all structure definitions into a header file that can be used by that one as well. Signed-off-by: Alexander Graf Signed-off-by: Michal Simek --- tools/zynqmpimage.c | 115 +-------------------------------------------- tools/zynqmpimage.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 tools/zynqmpimage.h diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index e972c68..870a6b5 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -57,122 +57,9 @@ #include "imagetool.h" #include "mkimage.h" +#include "zynqmpimage.h" #include -#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe)) -#define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) -#define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) -#define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) -#define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) - -enum { - ENCRYPTION_EFUSE = 0xa5c3c5a3, - ENCRYPTION_OEFUSE = 0xa5c3c5a7, - ENCRYPTION_BBRAM = 0x3a5c3c5a, - ENCRYPTION_OBBRAM = 0xa35c7ca5, - ENCRYPTION_NONE = 0x0, -}; - -struct zynqmp_reginit { - uint32_t address; - uint32_t data; -}; - -#define HEADER_INTERRUPT_VECTORS 8 -#define HEADER_REGINITS 256 - -struct image_header_table { - uint32_t version; /* 0x00 */ - uint32_t nr_parts; /* 0x04 */ - uint32_t partition_header_offset; /* 0x08, divided by 4 */ - uint32_t image_header_offset; /* 0x0c, divided by 4 */ - uint32_t auth_certificate_offset; /* 0x10 */ - uint32_t boot_device; /* 0x14 */ - uint32_t __reserved1[9]; /* 0x18 - 0x38 */ - uint32_t checksum; /* 0x3c */ -}; - -#define PART_ATTR_VEC_LOCATION 0x800000 -#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 -#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 -#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 -#define PART_ATTR_BIG_ENDIAN 0x040000 -#define PART_ATTR_PART_OWNER_MASK 0x030000 -#define PART_ATTR_PART_OWNER_FSBL 0x000000 -#define PART_ATTR_PART_OWNER_UBOOT 0x010000 -#define PART_ATTR_RSA_SIG 0x008000 -#define PART_ATTR_CHECKSUM_MASK 0x007000 -#define PART_ATTR_CHECKSUM_NONE 0x000000 -#define PART_ATTR_CHECKSUM_MD5 0x001000 -#define PART_ATTR_CHECKSUM_SHA2 0x002000 -#define PART_ATTR_CHECKSUM_SHA3 0x003000 -#define PART_ATTR_DEST_CPU_SHIFT 8 -#define PART_ATTR_DEST_CPU_MASK 0x000f00 -#define PART_ATTR_DEST_CPU_NONE 0x000000 -#define PART_ATTR_DEST_CPU_A53_0 0x000100 -#define PART_ATTR_DEST_CPU_A53_1 0x000200 -#define PART_ATTR_DEST_CPU_A53_2 0x000300 -#define PART_ATTR_DEST_CPU_A53_3 0x000400 -#define PART_ATTR_DEST_CPU_R5_0 0x000500 -#define PART_ATTR_DEST_CPU_R5_1 0x000600 -#define PART_ATTR_DEST_CPU_R5_L 0x000700 -#define PART_ATTR_DEST_CPU_PMU 0x000800 -#define PART_ATTR_ENCRYPTED 0x000080 -#define PART_ATTR_DEST_DEVICE_SHIFT 4 -#define PART_ATTR_DEST_DEVICE_MASK 0x000070 -#define PART_ATTR_DEST_DEVICE_NONE 0x000000 -#define PART_ATTR_DEST_DEVICE_PS 0x000010 -#define PART_ATTR_DEST_DEVICE_PL 0x000020 -#define PART_ATTR_DEST_DEVICE_PMU 0x000030 -#define PART_ATTR_DEST_DEVICE_XIP 0x000040 -#define PART_ATTR_A53_EXEC_AARCH32 0x000008 -#define PART_ATTR_TARGET_EL_SHIFT 1 -#define PART_ATTR_TARGET_EL_MASK 0x000006 -#define PART_ATTR_TZ_SECURE 0x000001 - -static const char *dest_cpus[0x10] = { - "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", - "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", - "unknown", "unknown", "unknown" -}; - -struct partition_header { - uint32_t len_enc; /* 0x00, divided by 4 */ - uint32_t len_unenc; /* 0x04, divided by 4 */ - uint32_t len; /* 0x08, divided by 4 */ - uint32_t next_partition_offset; /* 0x0c */ - uint64_t entry_point; /* 0x10 */ - uint64_t load_address; /* 0x18 */ - uint32_t offset; /* 0x20, divided by 4 */ - uint32_t attributes; /* 0x24 */ - uint32_t __reserved1; /* 0x28 */ - uint32_t checksum_offset; /* 0x2c, divided by 4 */ - uint32_t __reserved2; /* 0x30 */ - uint32_t auth_certificate_offset; /* 0x34 */ - uint32_t __reserved3; /* 0x38 */ - uint32_t checksum; /* 0x3c */ -}; - -struct zynqmp_header { - uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ - uint32_t width_detection; /* 0x20 */ - uint32_t image_identifier; /* 0x24 */ - uint32_t encryption; /* 0x28 */ - uint32_t image_load; /* 0x2c */ - uint32_t image_offset; /* 0x30 */ - uint32_t pfw_image_length; /* 0x34 */ - uint32_t total_pfw_image_length; /* 0x38 */ - uint32_t image_size; /* 0x3c */ - uint32_t image_stored_size; /* 0x40 */ - uint32_t image_attributes; /* 0x44 */ - uint32_t checksum; /* 0x48 */ - uint32_t __reserved1[19]; /* 0x4c */ - uint32_t image_header_table_offset; /* 0x98 */ - uint32_t __reserved2[7]; /* 0x9c */ - struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ - uint32_t __reserved4[66]; /* 0x9c0 */ -}; - static struct zynqmp_header zynqmpimage_header; static void *dynamic_header; static FILE *fpmu; diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h new file mode 100644 index 0000000..f3b5c19 --- /dev/null +++ b/tools/zynqmpimage.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Michal Simek + * Copyright (C) 2015 Nathan Rossi + * + * SPDX-License-Identifier: GPL-2.0+ + * + * The following Boot Header format/structures and values are defined in the + * following documents: + * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) + * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16) + */ + +#ifndef _ZYNQMPIMAGE_H_ +#define _ZYNQMPIMAGE_H_ + +#include + +#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe)) +#define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) +#define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) +#define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) +#define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) + +enum { + ENCRYPTION_EFUSE = 0xa5c3c5a3, + ENCRYPTION_OEFUSE = 0xa5c3c5a7, + ENCRYPTION_BBRAM = 0x3a5c3c5a, + ENCRYPTION_OBBRAM = 0xa35c7ca5, + ENCRYPTION_NONE = 0x0, +}; + +struct zynqmp_reginit { + uint32_t address; + uint32_t data; +}; + +#define HEADER_INTERRUPT_VECTORS 8 +#define HEADER_REGINITS 256 + +struct image_header_table { + uint32_t version; /* 0x00 */ + uint32_t nr_parts; /* 0x04 */ + uint32_t partition_header_offset; /* 0x08, divided by 4 */ + uint32_t image_header_offset; /* 0x0c, divided by 4 */ + uint32_t auth_certificate_offset; /* 0x10 */ + uint32_t boot_device; /* 0x14 */ + uint32_t __reserved1[9]; /* 0x18 - 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +#define PART_ATTR_VEC_LOCATION 0x800000 +#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 +#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 +#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 +#define PART_ATTR_BIG_ENDIAN 0x040000 +#define PART_ATTR_PART_OWNER_MASK 0x030000 +#define PART_ATTR_PART_OWNER_FSBL 0x000000 +#define PART_ATTR_PART_OWNER_UBOOT 0x010000 +#define PART_ATTR_RSA_SIG 0x008000 +#define PART_ATTR_CHECKSUM_MASK 0x007000 +#define PART_ATTR_CHECKSUM_NONE 0x000000 +#define PART_ATTR_CHECKSUM_MD5 0x001000 +#define PART_ATTR_CHECKSUM_SHA2 0x002000 +#define PART_ATTR_CHECKSUM_SHA3 0x003000 +#define PART_ATTR_DEST_CPU_SHIFT 8 +#define PART_ATTR_DEST_CPU_MASK 0x000f00 +#define PART_ATTR_DEST_CPU_NONE 0x000000 +#define PART_ATTR_DEST_CPU_A53_0 0x000100 +#define PART_ATTR_DEST_CPU_A53_1 0x000200 +#define PART_ATTR_DEST_CPU_A53_2 0x000300 +#define PART_ATTR_DEST_CPU_A53_3 0x000400 +#define PART_ATTR_DEST_CPU_R5_0 0x000500 +#define PART_ATTR_DEST_CPU_R5_1 0x000600 +#define PART_ATTR_DEST_CPU_R5_L 0x000700 +#define PART_ATTR_DEST_CPU_PMU 0x000800 +#define PART_ATTR_ENCRYPTED 0x000080 +#define PART_ATTR_DEST_DEVICE_SHIFT 4 +#define PART_ATTR_DEST_DEVICE_MASK 0x000070 +#define PART_ATTR_DEST_DEVICE_NONE 0x000000 +#define PART_ATTR_DEST_DEVICE_PS 0x000010 +#define PART_ATTR_DEST_DEVICE_PL 0x000020 +#define PART_ATTR_DEST_DEVICE_PMU 0x000030 +#define PART_ATTR_DEST_DEVICE_XIP 0x000040 +#define PART_ATTR_A53_EXEC_AARCH32 0x000008 +#define PART_ATTR_TARGET_EL_SHIFT 1 +#define PART_ATTR_TARGET_EL_MASK 0x000006 +#define PART_ATTR_TZ_SECURE 0x000001 + +static const char *dest_cpus[0x10] = { + "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", + "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", + "unknown", "unknown", "unknown" +}; + +struct partition_header { + uint32_t len_enc; /* 0x00, divided by 4 */ + uint32_t len_unenc; /* 0x04, divided by 4 */ + uint32_t len; /* 0x08, divided by 4 */ + uint32_t next_partition_offset; /* 0x0c */ + uint64_t entry_point; /* 0x10 */ + uint64_t load_address; /* 0x18 */ + uint32_t offset; /* 0x20, divided by 4 */ + uint32_t attributes; /* 0x24 */ + uint32_t __reserved1; /* 0x28 */ + uint32_t checksum_offset; /* 0x2c, divided by 4 */ + uint32_t __reserved2; /* 0x30 */ + uint32_t auth_certificate_offset; /* 0x34 */ + uint32_t __reserved3; /* 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +struct zynqmp_header { + uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ + uint32_t width_detection; /* 0x20 */ + uint32_t image_identifier; /* 0x24 */ + uint32_t encryption; /* 0x28 */ + uint32_t image_load; /* 0x2c */ + uint32_t image_offset; /* 0x30 */ + uint32_t pfw_image_length; /* 0x34 */ + uint32_t total_pfw_image_length; /* 0x38 */ + uint32_t image_size; /* 0x3c */ + uint32_t image_stored_size; /* 0x40 */ + uint32_t image_attributes; /* 0x44 */ + uint32_t checksum; /* 0x48 */ + uint32_t __reserved1[19]; /* 0x4c */ + uint32_t image_header_table_offset; /* 0x98 */ + uint32_t __reserved2[7]; /* 0x9c */ + struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ + uint32_t __reserved4[66]; /* 0x9c0 */ +}; + +#endif /* _ZYNQMPIMAGE_H_ */ From b123aff26f580343adf57b5145d8334cd2a4b6b4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 13 Apr 2018 14:18:51 +0200 Subject: [PATCH 21/31] MAINTAINERS: Declare tools/zynqmp* as Xilinx maintained The zynqmpimage.c and the new zynqmpbif.c files are all maintained by Xilinx for the Zynq platforms. Let's match them accordingly in the MAINTAINERS file. Signed-off-by: Alexander Graf Signed-off-by: Michal Simek --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 031f7ea..c2ae68c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -292,7 +292,7 @@ F: drivers/timer/cadence-ttc.c F: drivers/usb/host/ehci-zynq.c F: drivers/watchdog/cdns_wdt.c F: include/zynqmppl.h -F: tools/zynqimage.c +F: tools/zynqmp* N: zynqmp BUILDMAN From 6915dcf35987d654b491524f151e56b91e0d0ec9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 13 Apr 2018 14:18:52 +0200 Subject: [PATCH 22/31] tools: zynqmpimage: Add bif support The officially described way to generate boot.bin files for ZynqMP is to describe the contents of the target binary using a file of the "bif" format. This file then links to other files that all get packed into a bootable image. This patch adds support to read such a .bif file and generate a respective ZynqMP boot.bin file that can include the normal image and pmu files, but also supports image partitions now. This makes it a handy replacement for the proprietary "bootgen" utility that is currently used to generate boot.bin files with FSBL. Signed-off-by: Alexander Graf Signed-off-by: Michal Simek --- common/image.c | 1 + include/image.h | 1 + tools/Makefile | 1 + tools/imagetool.h | 1 + tools/mkimage.c | 7 + tools/zynqmpbif.c | 1008 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/zynqmpimage.c | 4 +- tools/zynqmpimage.h | 7 + 8 files changed, 1028 insertions(+), 2 deletions(-) create mode 100644 tools/zynqmpbif.c diff --git a/common/image.c b/common/image.c index 4eae585..87d1501 100644 --- a/common/image.c +++ b/common/image.c @@ -158,6 +158,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_VYBRIDIMAGE, "vybridimage", "Vybrid Boot Image", }, { IH_TYPE_ZYNQIMAGE, "zynqimage", "Xilinx Zynq Boot Image" }, { IH_TYPE_ZYNQMPIMAGE, "zynqmpimage", "Xilinx ZynqMP Boot Image" }, + { IH_TYPE_ZYNQMPBIF, "zynqmpbif", "Xilinx ZynqMP Boot Image (bif)" }, { IH_TYPE_FPGA, "fpga", "FPGA Image" }, { IH_TYPE_TEE, "tee", "Trusted Execution Environment Image",}, { IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" }, diff --git a/include/image.h b/include/image.h index 6a22c98..8fa75a5 100644 --- a/include/image.h +++ b/include/image.h @@ -268,6 +268,7 @@ enum { IH_TYPE_RKSPI, /* Rockchip SPI image */ IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ + IH_TYPE_ZYNQMPBIF, /* Xilinx ZynqMP Boot Image (bif) */ IH_TYPE_FPGA, /* FPGA Image */ IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ diff --git a/tools/Makefile b/tools/Makefile index 1185bf5..5dd33ed 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -111,6 +111,7 @@ dumpimage-mkimage-objs := aisimage.o \ ublimage.o \ zynqimage.o \ zynqmpimage.o \ + zynqmpbif.o \ $(LIBFDT_OBJS) \ gpimage.o \ gpimage-common.o \ diff --git a/tools/imagetool.h b/tools/imagetool.h index ef2429e..d191b9c 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -231,6 +231,7 @@ time_t imagetool_get_source_date( void pbl_load_uboot(int fd, struct image_tool_params *mparams); +int zynqmpbif_copy_image(int fd, struct image_tool_params *mparams); #define ___cat(a, b) a ## b #define __cat(a, b) ___cat(a, b) diff --git a/tools/mkimage.c b/tools/mkimage.c index 64ad131..e0d4d20 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -515,6 +515,13 @@ int main(int argc, char **argv) } else if (params.type == IH_TYPE_PBLIMAGE) { /* PBL has special Image format, implements its' own */ pbl_load_uboot(ifd, ¶ms); + } else if (params.type == IH_TYPE_ZYNQMPBIF) { + /* Image file is meta, walk through actual targets */ + int ret; + + ret = zynqmpbif_copy_image(ifd, ¶ms); + if (ret) + return ret; } else { copy_file(ifd, params.datafile, pad_len); } diff --git a/tools/zynqmpbif.c b/tools/zynqmpbif.c new file mode 100644 index 0000000..6c8f660 --- /dev/null +++ b/tools/zynqmpbif.c @@ -0,0 +1,1008 @@ +/* + * Copyright (C) 2018 Alexander Graf + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include "mkimage.h" +#include "zynqmpimage.h" +#include +#include + +struct bif_entry { + const char *filename; + uint64_t flags; + uint64_t dest_cpu; + uint64_t exp_lvl; + uint64_t dest_dev; + uint64_t load; + uint64_t entry; + size_t offset; +}; + +enum bif_flag { + BIF_FLAG_AESKEYFILE, + BIF_FLAG_INIT, + BIF_FLAG_UDF_BH, + BIF_FLAG_HEADERSIGNATURE, + BIF_FLAG_PPKFILE, + BIF_FLAG_PSKFILE, + BIF_FLAG_SPKFILE, + BIF_FLAG_SSKFILE, + BIF_FLAG_SPKSIGNATURE, + BIF_FLAG_FSBL_CONFIG, + BIF_FLAG_AUTH_PARAMS, + BIF_FLAG_KEYSRC_ENCRYPTION, + BIF_FLAG_PMUFW_IMAGE, + BIF_FLAG_BOOTLOADER, + BIF_FLAG_TZ, + BIF_FLAG_BH_KEY_IV, + BIF_FLAG_BH_KEYFILE, + BIF_FLAG_PUF_FILE, + BIF_FLAG_AARCH32, + BIF_FLAG_PART_OWNER_UBOOT, + + /* Internal flags */ + BIF_FLAG_BIT_FILE, + BIF_FLAG_ELF_FILE, + BIF_FLAG_BIN_FILE, +}; + +struct bif_flags { + const char name[32]; + uint64_t flag; + char *(*parse)(char *line, struct bif_entry *bf); +}; + +struct bif_file_type { + const char name[32]; + uint32_t header; + int (*add)(struct bif_entry *bf); +}; + +struct bif_output { + size_t data_len; + char *data; + struct image_header_table *imgheader; + struct zynqmp_header *header; + struct partition_header *last_part; +}; + +struct bif_output bif_output; + +static uint32_t zynqmp_csum(void *start, void *end) +{ + uint32_t checksum = 0; + uint32_t *ptr32 = start; + + while (ptr32 != end) { + checksum += le32_to_cpu(*ptr32); + ptr32++; + } + + return ~checksum; +} + +static int zynqmpbif_check_params(struct image_tool_params *params) +{ + if (!params) + return 0; + + if (params->addr != 0x0) { + fprintf(stderr, "Error: Load Address can not be specified.\n"); + return -1; + } + + if (params->eflag) { + fprintf(stderr, "Error: Entry Point can not be specified.\n"); + return -1; + } + + return !(params->lflag || params->dflag); +} + +static int zynqmpbif_check_image_types(uint8_t type) +{ + return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static char *parse_dest_cpu(char *line, struct bif_entry *bf) +{ + uint64_t i; + + for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) { + if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) { + bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; + return line + strlen(dest_cpus[i]); + } + + /* a5x can also be written as a53 */ + if (!strncmp(dest_cpus[i], "a5x", 3)) { + char a53[] = "a53-X"; + + a53[4] = dest_cpus[i][4]; + if (!strncmp(line, a53, strlen(a53))) { + bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; + return line + strlen(a53); + } + } + } + + return line; +} + +static char *parse_el(char *line, struct bif_entry *bf) +{ + const char *dest_els[] = { "none", "el-0", "el-1", "el-2", "el-3" }; + int i; + + for (i = 0; i < ARRAY_SIZE(dest_els); i++) { + if (!strncmp(line, dest_els[i], strlen(dest_els[i]))) { + bf->exp_lvl = i; + return line + strlen(dest_els[i]); + } + } + + return line; +} + +static char *parse_load(char *line, struct bif_entry *bf) +{ + char *endptr; + + bf->load = strtoll(line, &endptr, 0); + + return endptr; +} + +static char *parse_entry(char *line, struct bif_entry *bf) +{ + char *endptr; + + bf->entry = strtoll(line, &endptr, 0); + + return endptr; +} + +static char *parse_offset(char *line, struct bif_entry *bf) +{ + char *endptr; + + bf->offset = strtoll(line, &endptr, 0); + + return endptr; +} + +static char *parse_partition_owner(char *line, struct bif_entry *bf) +{ + char *endptr = NULL; + + if (!strncmp(line, "fsbl", 4)) { + endptr = line + 4; + } else if (!strncmp(line, "uboot", 5)) { + bf->flags |= 1ULL << BIF_FLAG_PART_OWNER_UBOOT; + endptr = line + 5; + } else { + printf("ERROR: Unknown partition type '%s'\n", line); + } + + return endptr; +} + +static const struct bif_flags bif_flags[] = { + { "fsbl_config", BIF_FLAG_FSBL_CONFIG }, + { "trustzone", BIF_FLAG_TZ }, + { "pmufw_image", BIF_FLAG_PMUFW_IMAGE }, + { "bootloader", BIF_FLAG_BOOTLOADER }, + { "destination_cpu=", 0, parse_dest_cpu }, + { "exception_level=", 0, parse_el }, + { "load=", 0, parse_load }, + { "startup=", 0, parse_entry }, + { "offset=", 0, parse_offset }, + { "partition_owner=", 0, parse_partition_owner }, +}; + +static char *read_full_file(const char *filename, size_t *size) +{ + char *buf, *bufp; + struct stat sbuf; + int len = 0, r, fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + if (fstat(fd, &sbuf) < 0) + return NULL; + + if (size) + *size = sbuf.st_size; + + buf = malloc(sbuf.st_size); + if (!buf) + return NULL; + + bufp = buf; + while (len < sbuf.st_size) { + r = read(fd, bufp, sbuf.st_size - len); + if (r < 0) + return NULL; + len += r; + bufp += r; + } + + close(fd); + + return buf; +} + +static int bif_add_blob(const void *data, size_t len, size_t *offset) +{ + size_t new_size; + uintptr_t header_off; + uintptr_t last_part_off; + uintptr_t imgheader_off; + uintptr_t old_data = (uintptr_t)bif_output.data; + void *new_data; + + header_off = (uintptr_t)bif_output.header - old_data; + last_part_off = (uintptr_t)bif_output.last_part - old_data; + imgheader_off = (uintptr_t)bif_output.imgheader - old_data; + + if (offset && *offset) { + /* Pad to a given offset */ + if (bif_output.data_len > *offset) { + printf("Can not pad to offset %zx\n", *offset); + return -1; + } + + bif_output.data_len = *offset; + } + + new_size = ROUND(bif_output.data_len + len, 64); + new_data = realloc(bif_output.data, new_size); + memcpy(new_data + bif_output.data_len, data, len); + if (offset) + *offset = bif_output.data_len; + bif_output.data = new_data; + bif_output.data_len = new_size; + + /* Readjust internal pointers */ + if (bif_output.header) + bif_output.header = new_data + header_off; + if (bif_output.last_part) + bif_output.last_part = new_data + last_part_off; + if (bif_output.imgheader) + bif_output.imgheader = new_data + imgheader_off; + + return 0; +} + +static int bif_init(void) +{ + struct zynqmp_header header = { { 0 } }; + int r; + + zynqmpimage_default_header(&header); + + r = bif_add_blob(&header, sizeof(header), NULL); + if (r) + return r; + + bif_output.header = (void *)bif_output.data; + + return 0; +} + +static int bif_add_pmufw(struct bif_entry *bf, const char *data, size_t len) +{ + int r; + + if (bif_output.header->image_offset) { + printf("PMUFW expected before bootloader in your .bif file!\n"); + return -1; + } + + r = bif_add_blob(data, len, &bf->offset); + if (r) + return r; + + len = ROUND(len, 64); + bif_output.header->pfw_image_length = cpu_to_le32(len); + bif_output.header->total_pfw_image_length = cpu_to_le32(len); + bif_output.header->image_offset = cpu_to_le32(bf->offset); + + return 0; +} + +static int bif_add_part(struct bif_entry *bf, const char *data, size_t len) +{ + size_t parthdr_offset = 0; + struct partition_header parthdr = { + .len_enc = cpu_to_le32(len / 4), + .len_unenc = cpu_to_le32(len / 4), + .len = cpu_to_le32(len / 4), + .entry_point = cpu_to_le64(bf->entry), + .load_address = cpu_to_le64(bf->load), + }; + int r; + uint32_t csum; + + if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) + return bif_add_pmufw(bf, data, len); + + r = bif_add_blob(data, len, &bf->offset); + if (r) + return r; + + parthdr.offset = cpu_to_le32(bf->offset / 4); + + if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { + if (bif_output.last_part) { + printf("ERROR: Bootloader expected before others\n"); + return -1; + } + + parthdr.offset = cpu_to_le32(bif_output.header->image_offset); + parthdr.len = cpu_to_le32((bf->offset + len - + bif_output.header->image_offset) / 4); + parthdr.len_enc = parthdr.len; + parthdr.len_unenc = parthdr.len; + } + + /* Normalize EL */ + bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3; + parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT; + parthdr.attributes |= bf->dest_dev; + parthdr.attributes |= bf->dest_cpu; + if (bf->flags & (1ULL << BIF_FLAG_TZ)) + parthdr.attributes |= PART_ATTR_TZ_SECURE; + if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT)) + parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT; + switch (bf->dest_cpu) { + case PART_ATTR_DEST_CPU_NONE: + case PART_ATTR_DEST_CPU_A53_0: + case PART_ATTR_DEST_CPU_A53_1: + case PART_ATTR_DEST_CPU_A53_2: + case PART_ATTR_DEST_CPU_A53_3: + if (bf->flags & (1ULL << BIF_FLAG_AARCH32)) + parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32; + } + + csum = zynqmp_csum(&parthdr, &parthdr.checksum); + parthdr.checksum = cpu_to_le32(csum); + + r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset); + if (r) + return r; + + /* Add image header table if not there yet */ + if (!bif_output.imgheader) { + size_t imghdr_off = 0; + struct image_header_table imghdr = { + .version = cpu_to_le32(0x01020000), + .nr_parts = 0, + }; + + r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off); + if (r) + return r; + + bif_output.header->image_header_table_offset = imghdr_off; + bif_output.imgheader = (void *)(bif_output.data + imghdr_off); + } + + bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu( + bif_output.imgheader->nr_parts) + 1); + + /* Link to this partition header */ + if (bif_output.last_part) { + bif_output.last_part->next_partition_offset = + cpu_to_le32(parthdr_offset / 4); + + /* Recalc checksum of last_part */ + csum = zynqmp_csum(bif_output.last_part, + &bif_output.last_part->checksum); + bif_output.last_part->checksum = cpu_to_le32(csum); + } else { + bif_output.imgheader->partition_header_offset = + cpu_to_le32(parthdr_offset / 4); + } + bif_output.last_part = (void *)(bif_output.data + parthdr_offset); + + if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { + bif_output.header->image_load = cpu_to_le32(bf->load); + if (!bif_output.header->image_offset) + bif_output.header->image_offset = + cpu_to_le32(bf->offset); + bif_output.header->image_size = cpu_to_le32(len); + bif_output.header->image_stored_size = cpu_to_le32(len); + + bif_output.header->image_attributes &= ~HEADER_CPU_SELECT_MASK; + switch (bf->dest_cpu) { + default: + case PART_ATTR_DEST_CPU_A53_0: + if (bf->flags & BIF_FLAG_AARCH32) + bif_output.header->image_attributes |= + HEADER_CPU_SELECT_A53_32BIT; + else + bif_output.header->image_attributes |= + HEADER_CPU_SELECT_A53_64BIT; + break; + case PART_ATTR_DEST_CPU_R5_0: + bif_output.header->image_attributes |= + HEADER_CPU_SELECT_R5_SINGLE; + break; + case PART_ATTR_DEST_CPU_R5_L: + bif_output.header->image_attributes |= + HEADER_CPU_SELECT_R5_DUAL; + break; + } + } + + return 0; +} + +/* Add .bit bitstream */ +static int bif_add_bit(struct bif_entry *bf) +{ + char *bit = read_full_file(bf->filename, NULL); + char *bitbin; + uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, + 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 }; + uint16_t len; + uint32_t bitlen; + int i; + + if (!bit) + return -1; + + /* Skip initial header */ + if (memcmp(bit, initial_header, sizeof(initial_header))) + return -1; + + bit += sizeof(initial_header); + + /* Design name */ + len = be16_to_cpu(*(uint16_t *)bit); + bit += sizeof(uint16_t); + debug("Design: %s\n", bit); + bit += len; + + /* Device identifier */ + if (*bit != 'b') + return -1; + bit++; + len = be16_to_cpu(*(uint16_t *)bit); + bit += sizeof(uint16_t); + debug("Device: %s\n", bit); + bit += len; + + /* Date */ + if (*bit != 'c') + return -1; + bit++; + len = be16_to_cpu(*(uint16_t *)bit); + bit += sizeof(uint16_t); + debug("Date: %s\n", bit); + bit += len; + + /* Time */ + if (*bit != 'd') + return -1; + bit++; + len = be16_to_cpu(*(uint16_t *)bit); + bit += sizeof(uint16_t); + debug("Time: %s\n", bit); + bit += len; + + /* Bitstream length */ + if (*bit != 'e') + return -1; + bit++; + bitlen = be32_to_cpu(*(uint32_t *)bit); + bit += sizeof(uint32_t); + bitbin = bit; + + debug("Bitstream Length: 0x%x\n", bitlen); + for (i = 0; i < bitlen; i += sizeof(uint32_t)) { + uint32_t *bitbin32 = (uint32_t *)&bitbin[i]; + *bitbin32 = __swab32(*bitbin32); + } + + if (!bf->dest_dev) + bf->dest_dev = PART_ATTR_DEST_DEVICE_PL; + + bf->load = 0xffffffff; + bf->entry = 0; + + bf->flags |= 1ULL << BIF_FLAG_BIT_FILE; + return bif_add_part(bf, bit, bitlen); +} + +/* Add .bin bitstream */ +static int bif_add_bin(struct bif_entry *bf) +{ + size_t size; + char *bin = read_full_file(bf->filename, &size); + + if (!bf->dest_dev) + bf->dest_dev = PART_ATTR_DEST_DEVICE_PS; + + bf->flags |= 1ULL << BIF_FLAG_BIN_FILE; + return bif_add_part(bf, bin, size); +} + +/* Add elf file */ +static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr) +{ + Elf64_Ehdr *ehdr; + Elf64_Shdr *shdr; + size_t min_addr = -1, max_addr = 0; + char *flat; + int i; + + ehdr = (void *)elf; + shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff)); + + /* Look for smallest / biggest address */ + for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) { + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC) || + (shdr->sh_type == SHT_NOBITS)) + continue; + + if (le64_to_cpu(shdr->sh_addr) < min_addr) + min_addr = le64_to_cpu(shdr->sh_addr); + if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) > + max_addr) + max_addr = le64_to_cpu(shdr->sh_addr) + + le64_to_cpu(shdr->sh_size); + } + + *load_addr = min_addr; + *flat_size = max_addr - min_addr; + flat = calloc(1, *flat_size); + if (!flat) + return NULL; + + shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff)); + for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) { + char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr; + char *src = elf + le64_to_cpu(shdr->sh_offset); + + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC)) + continue; + + if (shdr->sh_type != SHT_NOBITS) + memcpy(dst, src, le64_to_cpu(shdr->sh_size)); + } + + return flat; +} + +static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr) +{ + Elf32_Ehdr *ehdr; + Elf32_Shdr *shdr; + size_t min_addr = -1, max_addr = 0; + char *flat; + int i; + + ehdr = (void *)elf; + shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff)); + + /* Look for smallest / biggest address */ + for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) { + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC) || + (shdr->sh_type == SHT_NOBITS)) + continue; + + if (le32_to_cpu(shdr->sh_addr) < min_addr) + min_addr = le32_to_cpu(shdr->sh_addr); + if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) > + max_addr) + max_addr = le32_to_cpu(shdr->sh_addr) + + le32_to_cpu(shdr->sh_size); + } + + *load_addr = min_addr; + *flat_size = max_addr - min_addr; + flat = calloc(1, *flat_size); + if (!flat) + return NULL; + + shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff)); + for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) { + char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr; + char *src = elf + le32_to_cpu(shdr->sh_offset); + + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC)) + continue; + + if (shdr->sh_type != SHT_NOBITS) + memcpy(dst, src, le32_to_cpu(shdr->sh_size)); + } + + return flat; +} + +static int bif_add_elf(struct bif_entry *bf) +{ + size_t size; + size_t elf_size; + char *elf; + char *flat; + size_t load_addr; + Elf32_Ehdr *ehdr32; + Elf64_Ehdr *ehdr64; + + elf = read_full_file(bf->filename, &elf_size); + if (!elf) + return -1; + + ehdr32 = (void *)elf; + ehdr64 = (void *)elf; + + switch (ehdr32->e_ident[EI_CLASS]) { + case ELFCLASS32: + flat = elf2flat32(elf, &size, &load_addr); + bf->entry = le32_to_cpu(ehdr32->e_entry); + bf->flags |= 1ULL << BIF_FLAG_AARCH32; + break; + case ELFCLASS64: + flat = elf2flat64(elf, &size, &load_addr); + bf->entry = le64_to_cpu(ehdr64->e_entry); + break; + default: + printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]); + return -1; + } + + if (!flat) + return -1; + + bf->load = load_addr; + if (!bf->dest_dev) + bf->dest_dev = PART_ATTR_DEST_DEVICE_PS; + + bf->flags |= 1ULL << BIF_FLAG_ELF_FILE; + return bif_add_part(bf, flat, size); +} + +static const struct bif_file_type bif_file_types[] = { + { + .name = "bitstream (.bit)", + .header = 0x00090ff0, + .add = bif_add_bit, + }, + + { + .name = "ELF", + .header = 0x7f454c46, + .add = bif_add_elf, + }, + + /* Anything else is a .bin file */ + { + .name = ".bin", + .add = bif_add_bin, + }, +}; + +static int bif_fsbl_config(struct bif_entry *fsbl_config, + struct bif_entry *entries, int nr_entries) +{ + int i; + int config_set = 0; + struct { + const char *name; + uint64_t flags; + uint64_t dest_cpu; + } configs[] = { + { .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, + { .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, + { .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, + .flags = 1ULL << BIF_FLAG_AARCH32 }, + { .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, + .flags = 1ULL << BIF_FLAG_AARCH32 }, + { .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 }, + { .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L }, + }; + + /* Set target CPU of bootloader entry */ + for (i = 0; i < nr_entries; i++) { + struct bif_entry *b = &entries[i]; + const char *config_attr = fsbl_config->filename; + int j; + + if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER))) + continue; + + for (j = 0; j < ARRAY_SIZE(configs); j++) { + if (!strncmp(config_attr, configs[j].name, + strlen(configs[j].name))) { + b->dest_cpu = configs[j].dest_cpu; + b->flags |= configs[j].flags; + config_set = 1; + } + } + + if (!config_set) { + printf("ERROR: Unsupported fsbl_config: %s\n", + config_attr); + return -1; + } + } + + if (!config_set) { + printf("ERROR: fsbl_config w/o bootloader\n"); + return -1; + } + + return 0; +} + +static const struct bif_flags *find_flag(char *str) +{ + const struct bif_flags *bf; + int i; + + for (i = 0; i < ARRAY_SIZE(bif_flags); i++) { + bf = &bif_flags[i]; + if (!strncmp(bf->name, str, strlen(bf->name))) + return bf; + } + + printf("ERROR: Flag '%s' not found\n", str); + + return NULL; +} + +static int bif_open_file(struct bif_entry *entry) +{ + int fd = open(entry->filename, O_RDONLY); + + if (fd < 0) + printf("Error opening file %s\n", entry->filename); + + return fd; +} + +static const struct bif_file_type *get_file_type(struct bif_entry *entry) +{ + int fd = bif_open_file(entry); + uint32_t header; + int i; + + if (fd < 0) + return NULL; + + if (read(fd, &header, sizeof(header)) != sizeof(header)) { + printf("Error reading file %s", entry->filename); + return NULL; + } + + close(fd); + + for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) { + const struct bif_file_type *type = &bif_file_types[i]; + + if (!type->header) + return type; + if (type->header == be32_to_cpu(header)) + return type; + } + + return NULL; +} + +#define NEXT_CHAR(str, chr) ({ \ + char *_n = strchr(str, chr); \ + if (!_n) \ + goto err; \ + _n; \ +}) + +static char *skip_whitespace(char *str) +{ + while (*str == ' ' || *str == '\t') + str++; + + return str; +} + +int zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams) +{ + char *bif, *bifp, *bifpn; + char *line; + struct bif_entry entries[32] = { { 0 } }; + int nr_entries = 0; + struct bif_entry *entry = entries; + size_t len; + int i; + uint32_t csum; + int bldr = -1; + + bif_init(); + + /* Read .bif input file */ + bif = read_full_file(mparams->datafile, NULL); + if (!bif) + goto err; + + /* Interpret .bif file */ + bifp = bif; + + /* A bif description starts with a { section */ + bifp = NEXT_CHAR(bifp, '{') + 1; + + /* Read every line */ + while (1) { + bifpn = NEXT_CHAR(bifp, '\n'); + + if (bifpn[-1] == '\r') + bifpn[-1] = '\0'; + + *bifpn = '\0'; + bifpn++; + line = bifp; + + line = skip_whitespace(line); + + /* Attributes? */ + if (*line == '[') { + line++; + while (1) { + const struct bif_flags *bf; + + line = skip_whitespace(line); + bf = find_flag(line); + if (!bf) + goto err; + + line += strlen(bf->name); + if (bf->parse) + line = bf->parse(line, entry); + else + entry->flags |= 1ULL << bf->flag; + + if (!line) + goto err; + + /* Go to next attribute or quit */ + if (*line == ']') { + line++; + break; + } + if (*line == ',') + line++; + } + } + + /* End of image description */ + if (*line == '}') + break; + + if (*line) { + line = skip_whitespace(line); + entry->filename = line; + nr_entries++; + entry++; + } + + /* Use next line */ + bifp = bifpn; + } + + for (i = 0; i < nr_entries; i++) { + debug("Entry flags=%#lx name=%s\n", entries[i].flags, + entries[i].filename); + } + + /* + * Some entries are actually configuration option for other ones, + * let's apply them in an intermediate step. + */ + for (i = 0; i < nr_entries; i++) { + struct bif_entry *entry = &entries[i]; + + if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) + if (bif_fsbl_config(entry, entries, nr_entries)) + goto err; + } + + /* Make sure PMUFW comes before bootloader */ + for (i = 0; i < nr_entries; i++) { + struct bif_entry *entry = &entries[i]; + + if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER)) + bldr = i; + if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) { + if (bldr >= 0) { + struct bif_entry tmp = *entry; + + *entry = entries[bldr]; + entries[bldr] = tmp; + } + } + } + + for (i = 0; i < nr_entries; i++) { + struct bif_entry *entry = &entries[i]; + const struct bif_file_type *type; + int r; + + if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) + continue; + + type = get_file_type(entry); + if (!type) + goto err; + + debug("type=%s file=%s\n", type->name, entry->filename); + r = type->add(entry); + if (r) + goto err; + } + + /* Calculate checksums */ + csum = zynqmp_csum(&bif_output.header->width_detection, + &bif_output.header->checksum); + bif_output.header->checksum = cpu_to_le32(csum); + + if (bif_output.imgheader) { + csum = zynqmp_csum(bif_output.imgheader, + &bif_output.imgheader->checksum); + bif_output.imgheader->checksum = cpu_to_le32(csum); + } + + /* Write headers and components */ + if (lseek(outfd, 0, SEEK_SET) != 0) + goto err; + + len = bif_output.data_len; + bifp = bif_output.data; + while (len) { + int r; + + r = write(outfd, bifp, len); + if (r < 0) + goto err; + len -= r; + bifp += r; + } + + return 0; + +err: + fprintf(stderr, "Error: Failed to create image.\n"); + return -1; +} + +/* Needs to be stubbed out so we can print after creation */ +static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ +} + +static struct zynqmp_header zynqmpimage_header; + +U_BOOT_IMAGE_TYPE( + zynqmpbif, + "Xilinx ZynqMP Boot Image support (bif)", + sizeof(struct zynqmp_header), + (void *)&zynqmpimage_header, + zynqmpbif_check_params, + NULL, + zynqmpimage_print_header, + zynqmpbif_set_header, + NULL, + zynqmpbif_check_image_types, + NULL, + NULL +); diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 870a6b5..19b2f02 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -86,7 +86,7 @@ static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr) return cpu_to_le32(checksum); } -static void zynqmpimage_default_header(struct zynqmp_header *ptr) +void zynqmpimage_default_header(struct zynqmp_header *ptr) { int i; @@ -209,7 +209,7 @@ static void print_partition(const void *ptr, const struct partition_header *ph) printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum)); } -static void zynqmpimage_print_header(const void *ptr) +void zynqmpimage_print_header(const void *ptr) { struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; int i; diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h index f3b5c19..7a57681 100644 --- a/tools/zynqmpimage.h +++ b/tools/zynqmpimage.h @@ -19,7 +19,11 @@ #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) +#define HEADER_CPU_SELECT_MASK (0x3 << 10) +#define HEADER_CPU_SELECT_R5_SINGLE (0x0 << 10) +#define HEADER_CPU_SELECT_A53_32BIT (0x1 << 10) #define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) +#define HEADER_CPU_SELECT_R5_DUAL (0x3 << 10) enum { ENCRYPTION_EFUSE = 0xa5c3c5a3, @@ -129,4 +133,7 @@ struct zynqmp_header { uint32_t __reserved4[66]; /* 0x9c0 */ }; +void zynqmpimage_default_header(struct zynqmp_header *ptr); +void zynqmpimage_print_header(const void *ptr); + #endif /* _ZYNQMPIMAGE_H_ */ From 1d6c54ecb39b8591a98f02f9b47af225ff07cd0b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 12 Apr 2018 17:39:46 +0200 Subject: [PATCH 23/31] arm: zynqmp: Add ZynqMP minimal R5 support Xilinx ZynqMP also contains dual Cortex R5 which can run U-Boot. This patch is adding minimal support to get U-Boot boot. U-Boot on R5 runs out of DDR with default configuration that's why DDR needs to be partitioned if there is something else running on arm64. Console is done via Cadence uart driver and the first Cadence Triple Timer Counter is used for time. This configuration with uart1 was tested on zcu100-revC. U-Boot 2018.05-rc2-00021-gd058a08d907d (Apr 18 2018 - 14:11:27 +0200) Model: Xilinx ZynqMP R5 DRAM: 512 MiB WARNING: Caches not enabled MMC: In: serial@ff010000 Out: serial@ff010000 Err: serial@ff010000 Net: Net Initialization Skipped No ethernet found. ZynqMP r5> There are two ways how to run this on ZynqMP. 1. Run from ZynqMP arm64 tftpb 20000000 u-boot-r5.elf setenv autostart no && bootelf -p 20000000 cpu 4 disable && cpu 4 release 10000000 lockstep or cpu 4 disable && cpu 4 release 10000000 split 2. Load via jtag when directly to R5 Signed-off-by: Michal Simek --- MAINTAINERS | 6 ++++ arch/arm/Kconfig | 10 ++++++ arch/arm/Makefile | 1 + arch/arm/dts/Makefile | 2 ++ arch/arm/dts/zynqmp-r5.dts | 73 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-zynqmp-r5/Kconfig | 27 ++++++++++++++ arch/arm/mach-zynqmp-r5/Makefile | 3 ++ arch/arm/mach-zynqmp-r5/cpu.c | 37 +++++++++++++++++++ board/xilinx/zynqmp_r5/MAINTAINERS | 7 ++++ board/xilinx/zynqmp_r5/Makefile | 6 ++++ board/xilinx/zynqmp_r5/board.c | 25 +++++++++++++ configs/xilinx_zynqmp_r5_defconfig | 16 +++++++++ drivers/serial/Kconfig | 2 +- include/configs/xilinx_zynqmp_r5.h | 51 ++++++++++++++++++++++++++ 14 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-r5.dts create mode 100644 arch/arm/mach-zynqmp-r5/Kconfig create mode 100644 arch/arm/mach-zynqmp-r5/Makefile create mode 100644 arch/arm/mach-zynqmp-r5/cpu.c create mode 100644 board/xilinx/zynqmp_r5/MAINTAINERS create mode 100644 board/xilinx/zynqmp_r5/Makefile create mode 100644 board/xilinx/zynqmp_r5/board.c create mode 100644 configs/xilinx_zynqmp_r5_defconfig create mode 100644 include/configs/xilinx_zynqmp_r5.h diff --git a/MAINTAINERS b/MAINTAINERS index c2ae68c..5670917 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -295,6 +295,12 @@ F: include/zynqmppl.h F: tools/zynqmp* N: zynqmp +ARM ZYNQMP R5 +M: Michal Simek +S: Maintained +T: git git://git.denx.de/u-boot-microblaze.git +F: arch/arm/mach-zynqmp-r5/ + BUILDMAN M: Simon Glass S: Maintained diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a7618f9..c9d6e0a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -823,6 +823,14 @@ config ARCH_ZYNQ imply CMD_SPL imply ARCH_EARLY_INIT_R +config ARCH_ZYNQMP_R5 + bool "Xilinx ZynqMP R5 based platform" + select CPU_V7R + select OF_CONTROL + select DM + select DM_SERIAL + select CLK + config ARCH_ZYNQMP bool "Xilinx ZynqMP based platform" select ARM64 @@ -1345,6 +1353,8 @@ source "arch/arm/cpu/armv7/vf610/Kconfig" source "arch/arm/mach-zynq/Kconfig" +source "arch/arm/mach-zynqmp-r5/Kconfig" + source "arch/arm/cpu/armv7/Kconfig" source "arch/arm/cpu/armv8/zynqmp/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 3b1dd85..4d6d276 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -76,6 +76,7 @@ machine-$(CONFIG_ARCH_STM32MP) += stm32mp machine-$(CONFIG_TEGRA) += tegra machine-$(CONFIG_ARCH_UNIPHIER) += uniphier machine-$(CONFIG_ARCH_ZYNQ) += zynq +machine-$(CONFIG_ARCH_ZYNQMP_R5) += zynqmp-r5 machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index f7f2436..f94940a 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -163,6 +163,8 @@ dtb-$(CONFIG_ARCH_ZYNQMP) += \ zynqmp-zc1751-xm017-dc3.dtb \ zynqmp-zc1751-xm018-dc4.dtb \ zynqmp-zc1751-xm019-dc5.dtb +dtb-$(CONFIG_ARCH_ZYNQMP_R5) += \ + zynqmp-r5.dtb dtb-$(CONFIG_AM33XX) += am335x-boneblack.dtb am335x-bone.dtb \ am335x-draco.dtb \ am335x-evm.dtb \ diff --git a/arch/arm/dts/zynqmp-r5.dts b/arch/arm/dts/zynqmp-r5.dts new file mode 100644 index 0000000..a72172e --- /dev/null +++ b/arch/arm/dts/zynqmp-r5.dts @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dts file for Xilinx ZynqMP R5 + * + * (C) Copyright 2018, Xilinx, Inc. + * + * Michal Simek + */ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynqmp-r5"; + model = "Xilinx ZynqMP R5"; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + + cpu@0 { + compatible = "arm,cortex-r5"; + device_type = "cpu"; + reg = <0>; + }; + }; + + aliases { + serial0 = &uart1; + }; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = ""; + stdout-path = "serial0:115200n8"; + }; + + clk100: clk100 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + u-boot,dm-pre-reloc; + }; + + amba { + u-boot,dm-pre-reloc; + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ttc0: timer@ff110000 { + compatible = "cdns,ttc"; + status = "okay"; + reg = <0xff110000 0x1000>; + timer-width = <32>; + clocks = <&clk100>; + }; + + uart1: serial@ff010000 { + u-boot,dm-pre-reloc; + compatible = "cdns,uart-r1p12", "xlnx,xuartps"; + reg = <0xff010000 0x1000>; + clock-names = "uart_clk", "pclk"; + clocks = <&clk100 &clk100>; + }; + }; +}; diff --git a/arch/arm/mach-zynqmp-r5/Kconfig b/arch/arm/mach-zynqmp-r5/Kconfig new file mode 100644 index 0000000..5e01754 --- /dev/null +++ b/arch/arm/mach-zynqmp-r5/Kconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0 + +if ARCH_ZYNQMP_R5 + +config SYS_BOARD + string "Board name" + default "zynqmp_r5" + +config SYS_VENDOR + string "Vendor name" + default "xilinx" + +config SYS_SOC + default "zynqmp-r5" + +config SYS_CONFIG_NAME + string "Board configuration name" + default "xilinx_zynqmp_r5" + help + This option contains information about board configuration name. + Based on this option include/configs/.h header + will be used for board configuration. + +config SYS_MALLOC_F_LEN + default 0x600 + +endif diff --git a/arch/arm/mach-zynqmp-r5/Makefile b/arch/arm/mach-zynqmp-r5/Makefile new file mode 100644 index 0000000..0d39e97 --- /dev/null +++ b/arch/arm/mach-zynqmp-r5/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += cpu.o diff --git a/arch/arm/mach-zynqmp-r5/cpu.c b/arch/arm/mach-zynqmp-r5/cpu.c new file mode 100644 index 0000000..98f63e3 --- /dev/null +++ b/arch/arm/mach-zynqmp-r5/cpu.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Xilinx, Inc. (Michal Simek) + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct mpu_region_config region_config[] = { + { 0x00000000, REGION_0, XN_DIS, PRIV_RW_USR_RW, + O_I_WB_RD_WR_ALLOC, REGION_1GB }, + { 0x20000000, REGION_1, XN_EN, PRIV_RO_USR_RO, + O_I_WB_RD_WR_ALLOC, REGION_512MB }, + { 0x40000000, REGION_2, XN_EN, PRIV_RO_USR_RO, + O_I_WB_RD_WR_ALLOC, REGION_1GB }, +}; + +int arch_cpu_init(void) +{ + gd->cpu_clk = CONFIG_CPU_FREQ_HZ; + + setup_mpu_regions(region_config, sizeof(region_config) / + sizeof(struct mpu_region_config)); + + return 0; +} + +/* + * Perform the low-level reset. + */ +void reset_cpu(ulong addr) +{ + while (1) + ; +} diff --git a/board/xilinx/zynqmp_r5/MAINTAINERS b/board/xilinx/zynqmp_r5/MAINTAINERS new file mode 100644 index 0000000..ac26764 --- /dev/null +++ b/board/xilinx/zynqmp_r5/MAINTAINERS @@ -0,0 +1,7 @@ +XILINX_ZYNQMP_R5 BOARDS +M: Michal Simek +S: Maintained +F: arch/arm/dts/zynqmp-r5* +F: board/xilinx/zynqmp_r5/ +F: include/configs/xilinx_zynqmp_r5_* +F: configs/xilinx_zynqmp_r5_* diff --git a/board/xilinx/zynqmp_r5/Makefile b/board/xilinx/zynqmp_r5/Makefile new file mode 100644 index 0000000..c5a3e3d --- /dev/null +++ b/board/xilinx/zynqmp_r5/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# (C) Copyright 2018 Xilinx, Inc. (Michal Simek) +# + +obj-y := board.o diff --git a/board/xilinx/zynqmp_r5/board.c b/board/xilinx/zynqmp_r5/board.c new file mode 100644 index 0000000..70fb202 --- /dev/null +++ b/board/xilinx/zynqmp_r5/board.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2018 Xilinx, Inc. (Michal Simek) + */ + +#include +#include + +int board_init(void) +{ + return 0; +} + +int dram_init_banksize(void) +{ + return fdtdec_setup_memory_banksize(); +} + +int dram_init(void) +{ + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; + + return 0; +} diff --git a/configs/xilinx_zynqmp_r5_defconfig b/configs/xilinx_zynqmp_r5_defconfig new file mode 100644 index 0000000..4671524 --- /dev/null +++ b/configs/xilinx_zynqmp_r5_defconfig @@ -0,0 +1,16 @@ +CONFIG_ARM=y +CONFIG_ARCH_ZYNQMP_R5=y +CONFIG_SYS_TEXT_BASE=0x10000000 +CONFIG_DEFAULT_DEVICE_TREE="zynqmp-r5" +CONFIG_DEBUG_UART=y +# CONFIG_DISPLAY_CPUINFO is not set +CONFIG_SYS_PROMPT="ZynqMP r5> " +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_SETEXPR is not set +CONFIG_OF_EMBED=y +CONFIG_DEBUG_UART_ZYNQ=y +CONFIG_DEBUG_UART_BASE=0xff010000 +CONFIG_DEBUG_UART_CLOCK=100000000 +CONFIG_ZYNQ_SERIAL=y +CONFIG_TIMER=y +CONFIG_CADENCE_TTC_TIMER=y diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4be8868..5937910 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -624,7 +624,7 @@ config STM32_SERIAL config ZYNQ_SERIAL bool "Cadence (Xilinx Zynq) UART support" - depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_ZYNQMP_R5) help This driver supports the Cadence UART. It is found e.g. in Xilinx Zynq/ZynqMP. diff --git a/include/configs/xilinx_zynqmp_r5.h b/include/configs/xilinx_zynqmp_r5.h new file mode 100644 index 0000000..05105e5 --- /dev/null +++ b/include/configs/xilinx_zynqmp_r5.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * (C) Copyright 2018 Xilinx, Inc. (Michal Simek) + */ + +#ifndef __CONFIG_ZYNQMP_R5_H +#define __CONFIG_ZYNQMP_R5_H + +#define CONFIG_EXTRA_ENV_SETTINGS + +/* CPU clock */ +#define CONFIG_CPU_FREQ_HZ 500000000 + +/* Serial drivers */ +/* The following table includes the supported baudrates */ +#define CONFIG_SYS_BAUDRATE_TABLE \ + {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400} + +# define CONFIG_ENV_SIZE (128 << 10) + +/* Allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE + +/* Boot configuration */ +#define CONFIG_SYS_LOAD_ADDR 0 /* default? */ + +#define CONFIG_SYS_MAXARGS 32 /* max number of command args */ + +#define CONFIG_NR_DRAM_BANKS 1 + +#define CONFIG_SYS_MALLOC_LEN 0x1400000 + +#define CONFIG_SYS_INIT_RAM_ADDR 0xFFFF0000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x1000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ + CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) + +/* Extend size of kernel image for uncompression */ +#define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024) + +#define CONFIG_SYS_UBOOT_START CONFIG_SYS_TEXT_BASE + +#define CONFIG_SKIP_LOWLEVEL_INIT + +/* 0x0 - 0x40 is used for placing exception vectors */ +#define CONFIG_SYS_MEMTEST_START 0x40 +#define CONFIG_SYS_MEMTEST_END 0x100 +#define CONFIG_SYS_MEMTEST_SCRATCH 0 + +#endif /* __CONFIG_ZYNQ_ZYNQMP_R5_H */ From 36332b6e4b122e0bdb43eb992533bdd911b6c030 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Date: Thu, 3 May 2018 12:20:54 +0530 Subject: [PATCH 24/31] mmc: Changed the datatype of the variable to handle 64-bit arch This patch changed the datatype of variable "start" from uint to ulong to work properly on 64-bit machines as well. Also the return type of get_timer() function is ulong. Signed-off-by: Vipul Kumar Signed-off-by: Michal Simek --- drivers/mmc/mmc.c | 4 ++-- drivers/mmc/sdhci.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index a08c694..3cfe6bf 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -679,7 +679,7 @@ static int mmc_complete_op_cond(struct mmc *mmc) { struct mmc_cmd cmd; int timeout = 1000; - uint start; + ulong start; int err; mmc->op_cond_pending = 0; @@ -2611,7 +2611,7 @@ static int mmc_complete_init(struct mmc *mmc) int mmc_init(struct mmc *mmc) { int err = 0; - __maybe_unused unsigned start; + __maybe_unused ulong start; #if CONFIG_IS_ENABLED(DM_MMC) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 758850f..c2ae3e3 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -151,7 +151,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, u32 mask, flags, mode; unsigned int time = 0, start_addr = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; - unsigned start = get_timer(0); + ulong start = get_timer(0); /* Timeout unit - ms */ static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; From 2a2d7efe77f771e2776de6b360be264de12818d8 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:04 +0530 Subject: [PATCH 25/31] mmc: sdhci: Add support for disabling clock This patch adds support to disable clock if clk_disable was set and then enable or set clock if the clock was changed or clock was disabled when clock needs to be enabled. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c2ae3e3..d7acab1 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -439,6 +439,9 @@ static int sdhci_set_ios(struct mmc *mmc) if (mmc->clock != host->clock) sdhci_set_clock(mmc, mmc->clock); + if (mmc->clk_disable) + sdhci_set_clock(mmc, 0); + /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { From b88a7a4c5618565dfa2a913c0980b51dc96932cb Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:05 +0530 Subject: [PATCH 26/31] mmc: sdhci: Handle execute tuning command in sdhci_send_command This patch upadted sdhci_send_command to handle execute tuning command. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d7acab1..d92f6db 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -160,7 +160,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) mask &= ~SDHCI_DATA_INHIBIT; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { @@ -182,6 +183,9 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_INT_RESPONSE; + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) + mask = SDHCI_INT_DATA_AVAIL; + if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->resp_type & MMC_RSP_136) @@ -197,7 +201,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, flags |= SDHCI_CMD_CRC; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; - if (data) + if (data || cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK) flags |= SDHCI_CMD_DATA; /* Set Transfer mode regarding to data flag */ From 2fc3ed5d06121ab47e45127fc534881ed3be235d Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:06 +0530 Subject: [PATCH 27/31] sdhci: Add new sdhci ops for platform specific tuning and delays This patch adds new hooks for any platform specific tuning and tap delays programing. These are needed for supporting SD3.0. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- include/sdhci.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sdhci.h b/include/sdhci.h index 1e0c92c..8ca632f 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -242,6 +242,8 @@ struct sdhci_ops { void (*set_control_reg)(struct sdhci_host *host); void (*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); }; struct sdhci_host { From ca992e82e4e3428db0809303ebb9b696a77fa189 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:07 +0530 Subject: [PATCH 28/31] mmc: sdhci: Invoke platform specific tuning and delay routines This patch adds support to invoke any platform specific tuning and delay routines if available. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d92f6db..efc5a62 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -305,6 +305,24 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, return -ECOMM; } +#if defined(CONFIG_DM_MMC) && defined(MMC_SUPPORTS_TUNING) +static int sdhci_execute_tuning(struct udevice *dev, uint opcode) +{ + int err; + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + + debug("%s\n", __func__); + + if (host->ops->platform_execute_tuning) { + err = host->ops->platform_execute_tuning(mmc, opcode); + if (err) + return err; + return 0; + } + return 0; +} +#endif static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; @@ -329,6 +347,9 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (clock == 0) return 0; + if (host->ops->set_delay) + host->ops->set_delay(host); + if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { /* * Check if the Host Controller supports Programmable Clock @@ -521,6 +542,9 @@ int sdhci_probe(struct udevice *dev) const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, +#ifdef MMC_SUPPORTS_TUNING + .execute_tuning = sdhci_execute_tuning, +#endif }; #else static const struct mmc_ops sdhci_ops = { From b8e25ef16a58bee2770e48a7158e267f386c84de Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:08 +0530 Subject: [PATCH 29/31] mmc: sdhci: Read capabilities register1 and update host caps This patch reads the capabilities register1 and update the host caps accordingly for mmc layer usage. This patch mainly reads for UHS capabilities inorder to support SD3.0. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 28 +++++++++++++++++++++++++++- include/sdhci.h | 6 ++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index efc5a62..8971a11 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -557,7 +557,7 @@ static const struct mmc_ops sdhci_ops = { int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 f_max, u32 f_min) { - u32 caps, caps_1; + u32 caps, caps_1 = 0; caps = sdhci_readl(host, SDHCI_CAPABILITIES); @@ -638,6 +638,32 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } + if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) + caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + + if (!(cfg->voltages & MMC_VDD_165_195) || + (host->quirks & SDHCI_QUIRK_NO_1_8_V)) + caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); + + if (caps_1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50)) + cfg->host_caps |= MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25); + + if (caps_1 & SDHCI_SUPPORT_SDR104) { + cfg->host_caps |= MMC_CAP(UHS_SDR104) | MMC_CAP(UHS_SDR50); + /* + * SD3.0: SDR104 is supported so (for eMMC) the caps2 + * field can be promoted to support HS200. + */ + cfg->host_caps |= MMC_CAP(MMC_HS_200); + } else if (caps_1 & SDHCI_SUPPORT_SDR50) { + cfg->host_caps |= MMC_CAP(UHS_SDR50); + } + + if (caps_1 & SDHCI_SUPPORT_DDR50) + cfg->host_caps |= MMC_CAP(UHS_DDR50); + if (host->host_caps) cfg->host_caps |= host->host_caps; diff --git a/include/sdhci.h b/include/sdhci.h index 8ca632f..bef37df 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -166,6 +166,11 @@ #define SDHCI_CAN_64BIT BIT(28) #define SDHCI_CAPABILITIES_1 0x44 +#define SDHCI_SUPPORT_SDR50 0x00000001 +#define SDHCI_SUPPORT_SDR104 0x00000002 +#define SDHCI_SUPPORT_DDR50 0x00000004 +#define SDHCI_USE_SDR50_TUNING 0x00002000 + #define SDHCI_CLOCK_MUL_MASK 0x00FF0000 #define SDHCI_CLOCK_MUL_SHIFT 16 @@ -220,6 +225,7 @@ #define SDHCI_QUIRK_BROKEN_HISPD_MODE BIT(5) #define SDHCI_QUIRK_WAIT_SEND_CMD (1 << 6) #define SDHCI_QUIRK_USE_WIDE8 (1 << 8) +#define SDHCI_QUIRK_NO_1_8_V (1 << 9) /* to make gcc happy */ struct sdhci_host; From d1f4e39d58db32a4fd1a1b4085e0ede498bd773f Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:09 +0530 Subject: [PATCH 30/31] mmc: zynq_sdhci: Add support for SD3.0 This patch adds support of SD3.0 for ZynqMP. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- board/xilinx/zynqmp/Makefile | 2 + board/xilinx/zynqmp/tap_delays.c | 229 ++++++++++++++++++++++++++++++++++++++ drivers/mmc/zynq_sdhci.c | 231 ++++++++++++++++++++++++++++++++++++++- include/zynqmp_tap_delay.h | 19 ++++ 4 files changed, 476 insertions(+), 5 deletions(-) create mode 100644 board/xilinx/zynqmp/tap_delays.c create mode 100644 include/zynqmp_tap_delay.h diff --git a/board/xilinx/zynqmp/Makefile b/board/xilinx/zynqmp/Makefile index 65bcb59..05ccd25 100644 --- a/board/xilinx/zynqmp/Makefile +++ b/board/xilinx/zynqmp/Makefile @@ -24,6 +24,8 @@ ifneq ($(call ifdef_any_of, CONFIG_ZYNQMP_PSU_INIT_ENABLED CONFIG_SPL_BUILD),) obj-y += $(init-objs) 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 new file mode 100644 index 0000000..c3ae357 --- /dev/null +++ b/board/xilinx/zynqmp/tap_delays.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx ZynqMP SoC Tap Delay Programming + * + * Copyright (C) 2018 Xilinx, Inc. + */ + +#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 SD0_ITAPDLYSEL_HSD 0x00000015 +#define SD0_ITAPDLYSEL_SD_DDR50 0x0000003D +#define SD0_ITAPDLYSEL_MMC_DDR50 0x00000012 + +#define SD1_ITAPDLYSEL_MASK 0x00FF0000 +#define SD1_ITAPDLYSEL_HSD 0x00150000 +#define SD1_ITAPDLYSEL_SD_DDR50 0x003D0000 +#define SD1_ITAPDLYSEL_MMC_DDR50 0x00120000 + +#define SD0_OTAPDLYSEL_MASK 0x0000003F +#define SD0_OTAPDLYSEL_MMC_HSD 0x00000006 +#define SD0_OTAPDLYSEL_SD_HSD 0x00000005 +#define SD0_OTAPDLYSEL_SDR50 0x00000003 +#define SD0_OTAPDLYSEL_SDR104_B0 0x00000003 +#define SD0_OTAPDLYSEL_SDR104_B2 0x00000002 +#define SD0_OTAPDLYSEL_SD_DDR50 0x00000004 +#define SD0_OTAPDLYSEL_MMC_DDR50 0x00000006 + +#define SD1_OTAPDLYSEL_MASK 0x003F0000 +#define SD1_OTAPDLYSEL_MMC_HSD 0x00060000 +#define SD1_OTAPDLYSEL_SD_HSD 0x00050000 +#define SD1_OTAPDLYSEL_SDR50 0x00030000 +#define SD1_OTAPDLYSEL_SDR104_B0 0x00030000 +#define SD1_OTAPDLYSEL_SDR104_B2 0x00020000 +#define SD1_OTAPDLYSEL_SD_DDR50 0x00040000 +#define SD1_OTAPDLYSEL_MMC_DDR50 0x00060000 + +#define MMC_BANK2 0x2 + +#define MMC_TIMING_UHS_SDR25 1 +#define MMC_TIMING_UHS_SDR50 2 +#define MMC_TIMING_UHS_SDR104 3 +#define MMC_TIMING_UHS_DDR50 4 +#define MMC_TIMING_MMC_HS200 5 +#define MMC_TIMING_SD_HS 6 +#define MMC_TIMING_MMC_DDR52 7 +#define MMC_TIMING_MMC_HS 8 + +void zynqmp_dll_reset(u8 deviceid) +{ + /* 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); + + 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); +} + +static void arasan_zynqmp_tap_sdr104(u8 deviceid, u8 timing, u8 bank) +{ + if (deviceid == 0) { + /* Program OTAP */ + if (bank == MMC_BANK2) + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_SDR104_B2); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_SDR104_B0); + } else { + /* Program OTAP */ + if (bank == MMC_BANK2) + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_SDR104_B2); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_SDR104_B0); + } +} + +static void arasan_zynqmp_tap_hs(u8 deviceid, u8 timing, u8 bank) +{ + if (deviceid == 0) { + /* Program ITAP */ + 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, + SD0_ITAPDLYSEL_HSD); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, 0x0); + /* Program OTAP */ + if (timing == MMC_TIMING_MMC_HS) + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_MMC_HSD); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_SD_HSD); + } else { + /* Program ITAP */ + 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, + SD1_ITAPDLYSEL_HSD); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, 0x0); + /* Program OTAP */ + if (timing == MMC_TIMING_MMC_HS) + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_MMC_HSD); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_SD_HSD); + } +} + +static void arasan_zynqmp_tap_ddr50(u8 deviceid, u8 timing, u8 bank) +{ + if (deviceid == 0) { + /* Program ITAP */ + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, + SD0_ITAPCHGWIN); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK, + SD0_ITAPDLYENA); + if (timing == MMC_TIMING_UHS_DDR50) + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK, + SD0_ITAPDLYSEL_SD_DDR50); + else + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK, + SD0_ITAPDLYSEL_MMC_DDR50); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, 0x0); + /* Program OTAP */ + if (timing == MMC_TIMING_UHS_DDR50) + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_SD_DDR50); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_MMC_DDR50); + } else { + /* Program ITAP */ + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, + SD1_ITAPCHGWIN); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK, + SD1_ITAPDLYENA); + if (timing == MMC_TIMING_UHS_DDR50) + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, + SD1_ITAPDLYSEL_SD_DDR50); + else + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, + SD1_ITAPDLYSEL_MMC_DDR50); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, 0x0); + /* Program OTAP */ + if (timing == MMC_TIMING_UHS_DDR50) + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_SD_DDR50); + else + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_MMC_DDR50); + } +} + +static void arasan_zynqmp_tap_sdr50(u8 deviceid, u8 timing, u8 bank) +{ + if (deviceid == 0) { + /* Program OTAP */ + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + SD0_OTAPDLYSEL_SDR50); + } else { + /* Program OTAP */ + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + SD1_OTAPDLYSEL_SDR50); + } +} + +void arasan_zynqmp_set_tapdelay(u8 deviceid, u8 timing, u8 bank) +{ + 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); + + switch (timing) { + case MMC_TIMING_UHS_SDR25: + arasan_zynqmp_tap_hs(deviceid, timing, bank); + break; + case MMC_TIMING_UHS_SDR50: + arasan_zynqmp_tap_sdr50(deviceid, timing, bank); + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + arasan_zynqmp_tap_sdr104(deviceid, timing, bank); + break; + case MMC_TIMING_UHS_DDR50: + arasan_zynqmp_tap_ddr50(deviceid, timing, bank); + break; + } + + 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); +} diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index b53308a..f99731f 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -9,9 +9,11 @@ #include #include #include +#include "mmc_private.h" #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -21,15 +23,212 @@ struct arasan_sdhci_plat { unsigned int f_max; }; +struct arasan_sdhci_priv { + struct sdhci_host *host; + u8 deviceid; + u8 bank; + u8 no_1p8; + bool pwrseq; +}; + +#if defined(CONFIG_ARCH_ZYNQMP) +static const u8 mode2timing[] = { + [UHS_SDR12] = UHS_SDR12_BUS_SPEED, + [UHS_SDR25] = UHS_SDR25_BUS_SPEED, + [UHS_SDR50] = UHS_SDR50_BUS_SPEED, + [UHS_SDR104] = UHS_SDR104_BUS_SPEED, + [UHS_DDR50] = UHS_DDR50_BUS_SPEED, +}; + +#define SDHCI_HOST_CTRL2 0x3E +#define SDHCI_CTRL2_MODE_MASK 0x7 +#define SDHCI_18V_SIGNAL 0x8 +#define SDHCI_CTRL_EXEC_TUNING 0x0040 +#define SDHCI_CTRL_TUNED_CLK 0x80 +#define SDHCI_TUNING_LOOP_COUNT 40 + +static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) +{ + u16 clk; + unsigned long timeout; + + 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); + + /* 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; + } + timeout--; + udelay(1000); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +} + +static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) +{ + struct mmc_cmd cmd; + struct mmc_data data; + u32 ctrl; + struct sdhci_host *host; + struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev); + u8 tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT; + u8 deviceid; + + debug("%s\n", __func__); + + host = priv->host; + deviceid = priv->deviceid; + + ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl |= SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2); + + mdelay(1); + + arasan_zynqmp_dll_reset(host, deviceid); + + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); + + do { + cmd.cmdidx = opcode; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = 0; + + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + if (tuning_loop_counter-- == 0) + break; + + if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 && + mmc->bus_width == 8) + data.blocksize = 128; + + sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, + data.blocksize), + SDHCI_BLOCK_SIZE); + sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT); + sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); + + mmc_send_cmd(mmc, &cmd, NULL); + ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + + if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK) + udelay(1); + + } while (ctrl & SDHCI_CTRL_EXEC_TUNING); + + if (tuning_loop_counter < 0) { + ctrl &= ~SDHCI_CTRL_TUNED_CLK; + sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2); + } + + if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { + printf("%s:Tuning failed\n", __func__); + return -1; + } + + udelay(1); + arasan_zynqmp_dll_reset(host, deviceid); + + /* Enable only interrupts served by the SD controller */ + sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, + SDHCI_INT_ENABLE); + /* Mask all sdhci interrupt sources */ + sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); + + return 0; +} + +static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) +{ + struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); + struct mmc *mmc = (struct mmc *)host->mmc; + u8 uhsmode; + + if (!IS_SD(mmc)) + return; + + uhsmode = mode2timing[mmc->selected_mode]; + + if (uhsmode >= UHS_SDR25_BUS_SPEED) + arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode, + priv->bank); +} + +static void arasan_sdhci_set_control_reg(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + reg = sdhci_readw(host, SDHCI_HOST_CTRL2); + reg |= SDHCI_18V_SIGNAL; + sdhci_writew(host, reg, SDHCI_HOST_CTRL2); + } + + if (mmc->selected_mode > SD_HS && + mmc->selected_mode <= UHS_DDR50) { + reg = sdhci_readw(host, SDHCI_HOST_CTRL2); + reg &= ~SDHCI_CTRL2_MODE_MASK; + switch (mmc->selected_mode) { + case UHS_SDR12: + reg |= UHS_SDR12_BUS_SPEED; + break; + case UHS_SDR25: + reg |= UHS_SDR25_BUS_SPEED; + break; + case UHS_SDR50: + reg |= UHS_SDR50_BUS_SPEED; + break; + case UHS_SDR104: + reg |= UHS_SDR104_BUS_SPEED; + break; + case UHS_DDR50: + reg |= UHS_DDR50_BUS_SPEED; + break; + default: + break; + } + sdhci_writew(host, reg, SDHCI_HOST_CTRL2); + } +} +#endif + +#if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP) +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, +}; +#endif + static int arasan_sdhci_probe(struct udevice *dev) { struct arasan_sdhci_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); - struct sdhci_host *host = dev_get_priv(dev); + struct arasan_sdhci_priv *priv = dev_get_priv(dev); + struct sdhci_host *host; struct clk clk; unsigned long clock; int ret; + host = priv->host; + ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) { dev_err(dev, "failed to get clock\n"); @@ -41,6 +240,7 @@ static int arasan_sdhci_probe(struct udevice *dev) dev_err(dev, "failed to get rate\n"); return clock; } + debug("%s: CLK %ld\n", __func__, clock); ret = clk_enable(&clk); @@ -56,6 +256,9 @@ static int arasan_sdhci_probe(struct udevice *dev) host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE; #endif + if (priv->no_1p8) + host->quirks |= SDHCI_QUIRK_NO_1_8_V; + host->max_clk = clock; ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max, @@ -73,10 +276,28 @@ static int arasan_sdhci_probe(struct udevice *dev) static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) { struct arasan_sdhci_plat *plat = dev_get_platdata(dev); - struct sdhci_host *host = dev_get_priv(dev); + struct arasan_sdhci_priv *priv = dev_get_priv(dev); + + priv->host = calloc(1, sizeof(struct sdhci_host)); + if (!priv->host) + return -1; - host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + priv->host->name = dev->name; + priv->host->ioaddr = (void *)devfdt_get_addr(dev); + + priv->deviceid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "xlnx,device_id", -1); + priv->bank = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "xlnx,mio_bank", -1); + if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), + "no-1-8-v", NULL)) + priv->no_1p8 = 1; + else + priv->no_1p8 = 0; + +#if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP) + priv->host->ops = &arasan_ops; +#endif plat->f_max = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "max-frequency", CONFIG_ZYNQ_SDHCI_MAX_FREQ); @@ -104,6 +325,6 @@ U_BOOT_DRIVER(arasan_sdhci_drv) = { .ops = &sdhci_ops, .bind = arasan_sdhci_bind, .probe = arasan_sdhci_probe, - .priv_auto_alloc_size = sizeof(struct sdhci_host), + .priv_auto_alloc_size = sizeof(struct arasan_sdhci_priv), .platdata_auto_alloc_size = sizeof(struct arasan_sdhci_plat), }; diff --git a/include/zynqmp_tap_delay.h b/include/zynqmp_tap_delay.h new file mode 100644 index 0000000..b07e3e0 --- /dev/null +++ b/include/zynqmp_tap_delay.h @@ -0,0 +1,19 @@ +/* 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__ + +#ifdef CONFIG_ARCH_ZYNQMP +void zynqmp_dll_reset(u8 deviceid); +void arasan_zynqmp_set_tapdelay(u8 device_id, u8 uhsmode, u8 bank); +#else +inline void zynqmp_dll_reset(u8 deviceid) {} +inline void arasan_zynqmp_set_tapdelay(u8 device_id, u8 uhsmode, u8 bank) {} +#endif + +#endif From 4b87f2d500e94f877f38d9c11e4e47e1721f3fbe Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 19 Apr 2018 12:37:10 +0530 Subject: [PATCH 31/31] arm64: zynqmp: Enable UHS support for ZCU102 Rev1.0 board This patch enables UHS support for ZynqMP zcu102 rev 1.0 board. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_zcu102_rev1_0_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig index 8e3bef3..0ddec99 100644 --- a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig +++ b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig @@ -60,6 +60,8 @@ CONFIG_ZYNQ_I2C1=y CONFIG_MISC=y CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0x20 CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_SPI_FLASH=y