From 627085eacf4a64824fd0bfa2f6f9c1a72d48d21f Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Thu, 24 Sep 2020 11:54:36 +0300 Subject: [PATCH 01/71] microblaze: start.S: Factor out exception setup code to __setup_exceptions Currently, the exceptions setup code is duplicated in pre-relocation and post-relocation init. Factor out this code to __setup_exceptions asm routine to get rid of the duplication. __setup_exceptions is called with a relocation offset parameter (r5) which is set to zero for pre-reloc init and gd->reloc_off for post-reloc exception setup. Cc: Michal Simek Signed-off-by: Ovidiu Panait Signed-off-by: Michal Simek --- arch/microblaze/cpu/start.S | 271 +++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 131 deletions(-) diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index cbec299b7d8..b9c6ccc9122 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -13,13 +13,6 @@ .text .global _start _start: - /* - * reserve registers: - * r10: Stores little/big endian offset for vectors - * r2: Stores imm opcode - * r3: Stores brai opcode - */ - mts rmsr, r0 /* disable cache */ addi r8, r0, __end @@ -38,102 +31,16 @@ _start: mts rshr, r1 addi r1, r1, -4 /* Decrement SP to top of memory */ - /* Find-out if u-boot is running on BIG/LITTLE endian platform - * There are some steps which is necessary to keep in mind: - * 1. Setup offset value to r6 - * 2. Store word offset value to address 0x0 - * 3. Load just byte from address 0x0 - * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest - * value that's why is on address 0x0 - * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 - */ - addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ - lwi r7, r0, 0x28 - swi r6, r0, 0x28 /* used first unused MB vector */ - lbui r10, r0, 0x28 /* used first unused MB vector */ - swi r7, r0, 0x28 - - /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ - addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ - addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ - -#ifdef CONFIG_SYS_RESET_ADDRESS - /* reset address */ - swi r2, r0, 0x0 /* reset address - imm opcode */ - swi r3, r0, 0x4 /* reset address - brai opcode */ - - addik r6, r0, CONFIG_SYS_RESET_ADDRESS - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0x2 - sh r7, r0, r8 - rsubi r8, r10, 0x6 - sh r6, r0, r8 -#endif - -#ifdef CONFIG_SYS_USR_EXCEP - /* user_vector_exception */ - swi r2, r0, 0x8 /* user vector exception - imm opcode */ - swi r3, r0, 0xC /* user vector exception - brai opcode */ - - addik r6, r0, _exception_handler - sw r6, r1, r0 - /* - * BIG ENDIAN memory map for user exception - * 0x8: 0xB000XXXX - * 0xC: 0xB808XXXX - * - * then it is necessary to count address for storing the most significant - * 16bits from _exception_handler address and copy it to - * 0xa address. Big endian use offset in r10=0 that's why is it just - * 0xa address. The same is done for the least significant 16 bits - * for 0xe address. - * - * LITTLE ENDIAN memory map for user exception - * 0x8: 0xXXXX00B0 - * 0xC: 0xXXXX08B8 - * - * Offset is for little endian setup to 0x2. rsubi instruction decrease - * address value to ensure that points to proper place which is - * 0x8 for the most significant 16 bits and - * 0xC for the least significant 16 bits - */ - lhu r7, r1, r10 - rsubi r8, r10, 0xa - sh r7, r0, r8 - rsubi r8, r10, 0xe - sh r6, r0, r8 -#endif - - /* interrupt_handler */ - swi r2, r0, 0x10 /* interrupt - imm opcode */ - swi r3, r0, 0x14 /* interrupt - brai opcode */ - - addik r6, r0, _interrupt_handler - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0x12 - sh r7, r0, r8 - rsubi r8, r10, 0x16 - sh r6, r0, r8 - - /* hardware exception */ - swi r2, r0, 0x20 /* hardware exception - imm opcode */ - swi r3, r0, 0x24 /* hardware exception - brai opcode */ - - addik r6, r0, _hw_exception_handler - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0x22 - sh r7, r0, r8 - rsubi r8, r10, 0x26 - sh r6, r0, r8 + /* Setup vectors with pre-relocation symbols */ + or r5, r0, r0 + bralid r15, __setup_exceptions + nop #endif /* CONFIG_SPL_BUILD */ /* Flush cache before enable cache */ addik r5, r0, 0 addik r6, r0, XILINX_DCACHE_BYTE_SIZE - bralid r15, flush_cache + bralid r15, flush_cache nop /* enable instruction and data cache */ @@ -182,6 +89,137 @@ _gd: .space GENERATED_GBL_DATA_SIZE #ifndef CONFIG_SPL_BUILD + .text + .ent __setup_exceptions + .align 2 +/* + * Set up reset, interrupt, user exception and hardware exception vectors. + * + * Parameters: + * r5 - relocation offset (zero when setting up vectors before + * relocation, and gd->reloc_off when setting up vectors after + * relocation) + * - the relocation offset is added to the _exception_handler, + * _interrupt_handler and _hw_exception_handler symbols to reflect the + * post-relocation memory addresses + * + * Reserve registers: + * r10: Stores little/big endian offset for vectors + * r2: Stores imm opcode + * r3: Stores brai opcode + */ +__setup_exceptions: + addik r1, r1, -28 + swi r2, r1, 4 + swi r3, r1, 8 + swi r6, r1, 12 + swi r7, r1, 16 + swi r8, r1, 20 + swi r10, r1, 24 + + /* Find-out if u-boot is running on BIG/LITTLE endian platform + * There are some steps which is necessary to keep in mind: + * 1. Setup offset value to r6 + * 2. Store word offset value to address 0x0 + * 3. Load just byte from address 0x0 + * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest + * value that's why is on address 0x0 + * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 + */ + addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ + lwi r7, r0, 0x28 + swi r6, r0, 0x28 /* used first unused MB vector */ + lbui r10, r0, 0x28 /* used first unused MB vector */ + swi r7, r0, 0x28 + + /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ + addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ + addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ + +#ifdef CONFIG_SYS_RESET_ADDRESS + /* reset address */ + swi r2, r0, 0x0 /* reset address - imm opcode */ + swi r3, r0, 0x4 /* reset address - brai opcode */ + + addik r6, r0, CONFIG_SYS_RESET_ADDRESS + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x2 + sh r7, r0, r8 + rsubi r8, r10, 0x6 + sh r6, r0, r8 +#endif + +#ifdef CONFIG_SYS_USR_EXCEP + /* user_vector_exception */ + swi r2, r0, 0x8 /* user vector exception - imm opcode */ + swi r3, r0, 0xC /* user vector exception - brai opcode */ + + addik r6, r5, _exception_handler + sw r6, r1, r0 + /* + * BIG ENDIAN memory map for user exception + * 0x8: 0xB000XXXX + * 0xC: 0xB808XXXX + * + * then it is necessary to count address for storing the most significant + * 16bits from _exception_handler address and copy it to + * 0xa address. Big endian use offset in r10=0 that's why is it just + * 0xa address. The same is done for the least significant 16 bits + * for 0xe address. + * + * LITTLE ENDIAN memory map for user exception + * 0x8: 0xXXXX00B0 + * 0xC: 0xXXXX08B8 + * + * Offset is for little endian setup to 0x2. rsubi instruction decrease + * address value to ensure that points to proper place which is + * 0x8 for the most significant 16 bits and + * 0xC for the least significant 16 bits + */ + lhu r7, r1, r10 + rsubi r8, r10, 0xa + sh r7, r0, r8 + rsubi r8, r10, 0xe + sh r6, r0, r8 +#endif + + /* interrupt_handler */ + swi r2, r0, 0x10 /* interrupt - imm opcode */ + swi r3, r0, 0x14 /* interrupt - brai opcode */ + + addik r6, r5, _interrupt_handler + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x12 + sh r7, r0, r8 + rsubi r8, r10, 0x16 + sh r6, r0, r8 + + /* hardware exception */ + swi r2, r0, 0x20 /* hardware exception - imm opcode */ + swi r3, r0, 0x24 /* hardware exception - brai opcode */ + + addik r6, r5, _hw_exception_handler + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x22 + sh r7, r0, r8 + rsubi r8, r10, 0x26 + sh r6, r0, r8 + + lwi r10, r1, 24 + lwi r8, r1, 20 + lwi r7, r1, 16 + lwi r6, r1, 12 + lwi r3, r1, 8 + lwi r2, r1, 4 + addik r1, r1, 28 + + rtsd r15, 8 + or r0, r0, r0 + .end __setup_exceptions + /* * Read 16bit little endian */ @@ -249,39 +287,10 @@ relocate_code: addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ - addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ - lwi r7, r0, 0x28 - swi r6, r0, 0x28 /* used first unused MB vector */ - lbui r10, r0, 0x28 /* used first unused MB vector */ - swi r7, r0, 0x28 - -#ifdef CONFIG_SYS_USR_EXCEP - addik r6, r0, _exception_handler - addk r6, r6, r23 /* add offset */ - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0xa - sh r7, r0, r8 - rsubi r8, r10, 0xe - sh r6, r0, r8 -#endif - addik r6, r0, _hw_exception_handler - addk r6, r6, r23 /* add offset */ - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0x22 - sh r7, r0, r8 - rsubi r8, r10, 0x26 - sh r6, r0, r8 - - addik r6, r0, _interrupt_handler - addk r6, r6, r23 /* add offset */ - sw r6, r1, r0 - lhu r7, r1, r10 - rsubi r8, r10, 0x12 - sh r7, r0, r8 - rsubi r8, r10, 0x16 - sh r6, r0, r8 + /* Setup vectors with post-relocation symbols */ + add r5, r0, r23 /* load gd->reloc_off to r5 */ + bralid r15, __setup_exceptions + nop /* Check if GOT exist */ addik r21, r23, _got_start From f5d8b1a1f9f08911636dc095c7f4f281a0dfc59d Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Thu, 24 Sep 2020 11:54:37 +0300 Subject: [PATCH 02/71] microblaze: start.S: Use board_init_f_alloc/init in early init Implement early init by calling generic board_init_f_alloc_reserve and board_init_f_init_reserve functions: * drop SYS_MALLOC_F_LEN related code, as allocation and gd->malloc_base assignment are taken care of by the generic functions * drop _gd logic Cc: Michal Simek Signed-off-by: Ovidiu Panait --- arch/microblaze/cpu/start.S | 46 +++++++++++++--------------- include/configs/microblaze-generic.h | 3 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index b9c6ccc9122..9479737aa29 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -17,25 +17,39 @@ _start: addi r8, r0, __end mts rslr, r8 - /* TODO: Redo this code to call board_init_f_*() */ + #if defined(CONFIG_SPL_BUILD) addi r1, r0, CONFIG_SPL_STACK_ADDR - mts rshr, r1 - addi r1, r1, -4 /* Decrement SP to top of memory */ -#else -#if CONFIG_VAL(SYS_MALLOC_F_LEN) - addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_VAL(SYS_MALLOC_F_LEN) #else addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET #endif - mts rshr, r1 + addi r1, r1, -4 /* Decrement SP to top of memory */ + /* Call board_init_f_alloc_reserve with the current stack pointer as + * parameter. */ + add r5, r0, r1 + bralid r15, board_init_f_alloc_reserve + nop + + /* board_init_f_alloc_reserve returns a pointer to the allocated area + * in r3. Set the new stack pointer below this area. */ + add r1, r0, r3 + mts rshr, r1 + addi r1, r1, -4 + + /* Call board_init_f_init_reserve with the address returned by + * board_init_f_alloc_reserve as parameter. */ + add r5, r0, r3 + bralid r15, board_init_f_init_reserve + nop + +#if !defined(CONFIG_SPL_BUILD) /* Setup vectors with pre-relocation symbols */ or r5, r0, r0 bralid r15, __setup_exceptions nop -#endif /* CONFIG_SPL_BUILD */ +#endif /* Flush cache before enable cache */ addik r5, r0, 0 @@ -48,7 +62,6 @@ _start: ori r12, r12, 0x1a0 mts rmsr, r12 - /* TODO: Redo this code to call board_init_f_*() */ clear_bss: /* clear BSS segments */ addi r5, r0, __bss_start @@ -67,27 +80,12 @@ clear_bss: #endif #ifndef CONFIG_SPL_BUILD or r5, r0, r0 /* flags - empty */ - addi r31, r0, _gd -#if CONFIG_VAL(SYS_MALLOC_F_LEN) - addi r6, r0, CONFIG_SYS_INIT_SP_OFFSET - swi r6, r31, GD_MALLOC_BASE -#endif brai board_init_f #else - addi r31, r0, _gd -#if CONFIG_VAL(SYS_MALLOC_F_LEN) - addi r6, r0, CONFIG_SPL_STACK_ADDR - swi r6, r31, GD_MALLOC_BASE -#endif brai board_init_r #endif 1: bri 1b - .section .bss -.align 4 -_gd: - .space GENERATED_GBL_DATA_SIZE - #ifndef CONFIG_SPL_BUILD .text .ent __setup_exceptions diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h index 8ca0e83c783..dfc2cd97d33 100644 --- a/include/configs/microblaze-generic.h +++ b/include/configs/microblaze-generic.h @@ -167,8 +167,7 @@ #define CONFIG_SYS_INIT_RAM_SIZE 0x100000 # define CONFIG_SPL_STACK_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ - CONFIG_SYS_INIT_RAM_SIZE - \ - CONFIG_SYS_MALLOC_F_LEN) + CONFIG_SYS_INIT_RAM_SIZE) /* Just for sure that there is a space for stack */ #define CONFIG_SPL_STACK_SIZE 0x100 From 79d4204f72a60b4c1a1166942bd7c5adc8e040e5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 16 Sep 2020 15:25:08 +0200 Subject: [PATCH 03/71] MAINTAINERS: Record documentation for Xilinx platforms Add fragment to cover documenation for Xilinx platforms. Signed-off-by: Michal Simek Reviewed-by: Heinrich Schuchardt --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fc4fad46eee..2c4326f9c98 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -546,6 +546,7 @@ M: Michal Simek S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze.git F: arch/arm/mach-zynq/ +F: doc/board/xilinx/ F: drivers/clk/clk_zynq.c F: drivers/fpga/zynqpl.c F: drivers/gpio/zynq_gpio.c From 2bf4f763e6e7a3a65e60decc6d4fed6fdbf1010a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 14 Sep 2020 14:47:21 +0200 Subject: [PATCH 04/71] doc: board: xilinx: zynq.rst: Update zynq documentation - Correct location of BSP code - Remove TODO which is done already Signed-off-by: Michal Simek --- doc/board/xilinx/zynq.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/doc/board/xilinx/zynq.rst b/doc/board/xilinx/zynq.rst index f564434b69c..438912fe42c 100644 --- a/doc/board/xilinx/zynq.rst +++ b/doc/board/xilinx/zynq.rst @@ -83,7 +83,7 @@ Mainline status --------------- - Added basic board configurations support. -- Added zynq u-boot bsp code - arch/arm/cpu/armv7/zynq +- Added zynq u-boot bsp code - arch/arm/mach-zynq - Added zynq boards named - zc70x, zed, microzed, zc770_xm010/xm011/xm012/xm013 - Added zynq drivers: @@ -99,11 +99,6 @@ Mainline status - Added basic FDT support for zynq boards - d-cache support for zynq_gem.c -TODO ----- - -Add FDT support on individual drivers - * [1] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC702-G.htm * [2] http://www.xilinx.com/products/boards-and-kits/EK-Z7-ZC706-G.htm * [3] http://zedboard.org/product/zedboard From 4286f32a4eb85c60c5da7ad4211e5aeb71969e21 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 16 Sep 2020 15:16:45 +0200 Subject: [PATCH 05/71] doc: board: xilinx: Update links to DT binding docs Several drivers have been added without updating documentation. And also some dt bindings have been moved to yaml. Signed-off-by: Michal Simek --- doc/board/xilinx/xilinx.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/board/xilinx/xilinx.rst b/doc/board/xilinx/xilinx.rst index f6ea5dbe215..8c9afb482d6 100644 --- a/doc/board/xilinx/xilinx.rst +++ b/doc/board/xilinx/xilinx.rst @@ -10,18 +10,28 @@ kernel. * ata - Documentation/devicetree/bindings/ata/ahci-ceva.txt +* clock + - Documentation/devicetree/bindings/clock/xlnx,zynqmp-clk.txt +* firmware + - Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt +* fpga + - Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt * gpio - Documentation/devicetree/bindings/gpio/gpio-xilinx.txt - Documentation/devicetree/bindings/gpio/gpio-zynq.txt * i2c - - Documentation/devicetree/bindings/i2c/i2c-xiic.txt - - Documentation/devicetree/bindings/i2c/i2c-cadence.txt + - Documentation/devicetree/bindings/i2c/xlnx,xps-iic-2.00.a.yaml + - Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml * mmc - - Documentation/devicetree/bindings/mmc/arasan,sdhci.txt + - Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml * net - Documentation/devicetree/bindings/net/macb.txt - Documentation/devicetree/bindings/net/xilinx_axienet.txt - Documentation/devicetree/bindings/net/xilinx_emaclite.txt +* nvmem + - Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.txt +* power + - Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.txt * serial - Documentation/devicetree/bindings/serial/cdns,uart.txt - Documentation/devicetree/bindings/serial/xlnx,opb-uartlite.txt From bbda59ed418a1a17571eaf9cce8d8ed0b5441f61 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 16 Sep 2020 15:16:37 +0200 Subject: [PATCH 06/71] doc: board: xilinx: Add documentation for ZynqMP Add missing documentation for Xilinx ZynqMP configuration with steps how to configure it and run it. Signed-off-by: Michal Simek --- doc/board/xilinx/index.rst | 1 + doc/board/xilinx/zynqmp.rst | 115 ++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 doc/board/xilinx/zynqmp.rst diff --git a/doc/board/xilinx/index.rst b/doc/board/xilinx/index.rst index 47f09290af0..e9560f208fb 100644 --- a/doc/board/xilinx/index.rst +++ b/doc/board/xilinx/index.rst @@ -8,3 +8,4 @@ Xilinx xilinx zynq + zynqmp diff --git a/doc/board/xilinx/zynqmp.rst b/doc/board/xilinx/zynqmp.rst new file mode 100644 index 00000000000..a035cff1a5b --- /dev/null +++ b/doc/board/xilinx/zynqmp.rst @@ -0,0 +1,115 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. (C) Copyright 2020 Xilinx, Inc. + +ZYNQMP +====== + +About this +---------- + +This document describes the information about Xilinx Zynq UltraScale+ MPSOC +U-Boot support. Core support is available in arch/arm/mach-zynqmp folder. + +ZynqMP boards +------------- + +* zcu100 (ultra96 v1), zcu102, zcu104, zcu106 - Evaluation boards +* zc1232 - Characterization boards +* zcu111, zcu208, zcu216 - RFSOC evaluation boards +* zcu1254, zcu1275, zcu1285 - RFSOC characterization boards +* a2197 - System Controller on Versal boards +* mini - Mini U-Boot running out of OCM +* zc1751 - Characterization Processor boards + - zc1751-xm015-dc1 + - zc1751-xm016-dc2 + - zc1751-xm017-dc3 + - zc1751-xm018-dc4 + - zc1751-xm019-dc5 + +Building +-------- + +Configure and build for zcu102 board:: + + $ source arm64 toolchain + $ export DEVICE_TREE=zynqmp-zcu102-revA + $ make xilinx_zynqmp_virt_defconfig + $ make + +U-Boot SPL flow +--------------- + +For getting U-Boot SPL flow up and running it is necessary to do some additional +steps because booting device requires external images which are not the part of +U-Boot repository. + +PMU firmware +^^^^^^^^^^^^ +The Platform Management Unit (PMU) RAM can be loaded with a firmware (PMU +Firmware) at run-time and can be used to extend or customize the functionality +of PMU. The PMU firmware is the part of boot image (boot.bin) and it is +automatically loaded by BootROM. boot.bin can be directly generated by mkimage +tool as the part of make. If you want to create boot.bin with PMU Firmware +include please point CONFIG_PMUFW_INIT_FILE to PMU firmware binary. For example::: + + CONFIG_PMUFW_INIT_FILE="/pmu.bin" + +If you see below message you need to load PMU Firmware:: + + PMUFW is not found - Please load it! + +The second external blob is PMU Configuration object which is object which is +passed from U-Boot SPL to PMU Firmware for initial system configuration. PMU +configuration object is the part of U-Boot SPL image. For pointing to this +object please use CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE symbol. For example::: + + CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE="/pmu_obj.bin" + + +PMU configuration object +^^^^^^^^^^^^^^^^^^^^^^^^ + +Object can be obtain in several ways. The easiest way is to take pm_cfg_obj.c +from SDK/Vitis design and build it::: + + $ git clone https://github.com/Xilinx/embeddedsw.git + $ export EMBEDDED_SW=$PWD/embeddedsw + $ gcc -c pm_cfg_obj.c -I ${EMBEDDED_SW}/lib/bsp/standalone/src/common/ -I ${EMBEDDED_SW}/lib/sw_services/xilpm/src/zynqmp/client/common/ + $ objcopy -O binary pm_cfg_obj.o pmu_obj.bin + +The second way is to use tools/zynqmp_pm_cfg_obj_convert.py. For more +information about this tool please run it with -h parameter. + +The third way is to extract it from Xilinx FSBL elf file. Object is starting at +XPm_ConfigObject symbol. + + +Arm Trusted Firmware (ATF) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +U-Boot itself can run from EL3 to EL1. Without ATF U-Boot runs in EL3. Boot flow +is U-Boot SPL->U-Boot in EL3. When ATF is used U-Boot normally runs in EL2. Boot +flow is U-Boot SPL->ATF->U-Boot in EL2. As the part of build process u-boot.itb +is generated. When BL31 shell variable is present u-boot.itb is generated with +ATF included. You can point to it by::: + + $ export BL31=/bl31.bin + +Flashing +-------- + +SD Card +^^^^^^^ + +To write an image that boots from a SD card first create a FAT32 partition +and a FAT32 filesystem on the SD card:: + + sudo fdisk /dev/sdx + sudo mkfs.vfat -F 32 /dev/sdx1 + +Mount the SD card and copy the SPL and U-Boot to the root directory of the +SD card:: + + sudo mount -t vfat /dev/sdx1 /mnt + sudo cp spl/boot.bin /mnt + sudo cp u-boot.itb /mnt From 0d4e6a2d3b39437d6bf5e4b07c442af7ace805d2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 14 Sep 2020 15:00:06 +0200 Subject: [PATCH 07/71] doc: board: xilinx: Add documentation for ZynqMP R5 Add missing documentation for Xilinx ZynqMP R5 configuration with steps how to run it. Signed-off-by: Michal Simek --- doc/board/xilinx/index.rst | 1 + doc/board/xilinx/zynqmp-r5.rst | 137 +++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 doc/board/xilinx/zynqmp-r5.rst diff --git a/doc/board/xilinx/index.rst b/doc/board/xilinx/index.rst index e9560f208fb..2e31fe3f3a4 100644 --- a/doc/board/xilinx/index.rst +++ b/doc/board/xilinx/index.rst @@ -9,3 +9,4 @@ Xilinx xilinx zynq zynqmp + zynqmp-r5 diff --git a/doc/board/xilinx/zynqmp-r5.rst b/doc/board/xilinx/zynqmp-r5.rst new file mode 100644 index 00000000000..2cd368b0308 --- /dev/null +++ b/doc/board/xilinx/zynqmp-r5.rst @@ -0,0 +1,137 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. (C) Copyright 2020 Xilinx, Inc. + +ZYNQMP-R5 +========= + +About this +---------- + +This document describes the information about Xilinx Zynq UltraScale+ MPSOC +U-Boot Cortex R5 support. + +ZynqMP R5 boards +---------------- + +* zynqmp-r5 - U-Boot running on RPU Cortex-R5 + +Building +-------- + +configure and build armv7 toolchain:: + + $ make xilinx_zynqmp_r5_defconfig + $ make + +Notes +^^^^^ + +Output fragment is u-boot. + +Loading +------- + +ZynqMP R5 U-Boot was created for supporting loading OS on RPU. There are two +ways how to start U-Boot on R5. + +Bootgen +^^^^^^^ + +The first way is to use Xilinx FSBL (First stage +bootloader) to load u-boot and start it. The following bif can be used for boot +image generation via Xilinx bootgen utility:: + + + the_ROM_image: + { + [bootloader,destination_cpu=r5-0] fsbl_rpu.elf + [destination_cpu=r5-0]u-boot.elf + } + +Bootgen command for building boot.bin:: + + bootgen -image .bif -r -w -o i boot.bin + + +U-Boot cpu command +^^^^^^^^^^^^^^^^^^ + +The second way to load U-Boot to Cortex R5 is from U-Boot running on A53 as is +visible from the following log:: + + U-Boot SPL 2020.10-rc4-00090-g801b3d5c5757 (Sep 15 2020 - 14:07:24 +0200) + PMUFW: v1.1 + Loading new PMUFW cfg obj (2024 bytes) + EL Level: EL3 + Multiboot: 0 + Trying to boot from MMC2 + spl: could not initialize mmc. error: -19 + Trying to boot from MMC1 + spl_load_image_fat_os: error reading image u-boot.bin, err - -2 + NOTICE: ATF running on XCZU7EG/EV/silicon v4/RTL5.1 at 0xfffea000 + NOTICE: BL31: v2.2(release):v2.2-614-ged9dc512fb9c + NOTICE: BL31: Built : 09:32:09, Mar 13 2020 + + + U-Boot 2020.10-rc4-00090-g801b3d5c5757 (Sep 15 2020 - 14:07:24 +0200) + + Model: ZynqMP ZCU104 RevC + Board: Xilinx ZynqMP + DRAM: 2 GiB + PMUFW: v1.1 + EL Level: EL2 + Chip ID: zu7e + WDT: Started with servicing (60s timeout) + NAND: 0 MiB + MMC: mmc@ff170000: 0 + Loading Environment from FAT... *** Warning - bad CRC, using default environment + + In: serial + Out: serial + Err: serial + Bootmode: LVL_SHFT_SD_MODE1 + Reset reason: SOFT + Net: + ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 12, interface rgmii-id + eth0: ethernet@ff0e0000 + Hit any key to stop autoboot: 0 + ZynqMP> setenv autoload no + ZynqMP> dhcp + BOOTP broadcast 1 + DHCP client bound to address 192.168.0.167 (8 ms) + ZynqMP> tftpboot 20000000 192.168.0.105:u-boot-r5-2.elf + Using ethernet@ff0e0000 device + TFTP from server 192.168.0.105; our IP address is 192.168.0.167 + Filename 'u-boot-r5-2.elf'. + Load address: 0x20000000 + Loading: ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################ + 376 KiB/s + done + Bytes transferred = 2075464 (1fab48 hex) + ZynqMP> setenv autostart no + ZynqMP> bootelf -p 20000000 + ZynqMP> cpu 4 release 10000000 lockstep + Using TCM jump trampoline for address 0x10000000 + R5 lockstep mode + ZynqMP> + +Then on second uart you can see U-Boot up and running on R5:: + + U-Boot 2020.10-rc4-00071-g7045622cc9ba (Sep 16 2020 - 13:38:53 +0200) + + Model: Xilinx ZynqMP R5 + DRAM: 512 MiB + MMC: + In: serial@ff010000 + Out: serial@ff010000 + Err: serial@ff010000 + Net: No ethernet found. + ZynqMP r5> + +Please make sure MIO pins for uart are properly configured to see output. From bd897a078953d1b07d409e89bdd8bc9ef1dbf8a4 Mon Sep 17 00:00:00 2001 From: Alexandre GRIVEAUX Date: Thu, 1 Oct 2020 10:33:36 +0200 Subject: [PATCH 08/71] ARM: zynq: Add Z-turn board V5 Adding Z-turn board V5 to resolve the change between: "Z-TURNBOARD_schematic.pdf" schematics state version 1 to 4 has Atheros AR8035 "Z-Turn_Board_sch_V15_20160303.pdf" schematics state version 5 has Micrel KSZ9031 At this time the S25FL128SAGNFI003 doesn't work because of bug: *** Warning - spi_flash_probe_bus_cs() failed, using default environment zynq-zturn was checked on V5 board, same error. Maybe Z-turn board have the same problem (board with W25Q128BVFIG). Signed-off-by: Alexandre GRIVEAUX Signed-off-by: Michal Simek --- arch/arm/dts/Makefile | 1 + arch/arm/dts/zynq-zturn-common.dtsi | 120 ++++++++ arch/arm/dts/zynq-zturn-v5.dts | 15 + arch/arm/dts/zynq-zturn.dts | 109 +------ .../xilinx/zynq/zynq-zturn-v5/ps7_init_gpl.c | 273 ++++++++++++++++++ configs/xilinx_zynq_virt_defconfig | 4 +- 6 files changed, 413 insertions(+), 109 deletions(-) create mode 100644 arch/arm/dts/zynq-zturn-common.dtsi create mode 100644 arch/arm/dts/zynq-zturn-v5.dts create mode 100644 board/xilinx/zynq/zynq-zturn-v5/ps7_init_gpl.c diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index b195723f164..687a92f685c 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -279,6 +279,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \ zynq-zc770-xm013.dtb \ zynq-zed.dtb \ zynq-zturn.dtb \ + zynq-zturn-v5.dtb \ zynq-zybo.dtb \ zynq-zybo-z7.dtb dtb-$(CONFIG_ARCH_ZYNQMP) += \ diff --git a/arch/arm/dts/zynq-zturn-common.dtsi b/arch/arm/dts/zynq-zturn-common.dtsi new file mode 100644 index 00000000000..1d7af02893d --- /dev/null +++ b/arch/arm/dts/zynq-zturn-common.dtsi @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2015 Andrea Merello + * Copyright (C) 2017 Alexander Graf + * + * Based on zynq-zed.dts which is: + * Copyright (C) 2011 - 2014 Xilinx + * Copyright (C) 2012 National Instruments Corp. + * + */ + +/dts-v1/; +/include/ "zynq-7000.dtsi" + +/ { + compatible = "xlnx,zynq-7000"; + + aliases { + ethernet0 = &gem0; + serial0 = &uart1; + serial1 = &uart0; + mmc0 = &sdhci0; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-leds { + compatible = "gpio-leds"; + usr-led1 { + label = "usr-led1"; + gpios = <&gpio0 0x0 0x1>; + default-state = "off"; + }; + + usr-led2 { + label = "usr-led2"; + gpios = <&gpio0 0x9 0x1>; + default-state = "off"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + K1 { + label = "K1"; + gpios = <&gpio0 0x32 0x1>; + linux,code = <0x66>; + wakeup-source; + autorepeat; + }; + }; +}; + +&clkc { + ps-clk-frequency = <33333333>; +}; + +&qspi { + u-boot,dm-pre-reloc; + status = "okay"; +}; + +&gem0 { + status = "okay"; + phy-mode = "rgmii-id"; + phy-handle = <ðernet_phy>; + + ethernet_phy: ethernet-phy@0 { + }; +}; + +&sdhci0 { + u-boot,dm-pre-reloc; + status = "okay"; +}; + +&uart0 { + u-boot,dm-pre-reloc; + status = "okay"; +}; + +&uart1 { + u-boot,dm-pre-reloc; + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&can0 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = <400000>; + + stlm75@49 { + status = "okay"; + compatible = "lm75"; + reg = <0x49>; + }; + + accelerometer@53 { + compatible = "adi,adxl345", "adxl345", "adi,adxl34x", "adxl34x"; + reg = <0x53>; + interrupt-parent = <&intc>; + interrupts = <0x0 0x1e 0x4>; + }; +}; diff --git a/arch/arm/dts/zynq-zturn-v5.dts b/arch/arm/dts/zynq-zturn-v5.dts new file mode 100644 index 00000000000..536632a09a2 --- /dev/null +++ b/arch/arm/dts/zynq-zturn-v5.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 + +/dts-v1/; +/include/ "zynq-zturn-common.dtsi" + +/ { + model = "Zynq Z-Turn MYIR Board V5"; + compatible = "myir,zynq-zturn-v5", "xlnx,zynq-7000"; +}; + +&gem0 { + ethernet_phy: ethernet-phy@0 { + reg = <0x3>; + }; +}; diff --git a/arch/arm/dts/zynq-zturn.dts b/arch/arm/dts/zynq-zturn.dts index 600e8ee0255..620b24a25e0 100644 --- a/arch/arm/dts/zynq-zturn.dts +++ b/arch/arm/dts/zynq-zturn.dts @@ -1,122 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2015 Andrea Merello - * Copyright (C) 2017 Alexander Graf - * - * Based on zynq-zed.dts which is: - * Copyright (C) 2011 - 2014 Xilinx - * Copyright (C) 2012 National Instruments Corp. - * - */ /dts-v1/; -/include/ "zynq-7000.dtsi" +/include/ "zynq-zturn-common.dtsi" / { model = "Zynq Z-Turn MYIR Board"; compatible = "myir,zynq-zturn", "xlnx,zynq-7000"; - - aliases { - ethernet0 = &gem0; - serial0 = &uart1; - serial1 = &uart0; - mmc0 = &sdhci0; - }; - - memory@0 { - device_type = "memory"; - reg = <0x0 0x40000000>; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - gpio-leds { - compatible = "gpio-leds"; - usr-led1 { - label = "usr-led1"; - gpios = <&gpio0 0x0 0x1>; - default-state = "off"; - }; - - usr-led2 { - label = "usr-led2"; - gpios = <&gpio0 0x9 0x1>; - default-state = "off"; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - autorepeat; - K1 { - label = "K1"; - gpios = <&gpio0 0x32 0x1>; - linux,code = <0x66>; - wakeup-source; - autorepeat; - }; - }; -}; - -&clkc { - ps-clk-frequency = <33333333>; -}; - -&qspi { - u-boot,dm-pre-reloc; - status = "okay"; }; &gem0 { - status = "okay"; - phy-mode = "rgmii-id"; - phy-handle = <ðernet_phy>; - ethernet_phy: ethernet-phy@0 { reg = <0x0>; }; }; - -&sdhci0 { - u-boot,dm-pre-reloc; - status = "okay"; -}; - -&uart0 { - u-boot,dm-pre-reloc; - status = "okay"; -}; - -&uart1 { - u-boot,dm-pre-reloc; - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&can0 { - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = <400000>; - - stlm75@49 { - status = "okay"; - compatible = "lm75"; - reg = <0x49>; - }; - - accelerometer@53 { - compatible = "adi,adxl345", "adxl345", "adi,adxl34x", "adxl34x"; - reg = <0x53>; - interrupt-parent = <&intc>; - interrupts = <0x0 0x1e 0x4>; - }; -}; diff --git a/board/xilinx/zynq/zynq-zturn-v5/ps7_init_gpl.c b/board/xilinx/zynq/zynq-zturn-v5/ps7_init_gpl.c new file mode 100644 index 00000000000..5d573868cb1 --- /dev/null +++ b/board/xilinx/zynq/zynq-zturn-v5/ps7_init_gpl.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Xilinx, Inc. + */ + +#include + +static unsigned long ps7_pll_init_data[] = { + EMIT_WRITE(0xF8000008, 0x0000DF0DU), + EMIT_MASKWRITE(0xF8000110, 0x003FFFF0U, 0x000FA220U), + EMIT_MASKWRITE(0xF8000100, 0x0007F000U, 0x00028000U), + EMIT_MASKWRITE(0xF8000100, 0x00000010U, 0x00000010U), + EMIT_MASKWRITE(0xF8000100, 0x00000001U, 0x00000001U), + EMIT_MASKWRITE(0xF8000100, 0x00000001U, 0x00000000U), + EMIT_MASKPOLL(0xF800010C, 0x00000001U), + EMIT_MASKWRITE(0xF8000100, 0x00000010U, 0x00000000U), + EMIT_MASKWRITE(0xF8000120, 0x1F003F30U, 0x1F000200U), + EMIT_MASKWRITE(0xF8000114, 0x003FFFF0U, 0x0012C220U), + EMIT_MASKWRITE(0xF8000104, 0x0007F000U, 0x00020000U), + EMIT_MASKWRITE(0xF8000104, 0x00000010U, 0x00000010U), + EMIT_MASKWRITE(0xF8000104, 0x00000001U, 0x00000001U), + EMIT_MASKWRITE(0xF8000104, 0x00000001U, 0x00000000U), + EMIT_MASKPOLL(0xF800010C, 0x00000002U), + EMIT_MASKWRITE(0xF8000104, 0x00000010U, 0x00000000U), + EMIT_MASKWRITE(0xF8000124, 0xFFF00003U, 0x0C200003U), + EMIT_MASKWRITE(0xF8000118, 0x003FFFF0U, 0x001452C0U), + EMIT_MASKWRITE(0xF8000108, 0x0007F000U, 0x0001E000U), + EMIT_MASKWRITE(0xF8000108, 0x00000010U, 0x00000010U), + EMIT_MASKWRITE(0xF8000108, 0x00000001U, 0x00000001U), + EMIT_MASKWRITE(0xF8000108, 0x00000001U, 0x00000000U), + EMIT_MASKPOLL(0xF800010C, 0x00000004U), + EMIT_MASKWRITE(0xF8000108, 0x00000010U, 0x00000000U), + EMIT_WRITE(0xF8000004, 0x0000767BU), + EMIT_EXIT(), +}; + +static unsigned long ps7_clock_init_data[] = { + EMIT_WRITE(0xF8000008, 0x0000DF0DU), + EMIT_MASKWRITE(0xF8000128, 0x03F03F01U, 0x00700F01U), + EMIT_MASKWRITE(0xF8000138, 0x00000011U, 0x00000001U), + EMIT_MASKWRITE(0xF8000140, 0x03F03F71U, 0x00100801U), + EMIT_MASKWRITE(0xF800014C, 0x00003F31U, 0x00000501U), + EMIT_MASKWRITE(0xF8000150, 0x00003F33U, 0x00001401U), + EMIT_MASKWRITE(0xF8000154, 0x00003F33U, 0x00000A03U), + EMIT_MASKWRITE(0xF800015C, 0x03F03F33U, 0x00200501U), + EMIT_MASKWRITE(0xF8000160, 0x007F007FU, 0x00000000U), + EMIT_MASKWRITE(0xF8000168, 0x00003F31U, 0x00000501U), + EMIT_MASKWRITE(0xF8000170, 0x03F03F30U, 0x00200500U), + EMIT_MASKWRITE(0xF8000180, 0x03F03F30U, 0x00400500U), + EMIT_MASKWRITE(0xF80001C4, 0x00000001U, 0x00000001U), + EMIT_MASKWRITE(0xF800012C, 0x01FFCCCDU, 0x01FD044DU), + EMIT_WRITE(0xF8000004, 0x0000767BU), + EMIT_EXIT(), +}; + +static unsigned long ps7_ddr_init_data[] = { + EMIT_MASKWRITE(0xF8006000, 0x0001FFFFU, 0x00000080U), + EMIT_MASKWRITE(0xF8006004, 0x0007FFFFU, 0x00001082U), + EMIT_MASKWRITE(0xF8006008, 0x03FFFFFFU, 0x03C0780FU), + EMIT_MASKWRITE(0xF800600C, 0x03FFFFFFU, 0x02001001U), + EMIT_MASKWRITE(0xF8006010, 0x03FFFFFFU, 0x00014001U), + EMIT_MASKWRITE(0xF8006014, 0x001FFFFFU, 0x0004285BU), + EMIT_MASKWRITE(0xF8006018, 0xF7FFFFFFU, 0x44E458D3U), + EMIT_MASKWRITE(0xF800601C, 0xFFFFFFFFU, 0x7282BCE5U), + EMIT_MASKWRITE(0xF8006020, 0x7FDFFFFCU, 0x270872D0U), + EMIT_MASKWRITE(0xF8006024, 0x0FFFFFC3U, 0x00000000U), + EMIT_MASKWRITE(0xF8006028, 0x00003FFFU, 0x00002007U), + EMIT_MASKWRITE(0xF800602C, 0xFFFFFFFFU, 0x00000008U), + EMIT_MASKWRITE(0xF8006030, 0xFFFFFFFFU, 0x00040B30U), + EMIT_MASKWRITE(0xF8006034, 0x13FF3FFFU, 0x000116D4U), + EMIT_MASKWRITE(0xF8006038, 0x00000003U, 0x00000000U), + EMIT_MASKWRITE(0xF800603C, 0x000FFFFFU, 0x00000777U), + EMIT_MASKWRITE(0xF8006040, 0xFFFFFFFFU, 0xFFF00000U), + EMIT_MASKWRITE(0xF8006044, 0x0FFFFFFFU, 0x0F666666U), + EMIT_MASKWRITE(0xF8006048, 0x0003F03FU, 0x0003C008U), + EMIT_MASKWRITE(0xF8006050, 0xFF0F8FFFU, 0x77010800U), + EMIT_MASKWRITE(0xF8006058, 0x00010000U, 0x00000000U), + EMIT_MASKWRITE(0xF800605C, 0x0000FFFFU, 0x00005003U), + EMIT_MASKWRITE(0xF8006060, 0x000017FFU, 0x0000003EU), + EMIT_MASKWRITE(0xF8006064, 0x00021FE0U, 0x00020000U), + EMIT_MASKWRITE(0xF8006068, 0x03FFFFFFU, 0x00284141U), + EMIT_MASKWRITE(0xF800606C, 0x0000FFFFU, 0x00001610U), + EMIT_MASKWRITE(0xF8006078, 0x03FFFFFFU, 0x00466111U), + EMIT_MASKWRITE(0xF800607C, 0x000FFFFFU, 0x00032222U), + EMIT_MASKWRITE(0xF80060A4, 0xFFFFFFFFU, 0x10200802U), + EMIT_MASKWRITE(0xF80060A8, 0x0FFFFFFFU, 0x0690CB73U), + EMIT_MASKWRITE(0xF80060AC, 0x000001FFU, 0x000001FEU), + EMIT_MASKWRITE(0xF80060B0, 0x1FFFFFFFU, 0x1CFFFFFFU), + EMIT_MASKWRITE(0xF80060B4, 0x00000200U, 0x00000200U), + EMIT_MASKWRITE(0xF80060B8, 0x01FFFFFFU, 0x00200066U), + EMIT_MASKWRITE(0xF80060C4, 0x00000003U, 0x00000000U), + EMIT_MASKWRITE(0xF80060C8, 0x000000FFU, 0x00000000U), + EMIT_MASKWRITE(0xF80060DC, 0x00000001U, 0x00000000U), + EMIT_MASKWRITE(0xF80060F0, 0x0000FFFFU, 0x00000000U), + EMIT_MASKWRITE(0xF80060F4, 0x0000000FU, 0x00000008U), + EMIT_MASKWRITE(0xF8006114, 0x000000FFU, 0x00000000U), + EMIT_MASKWRITE(0xF8006118, 0x7FFFFFCFU, 0x40000001U), + EMIT_MASKWRITE(0xF800611C, 0x7FFFFFCFU, 0x40000001U), + EMIT_MASKWRITE(0xF8006120, 0x7FFFFFCFU, 0x40000001U), + EMIT_MASKWRITE(0xF8006124, 0x7FFFFFCFU, 0x40000001U), + EMIT_MASKWRITE(0xF800612C, 0x000FFFFFU, 0x0002A81FU), + EMIT_MASKWRITE(0xF8006130, 0x000FFFFFU, 0x00029822U), + EMIT_MASKWRITE(0xF8006134, 0x000FFFFFU, 0x00026C10U), + EMIT_MASKWRITE(0xF8006138, 0x000FFFFFU, 0x00026013U), + EMIT_MASKWRITE(0xF8006140, 0x000FFFFFU, 0x00000035U), + EMIT_MASKWRITE(0xF8006144, 0x000FFFFFU, 0x00000035U), + EMIT_MASKWRITE(0xF8006148, 0x000FFFFFU, 0x00000035U), + EMIT_MASKWRITE(0xF800614C, 0x000FFFFFU, 0x00000035U), + EMIT_MASKWRITE(0xF8006154, 0x000FFFFFU, 0x0000009FU), + EMIT_MASKWRITE(0xF8006158, 0x000FFFFFU, 0x000000A2U), + EMIT_MASKWRITE(0xF800615C, 0x000FFFFFU, 0x00000090U), + EMIT_MASKWRITE(0xF8006160, 0x000FFFFFU, 0x00000093U), + EMIT_MASKWRITE(0xF8006168, 0x001FFFFFU, 0x000000FFU), + EMIT_MASKWRITE(0xF800616C, 0x001FFFFFU, 0x000000FBU), + EMIT_MASKWRITE(0xF8006170, 0x001FFFFFU, 0x000000F0U), + EMIT_MASKWRITE(0xF8006174, 0x001FFFFFU, 0x000000EDU), + EMIT_MASKWRITE(0xF800617C, 0x000FFFFFU, 0x000000DFU), + EMIT_MASKWRITE(0xF8006180, 0x000FFFFFU, 0x000000E2U), + EMIT_MASKWRITE(0xF8006184, 0x000FFFFFU, 0x000000D0U), + EMIT_MASKWRITE(0xF8006188, 0x000FFFFFU, 0x000000D3U), + EMIT_MASKWRITE(0xF8006190, 0x6FFFFEFEU, 0x00040080U), + EMIT_MASKWRITE(0xF8006194, 0x000FFFFFU, 0x0001FC82U), + EMIT_MASKWRITE(0xF8006204, 0xFFFFFFFFU, 0x00000000U), + EMIT_MASKWRITE(0xF8006208, 0x000703FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF800620C, 0x000703FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF8006210, 0x000703FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF8006214, 0x000703FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF8006218, 0x000F03FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF800621C, 0x000F03FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF8006220, 0x000F03FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF8006224, 0x000F03FFU, 0x000003FFU), + EMIT_MASKWRITE(0xF80062A8, 0x00000FF5U, 0x00000000U), + EMIT_MASKWRITE(0xF80062AC, 0xFFFFFFFFU, 0x00000000U), + EMIT_MASKWRITE(0xF80062B0, 0x003FFFFFU, 0x00005125U), + EMIT_MASKWRITE(0xF80062B4, 0x0003FFFFU, 0x000012A8U), + EMIT_MASKPOLL(0xF8000B74, 0x00002000U), + EMIT_MASKWRITE(0xF8006000, 0x0001FFFFU, 0x00000081U), + EMIT_MASKPOLL(0xF8006054, 0x00000007U), + EMIT_EXIT(), +}; + +static unsigned long ps7_mio_init_data[] = { + EMIT_WRITE(0xF8000008, 0x0000DF0DU), + EMIT_MASKWRITE(0xF8000B40, 0x00000FFFU, 0x00000600U), + EMIT_MASKWRITE(0xF8000B44, 0x00000FFFU, 0x00000600U), + EMIT_MASKWRITE(0xF8000B48, 0x00000FFFU, 0x00000672U), + EMIT_MASKWRITE(0xF8000B4C, 0x00000FFFU, 0x00000672U), + EMIT_MASKWRITE(0xF8000B50, 0x00000FFFU, 0x00000674U), + EMIT_MASKWRITE(0xF8000B54, 0x00000FFFU, 0x00000674U), + EMIT_MASKWRITE(0xF8000B58, 0x00000FFFU, 0x00000600U), + EMIT_MASKWRITE(0xF8000B5C, 0xFFFFFFFFU, 0x0018C61CU), + EMIT_MASKWRITE(0xF8000B60, 0xFFFFFFFFU, 0x00F9861CU), + EMIT_MASKWRITE(0xF8000B64, 0xFFFFFFFFU, 0x00F9861CU), + EMIT_MASKWRITE(0xF8000B68, 0xFFFFFFFFU, 0x00F9861CU), + EMIT_MASKWRITE(0xF8000B6C, 0x00007FFFU, 0x00000260U), + EMIT_MASKWRITE(0xF8000B70, 0x00000001U, 0x00000001U), + EMIT_MASKWRITE(0xF8000B70, 0x00000021U, 0x00000020U), + EMIT_MASKWRITE(0xF8000B70, 0x07FEFFFFU, 0x00000823U), + EMIT_MASKWRITE(0xF8000700, 0x00003FFFU, 0x00001600U), + EMIT_MASKWRITE(0xF8000704, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF8000708, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF800070C, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF8000710, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF8000714, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF8000718, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF800071C, 0x00003FFFU, 0x00000600U), + EMIT_MASKWRITE(0xF8000720, 0x00003FFFU, 0x00000602U), + EMIT_MASKWRITE(0xF8000724, 0x00003FFFU, 0x00000600U), + EMIT_MASKWRITE(0xF8000728, 0x00003FFFU, 0x000016E1U), + EMIT_MASKWRITE(0xF800072C, 0x00003FFFU, 0x000016E0U), + EMIT_MASKWRITE(0xF8000730, 0x00003FFFU, 0x00001640U), + EMIT_MASKWRITE(0xF8000734, 0x00003FFFU, 0x00001640U), + EMIT_MASKWRITE(0xF8000738, 0x00003FFFU, 0x00001621U), + EMIT_MASKWRITE(0xF800073C, 0x00003FFFU, 0x00001620U), + EMIT_MASKWRITE(0xF8000740, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF8000744, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF8000748, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF800074C, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF8000750, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF8000754, 0x00003FFFU, 0x00001202U), + EMIT_MASKWRITE(0xF8000758, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF800075C, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF8000760, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF8000764, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF8000768, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF800076C, 0x00003FFFU, 0x00001203U), + EMIT_MASKWRITE(0xF8000770, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF8000774, 0x00003FFFU, 0x00001205U), + EMIT_MASKWRITE(0xF8000778, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF800077C, 0x00003FFFU, 0x00001205U), + EMIT_MASKWRITE(0xF8000780, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF8000784, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF8000788, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF800078C, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF8000790, 0x00003FFFU, 0x00001205U), + EMIT_MASKWRITE(0xF8000794, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF8000798, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF800079C, 0x00003FFFU, 0x00001204U), + EMIT_MASKWRITE(0xF80007A0, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007A4, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007A8, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007AC, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007B0, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007B4, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007B8, 0x00003F01U, 0x00000201U), + EMIT_MASKWRITE(0xF80007BC, 0x00003F01U, 0x00000201U), + EMIT_MASKWRITE(0xF80007C0, 0x00003FFFU, 0x000012E0U), + EMIT_MASKWRITE(0xF80007C4, 0x00003FFFU, 0x000012E1U), + EMIT_MASKWRITE(0xF80007C8, 0x00003FFFU, 0x00000200U), + EMIT_MASKWRITE(0xF80007CC, 0x00003FFFU, 0x00000200U), + EMIT_MASKWRITE(0xF80007D0, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF80007D4, 0x00003FFFU, 0x00001280U), + EMIT_MASKWRITE(0xF8000830, 0x003F003FU, 0x002E002FU), + EMIT_WRITE(0xF8000004, 0x0000767BU), + EMIT_EXIT(), +}; + +static unsigned long ps7_peripherals_init_data[] = { + EMIT_WRITE(0xF8000008, 0x0000DF0DU), + EMIT_MASKWRITE(0xF8000B48, 0x00000180U, 0x00000180U), + EMIT_MASKWRITE(0xF8000B4C, 0x00000180U, 0x00000180U), + EMIT_MASKWRITE(0xF8000B50, 0x00000180U, 0x00000180U), + EMIT_MASKWRITE(0xF8000B54, 0x00000180U, 0x00000180U), + EMIT_WRITE(0xF8000004, 0x0000767BU), + EMIT_MASKWRITE(0xE000D000, 0x00080000U, 0x00080000U), + EMIT_MASKWRITE(0xF8007000, 0x20000000U, 0x00000000U), + EMIT_MASKWRITE(0xE000A244, 0x003FFFFFU, 0x00080000U), + EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370008U), + EMIT_MASKWRITE(0xE000A248, 0x003FFFFFU, 0x00080000U), + EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370000U), + EMIT_MASKDELAY(0xF8F00200, 1), + EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370008U), + EMIT_EXIT(), +}; + +static unsigned long ps7_post_config_0[] = { + EMIT_WRITE(0xF8000008, 0x0000DF0DU), + EMIT_MASKWRITE(0xF8000900, 0x0000000FU, 0x0000000FU), + EMIT_MASKWRITE(0xF8000240, 0xFFFFFFFFU, 0x00000000U), + EMIT_WRITE(0xF8000004, 0x0000767BU), + EMIT_EXIT(), +}; + +int ps7_post_config(void) +{ + return ps7_config(ps7_post_config_0); +} + +int ps7_init(void) +{ + int ret; + + ret = ps7_config(ps7_mio_init_data); + if (ret != PS7_INIT_SUCCESS) + return ret; + + ret = ps7_config(ps7_pll_init_data); + if (ret != PS7_INIT_SUCCESS) + return ret; + + ret = ps7_config(ps7_clock_init_data); + if (ret != PS7_INIT_SUCCESS) + return ret; + + ret = ps7_config(ps7_ddr_init_data); + if (ret != PS7_INIT_SUCCESS) + return ret; + + ret = ps7_config(ps7_peripherals_init_data); + if (ret != PS7_INIT_SUCCESS) + return ret; + return PS7_INIT_SUCCESS; +} diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index b1279452970..df3da763c50 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -49,7 +49,7 @@ CONFIG_CMD_MTDPARTS=y CONFIG_CMD_MTDPARTS_SPREAD=y CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y CONFIG_CMD_UBI=y -CONFIG_OF_LIST="zynq-zc702 zynq-zc706 zynq-zc770-xm010 zynq-zc770-xm011 zynq-zc770-xm011-x16 zynq-zc770-xm012 zynq-zc770-xm013 zynq-cc108 zynq-microzed zynq-minized zynq-picozed zynq-zed zynq-zturn zynq-zybo zynq-zybo-z7 zynq-dlc20-rev1.0" +CONFIG_OF_LIST="zynq-zc702 zynq-zc706 zynq-zc770-xm010 zynq-zc770-xm011 zynq-zc770-xm011-x16 zynq-zc770-xm012 zynq-zc770-xm013 zynq-cc108 zynq-microzed zynq-minized zynq-picozed zynq-zed zynq-zturn zynq-zturn-v5 zynq-zybo zynq-zybo-z7 zynq-dlc20-rev1.0" CONFIG_ENV_OVERWRITE=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y @@ -88,6 +88,8 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_SST=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_MARVELL=y +CONFIG_PHY_MICREL=y +CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_PHY_REALTEK=y CONFIG_PHY_XILINX=y CONFIG_MII=y From bbe086a95038f3143c14c984fde4eaa27a47f1b2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 2 Oct 2020 14:42:05 +0200 Subject: [PATCH 09/71] arm64: zynqmp: Add missing support for 9cg version 9cg version was supported before code refactoring. The patch is adding it back. Fixes: fa793165daf7 ("xilinx: zynqmp: refactor silicon name function") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 28f067a2515..70d6fd422eb 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -100,7 +100,7 @@ static const struct { { .id = 0x04738093, .device = 9, - .variants = ZYNQMP_VARIANT_EG, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, }, { .id = 0x04740093, From b9ac6c0820e6b5d953b847bfa0a217273a1ec7f2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 29 Sep 2020 12:38:17 +0200 Subject: [PATCH 10/71] arm64: zynqmp: Enable EMMC boot Enable EMMC boot commands to be able to change EMMC setup. Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index 5175571c66d..b4123a9bfe9 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -51,6 +51,7 @@ CONFIG_MISC=y CONFIG_I2C_EEPROM=y CONFIG_SYS_I2C_EEPROM_ADDR=0x0 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW=0x0 +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS400_SUPPORT=y From e1303b2bc14fb633dee9716af8a93657e4565eb7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 23 Sep 2020 10:36:47 +0200 Subject: [PATCH 11/71] spi: xilinx_spi: Remove unused variable Remove unused variable: drivers/spi/xilinx_spi.c: In function 'xilinx_spi_xfer': drivers/spi/xilinx_spi.c:254:18: warning: unused variable 'timeout' [-Wunused-variable] 254 | u32 reg, count, timeout; | ^~~~~~~ Fixes: 0c0de58f7b30 ("spi: xilinx_spi: Modify transfer logic xilinx_spi_xfer() function") Signed-off-by: Michal Simek --- drivers/spi/xilinx_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 348630faf38..c0cfe94d443 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -251,7 +251,7 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, unsigned char *rxp = din; u32 txbytes = bytes; u32 rxbytes = bytes; - u32 reg, count, timeout; + u32 reg, count; int ret; debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", From 78efd7847c0ec037a168b8a03b28f949ad4bfffe Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Thu, 17 Sep 2020 06:52:09 -0600 Subject: [PATCH 12/71] microblaze: Enable spi for microblaze Enable SPI drivers and driver model for microblaze. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- arch/microblaze/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index ff6b3c7e3d6..2755cce884c 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -16,6 +16,9 @@ config TARGET_MICROBLAZE_GENERIC select OF_CONTROL select SUPPORT_SPL select SYSRESET + select DM_SPI + select DM_SPI_FLASH + select SPI imply CMD_DM endchoice From 581d6a6da7f619281f3bf6181a2cb438051b0e48 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 22 Sep 2020 05:18:52 -0600 Subject: [PATCH 13/71] microblaze: trivial code fixes Set proper indentation for env variables in microblaze header file. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- include/configs/microblaze-generic.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h index dfc2cd97d33..642de612b7c 100644 --- a/include/configs/microblaze-generic.h +++ b/include/configs/microblaze-generic.h @@ -131,15 +131,16 @@ #define CONFIG_SYS_USR_EXCEP /* user exception */ #ifndef CONFIG_EXTRA_ENV_SETTINGS -#define CONFIG_EXTRA_ENV_SETTINGS "unlock=yes\0" \ - "nor0=flash-0\0"\ - "mtdparts=mtdparts=flash-0:"\ - "256k(u-boot),256k(env),3m(kernel),"\ - "1m(romfs),1m(cramfs),-(jffs2)\0"\ - "nc=setenv stdout nc;"\ - "setenv stdin nc\0" \ - "serial=setenv stdout serial;"\ - "setenv stdin serial\0" +#define CONFIG_EXTRA_ENV_SETTINGS \ + "unlock=yes\0"\ + "nor0=flash-0\0"\ + "mtdparts=mtdparts=flash-0:"\ + "256k(u-boot),256k(env),3m(kernel),"\ + "1m(romfs),1m(cramfs),-(jffs2)\0"\ + "nc=setenv stdout nc;"\ + "setenv stdin nc\0" \ + "serial=setenv stdout serial;"\ + "setenv stdin serial\0" #endif #if defined(CONFIG_XILINX_AXIEMAC) From d6242edcce52499ee24a1994272ecba63fe96e17 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 22 Sep 2020 05:18:53 -0600 Subject: [PATCH 14/71] microblaze: board: Check return value whlie saving env variables Check and print warning if run time env variables are not saved. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- board/xilinx/microblaze-generic/microblaze-generic.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/board/xilinx/microblaze-generic/microblaze-generic.c b/board/xilinx/microblaze-generic/microblaze-generic.c index 4e569e910d9..724c33987ba 100644 --- a/board/xilinx/microblaze-generic/microblaze-generic.c +++ b/board/xilinx/microblaze-generic/microblaze-generic.c @@ -37,6 +37,7 @@ int dram_init(void) int board_late_init(void) { ulong max_size, lowmem_size; + u32 status = 0; #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE) int ret; @@ -58,9 +59,12 @@ int board_late_init(void) /* Linux default LOWMEM_SIZE is 0x30000000 = 768MB */ lowmem_size = gd->ram_base + 768 * 1024 * 1024; - env_set_addr("initrd_high", (void *)min_t(ulong, max_size, - lowmem_size)); - env_set_addr("fdt_high", (void *)min_t(ulong, max_size, lowmem_size)); + status |= env_set_addr("initrd_high", (void *)min_t(ulong, max_size, + lowmem_size)); + status |= env_set_addr("fdt_high", (void *)min_t(ulong, max_size, + lowmem_size)); + if (status) + printf("%s: Saving run time variables FAILED\n", __func__); return 0; } From ed0842d6c5c6681df425bcefcdf259667c9384a9 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 22 Sep 2020 05:18:54 -0600 Subject: [PATCH 15/71] microblaze: Setup distro boot env variables at run time Setup all the distro boot related environment variables at run time. Add BOOT_SCRIPT_OFFSET config to microblaze board Kconfig. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- board/xilinx/microblaze-generic/Kconfig | 5 +++++ .../xilinx/microblaze-generic/microblaze-generic.c | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index f2fa0f72b13..7a97211a1ec 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -38,4 +38,9 @@ config XILINX_MICROBLAZE0_HW_VER string "Core version number" default "7.10.d" +config BOOT_SCRIPT_OFFSET + hex "Boot script offset" + default 0xFC0000 + help + Specifies distro boot script offset in NAND/QSPI flash. endif diff --git a/board/xilinx/microblaze-generic/microblaze-generic.c b/board/xilinx/microblaze-generic/microblaze-generic.c index 724c33987ba..c1ae8fbfe74 100644 --- a/board/xilinx/microblaze-generic/microblaze-generic.c +++ b/board/xilinx/microblaze-generic/microblaze-generic.c @@ -63,6 +63,20 @@ int board_late_init(void) lowmem_size)); status |= env_set_addr("fdt_high", (void *)min_t(ulong, max_size, lowmem_size)); + + status |= env_set_hex("scriptaddr", max_size + SZ_2M); + + status |= env_set_hex("pxefile_addr_r", max_size + SZ_1M); + + status |= env_set_hex("kernel_addr_r", gd->ram_base + SZ_32M); + + status |= env_set_hex("fdt_addr_r", gd->ram_base + SZ_32M - SZ_1M); + + status |= env_set_hex("ramdisk_addr_r", + gd->ram_base + SZ_32M + SZ_4M + SZ_2M); + + status |= env_set_hex("script_offset_f", CONFIG_BOOT_SCRIPT_OFFSET); + if (status) printf("%s: Saving run time variables FAILED\n", __func__); From 44d2be8d6aa5b73a8d8ca1b1d36d2e1e794f449d Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 22 Sep 2020 05:18:55 -0600 Subject: [PATCH 16/71] microblaze: Add support for distro boot Add distro boot support for microblaze and enable jtag, qspi, dhcp, pxe boot targets for distro boot. Enable DISTRO_DEFAULTS config in microblaze defconfig and also enable support for spi xilinx driver & spi vendors to access spi flash by distro boot. Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- configs/microblaze-generic_defconfig | 13 +++++--- include/configs/microblaze-generic.h | 49 ++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/configs/microblaze-generic_defconfig b/configs/microblaze-generic_defconfig index bfbdb492893..df79206ac27 100644 --- a/configs/microblaze-generic_defconfig +++ b/configs/microblaze-generic_defconfig @@ -12,6 +12,7 @@ CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1 CONFIG_XILINX_MICROBLAZE0_USE_DIV=1 CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=1 CONFIG_DEFAULT_DEVICE_TREE="microblaze-generic" +CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_BOOTDELAY=-1 @@ -26,8 +27,6 @@ CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_NOR_SUPPORT=y CONFIG_SPL_OS_BOOT=y CONFIG_SYS_OS_BASE=0x2c060000 -CONFIG_HUSH_PARSER=y -# CONFIG_AUTO_COMPLETE is not set CONFIG_SYS_PROMPT="U-Boot-mONStR> " CONFIG_CMD_IMLS=y CONFIG_CMD_SPL=y @@ -35,10 +34,7 @@ CONFIG_CMD_ASKENV=y CONFIG_CMD_GPIO=y CONFIG_CMD_SAVES=y # CONFIG_CMD_SETEXPR is not set -CONFIG_CMD_DHCP=y CONFIG_CMD_TFTPPUT=y -CONFIG_CMD_MII=y -CONFIG_CMD_PING=y CONFIG_CMD_CACHE=y CONFIG_CMD_JFFS2=y CONFIG_SPL_OF_CONTROL=y @@ -56,6 +52,12 @@ CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y CONFIG_FLASH_CFI_MTD=y CONFIG_SYS_FLASH_PROTECTION=y CONFIG_SYS_FLASH_CFI=y +CONFIG_SPI_FLASH_ISSI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_ATHEROS=y CONFIG_PHY_BROADCOM=y CONFIG_PHY_DAVICOM=y @@ -71,6 +73,7 @@ CONFIG_XILINX_AXIEMAC=y CONFIG_XILINX_EMACLITE=y CONFIG_SYS_NS16550=y CONFIG_XILINX_UARTLITE=y +CONFIG_XILINX_SPI=y CONFIG_SYSRESET_GPIO=y CONFIG_SYSRESET_MICROBLAZE=y CONFIG_WDT=y diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h index 642de612b7c..2b412423508 100644 --- a/include/configs/microblaze-generic.h +++ b/include/configs/microblaze-generic.h @@ -125,11 +125,54 @@ #define CONFIG_SYS_LOAD_ADDR 0 #define CONFIG_HOSTNAME "microblaze-generic" -#define CONFIG_BOOTCOMMAND "base 0;tftp 11000000 image.img;bootm" /* architecture dependent code */ #define CONFIG_SYS_USR_EXCEP /* user exception */ +#if defined(CONFIG_CMD_PXE) && defined(CONFIG_CMD_DHCP) +#define BOOT_TARGET_DEVICES_PXE(func) func(PXE, pxe, na) +#else +#define BOOT_TARGET_DEVICES_PXE(func) +#endif + +#if defined(CONFIG_CMD_DHCP) +#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na) +#else +#define BOOT_TARGET_DEVICES_DHCP(func) +#endif + +#if defined(CONFIG_SPI_FLASH) +# define BOOT_TARGET_DEVICES_QSPI(func) func(QSPI, qspi, na) +#else +# define BOOT_TARGET_DEVICES_QSPI(func) +#endif + +#define BOOTENV_DEV_QSPI(devtypeu, devtypel, instance) \ + "bootcmd_qspi=sf probe 0 0 0 && " \ + "sf read ${scriptaddr} ${script_offset_f} ${script_size_f} && " \ + "echo QSPI: Trying to boot script at ${scriptaddr} && " \ + "source ${scriptaddr}; echo QSPI: SCRIPT FAILED: continuing...;\0" + +#define BOOTENV_DEV_NAME_QSPI(devtypeu, devtypel, instance) \ + "qspi " + +#define BOOT_TARGET_DEVICES_JTAG(func) func(JTAG, jtag, na) + +#define BOOTENV_DEV_JTAG(devtypeu, devtypel, instance) \ + "bootcmd_jtag=echo JTAG: Trying to boot script at ${scriptaddr} && " \ + "source ${scriptaddr}; echo JTAG: SCRIPT FAILED: continuing...;\0" + +#define BOOTENV_DEV_NAME_JTAG(devtypeu, devtypel, instance) \ + "jtag " + +#define BOOT_TARGET_DEVICES(func) \ + BOOT_TARGET_DEVICES_JTAG(func) \ + BOOT_TARGET_DEVICES_QSPI(func) \ + BOOT_TARGET_DEVICES_DHCP(func) \ + BOOT_TARGET_DEVICES_PXE(func) + +#include + #ifndef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ "unlock=yes\0"\ @@ -140,7 +183,9 @@ "nc=setenv stdout nc;"\ "setenv stdin nc\0" \ "serial=setenv stdout serial;"\ - "setenv stdin serial\0" + "setenv stdin serial\0"\ + "script_size_f=0x40000\0"\ + BOOTENV #endif #if defined(CONFIG_XILINX_AXIEMAC) From 90f06e9d20a402311b89b08eff5e1e0f2c987840 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Wed, 7 Oct 2020 00:36:54 -0600 Subject: [PATCH 17/71] arm64: versal: Update mini u-boot eMMC node parameters Mini u-boot eMMC dt parameters are not in sync with full u-boot dt. Frequency for eMMC is fixed to 25Mhz. Due to this, mmc multi-block write commands are failing. Increase frequency to 200Mhz to fix this issue. Add bus-width = <8>, non-removable and disable-wp properties to the node as this is eMMC. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- arch/arm/dts/versal-mini-emmc0.dts | 9 ++++++--- arch/arm/dts/versal-mini-emmc1.dts | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/arm/dts/versal-mini-emmc0.dts b/arch/arm/dts/versal-mini-emmc0.dts index 7826a282134..6a6e7467a23 100644 --- a/arch/arm/dts/versal-mini-emmc0.dts +++ b/arch/arm/dts/versal-mini-emmc0.dts @@ -16,10 +16,10 @@ #size-cells = <2>; model = "Xilinx Versal MINI eMMC0"; - clk25: clk25 { + clk200: clk200 { compatible = "fixed-clock"; #clock-cells = <0x0>; - clock-frequency = <25000000>; + clock-frequency = <200000000>; }; dcc: dcc { @@ -38,9 +38,12 @@ sdhci0: sdhci@f1040000 { compatible = "xlnx,versal-8.9a", "arasan,sdhci-8.9a"; status = "okay"; + non-removable; + disable-wp; + bus-width = <8>; reg = <0x0 0xf1040000 0x0 0x10000>; clock-names = "clk_xin", "clk_ahb"; - clocks = <&clk25 &clk25>; + clocks = <&clk200 &clk200>; xlnx,device_id = <0>; no-1-8-v; xlnx,mio-bank = <0>; diff --git a/arch/arm/dts/versal-mini-emmc1.dts b/arch/arm/dts/versal-mini-emmc1.dts index 2f28f856a6a..c342e6bdf7a 100644 --- a/arch/arm/dts/versal-mini-emmc1.dts +++ b/arch/arm/dts/versal-mini-emmc1.dts @@ -16,10 +16,10 @@ #size-cells = <2>; model = "Xilinx Versal MINI eMMC1"; - clk25: clk25 { + clk200: clk200 { compatible = "fixed-clock"; #clock-cells = <0x0>; - clock-frequency = <25000000>; + clock-frequency = <200000000>; }; dcc: dcc { @@ -38,9 +38,12 @@ sdhci1: sdhci@f1050000 { compatible = "xlnx,versal-8.9a", "arasan,sdhci-8.9a"; status = "okay"; + non-removable; + disable-wp; + bus-width = <8>; reg = <0x0 0xf1050000 0x0 0x10000>; clock-names = "clk_xin", "clk_ahb"; - clocks = <&clk25 &clk25>; + clocks = <&clk200 &clk200>; xlnx,device_id = <1>; no-1-8-v; xlnx,mio-bank = <0>; From 5d5984c70e0e162ff09f055a15386ab21152aae1 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Wed, 7 Oct 2020 01:54:18 -0600 Subject: [PATCH 18/71] config: versal: Update mini u-boot timer clock to 100Mhz Mini u-boot timer clock is not updated when u-boot is migrated from emulator to silicon. Due to this slower clock of 2.72Mhz, delay() functions are not working accurately. Update CONFIG_COUNTER_FREQUENCY to 100Mhz. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- configs/xilinx_versal_mini_defconfig | 2 +- configs/xilinx_versal_mini_emmc0_defconfig | 2 +- configs/xilinx_versal_mini_emmc1_defconfig | 2 +- configs/xilinx_versal_virt_defconfig | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/xilinx_versal_mini_defconfig b/configs/xilinx_versal_mini_defconfig index e72cef9c36d..427268bd588 100644 --- a/configs/xilinx_versal_mini_defconfig +++ b/configs/xilinx_versal_mini_defconfig @@ -7,7 +7,7 @@ CONFIG_NR_DRAM_BANKS=3 CONFIG_ENV_SIZE=0x80 CONFIG_SYS_MALLOC_LEN=0x2000 CONFIG_SYS_MEM_RSVD_FOR_MMU=y -CONFIG_COUNTER_FREQUENCY=2720000 +CONFIG_COUNTER_FREQUENCY=100000000 # CONFIG_PSCI_RESET is not set CONFIG_DEFAULT_DEVICE_TREE="versal-mini" # CONFIG_EXPERT is not set diff --git a/configs/xilinx_versal_mini_emmc0_defconfig b/configs/xilinx_versal_mini_emmc0_defconfig index b5c3ae48843..8837987e35e 100644 --- a/configs/xilinx_versal_mini_emmc0_defconfig +++ b/configs/xilinx_versal_mini_emmc0_defconfig @@ -6,7 +6,7 @@ CONFIG_SYS_TEXT_BASE=0x10000 CONFIG_NR_DRAM_BANKS=1 CONFIG_ENV_SIZE=0x80 CONFIG_SYS_MALLOC_LEN=0x80000 -CONFIG_COUNTER_FREQUENCY=2720000 +CONFIG_COUNTER_FREQUENCY=100000000 # CONFIG_PSCI_RESET is not set CONFIG_DEFAULT_DEVICE_TREE="versal-mini-emmc0" # CONFIG_EXPERT is not set diff --git a/configs/xilinx_versal_mini_emmc1_defconfig b/configs/xilinx_versal_mini_emmc1_defconfig index 871f8cc5c30..b07dc040607 100644 --- a/configs/xilinx_versal_mini_emmc1_defconfig +++ b/configs/xilinx_versal_mini_emmc1_defconfig @@ -6,7 +6,7 @@ CONFIG_SYS_TEXT_BASE=0x10000 CONFIG_NR_DRAM_BANKS=1 CONFIG_ENV_SIZE=0x80 CONFIG_SYS_MALLOC_LEN=0x80000 -CONFIG_COUNTER_FREQUENCY=2720000 +CONFIG_COUNTER_FREQUENCY=100000000 # CONFIG_PSCI_RESET is not set CONFIG_DEFAULT_DEVICE_TREE="versal-mini-emmc1" # CONFIG_EXPERT is not set diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index b4123a9bfe9..b6ca566ed8c 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -5,7 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x100000 CONFIG_DM_GPIO=y CONFIG_DEFINE_TCM_OCM_MMAP=y -CONFIG_COUNTER_FREQUENCY=62500000 +CONFIG_COUNTER_FREQUENCY=100000000 CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y From 5690128f70a1a4038629be0465d0aa53e7b05f27 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Oct 2020 15:23:28 +0200 Subject: [PATCH 19/71] firmware: zynqmp: Swap addr_hi/low when PM_FPGA_LOAD is called Don't know reason but in regular flow addr_hi/low are swapped in ATF. It means when fpga load is done from EL3 there is a need to swap it for PMUFW to load bitstream. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- drivers/firmware/firmware-zynqmp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 7583f24a200..d4dc856bafa 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -165,6 +165,14 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, */ u32 regs[] = {api_id, arg0, arg1, arg2, arg3}; + if (api_id == PM_FPGA_LOAD) { + /* Swap addr_hi/low because of incompatibility */ + u32 temp = regs[1]; + + regs[1] = regs[2]; + regs[2] = temp; + } + ipi_req(regs, PAYLOAD_ARG_CNT, ret_payload, PAYLOAD_ARG_CNT); #else return -EPERM; From f08d0c51b5738fd36748b72a8a98108c7ee1cba0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Oct 2020 15:23:00 +0200 Subject: [PATCH 20/71] mailbox: zynqmp: Extend timeout for getting observation bit In case of fpga loading (which can be huge) 100ms is not enough. That's why extend timeout 10 times to wait maximum 1s to get ACK back. Signed-off-by: Michal Simek --- drivers/mailbox/zynqmp-ipi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index 9483ed9cefc..847a03648b8 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -56,7 +56,7 @@ static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data) /* Wait until observation bit is cleared */ ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false, - 100, false); + 1000, false); debug("%s, send %ld bytes\n", __func__, msg->len); return ret; From 0d76b71d93f6d7740b973dbb50010dc8f7b347f0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 7 Oct 2020 15:13:17 +0200 Subject: [PATCH 21/71] arm64: zynqmp: Get rid of simple_itoa and replace it by snprintf simple_itoa() is implemented only for !CONFIG_USE_TINY_PRINTF. Tiny printf is normally used by SPL that's code which uses simple_itoa() has missing reference. That's why refactor code by using on snprintf() instead of strncpy()/strncat() combination. This change also descrease code size by saving 24B based on buildman. aarch64: (for 1/1 boards) all -22.0 rodata +2.0 text -24.0 xilinx_zynqmp_virt: all -22 rodata +2 text -24 u-boot: add: 0/0, grow: 0/-1 bytes: 0/-24 (-24) function old new delta board_init 520 496 -24 Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 70d6fd422eb..362c6e3dd6f 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -190,6 +190,7 @@ static char *zynqmp_get_silicon_idcode_name(void) u32 idcode, idcode2; char name[ZYNQMP_VERSION_SIZE]; u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); @@ -216,8 +217,10 @@ static char *zynqmp_get_silicon_idcode_name(void) return "unknown"; /* Add device prefix to the name */ - strncpy(name, "zu", ZYNQMP_VERSION_SIZE); - strncat(&name[2], simple_itoa(zynqmp_devices[i].device), 2); + ret = snprintf(name, ZYNQMP_VERSION_SIZE, "zu%d", + zynqmp_devices[i].device); + if (ret <= 0) + return "unknown"; if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_EV) { /* Devices with EV variant might be EG/CG/EV family */ From e9284066958e906118b3fd71d7e81e9916b2c58a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Oct 2020 15:43:44 +0200 Subject: [PATCH 22/71] arm64: zynqmp: Enable FPGA loading from SPL fpga bitstream needs to be listed in config node in FIT image. Only tested option is bitstream in BIN format. Enabling this feature increase code size by almost 4k. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 264b662ece1..5b4fe537c31 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -19,6 +19,7 @@ CONFIG_USE_PREBOOT=y # CONFIG_DISPLAY_CPUINFO is not set CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_EARLY_INIT_R=y +CONFIG_SPL_FPGA=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_RAM_SUPPORT=y CONFIG_SPL_RAM_DEVICE=y From b15412f9a082ebd1d5a20ded21a2fe9f2ed138d0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 7 Oct 2020 15:41:21 +0200 Subject: [PATCH 23/71] arm64: zynqmp: Enable cache command Sometimes it is very useful to be able disable/enable cache that's why enable commands for it by default. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 5b4fe537c31..8ffcd3dadd4 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -50,6 +50,7 @@ CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_CACHE=y CONFIG_CMD_TIME=y CONFIG_CMD_TIMER=y CONFIG_CMD_EXT4_WRITE=y From 248fabc3ceefd1875cb8608e7372220ec4ac9d10 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 7 Oct 2020 15:53:39 +0200 Subject: [PATCH 24/71] arm64: zynqmp: Get rid of iommus/power-domains properties for SPL DT SPL DT contains only nodes which are contain u-boot,dm-pre-reloc property. iommu node is not this case that's why when DT is read DTC reports some warnings. $ dtc -I dtb -O dts dts/dt-spl.dtb >/dev/null : Warning (iommus_property): /amba/spi@ff0f0000:iommus: Could not get phandle node for (cell 0) : Warning (iommus_property): /amba/mmc@ff160000:iommus: Could not get phandle node for (cell 0) : Warning (iommus_property): /amba/mmc@ff170000:iommus: Could not get phandle node for (cell 0) SPL also has an option to remove some DT properties which are useless for SPL to make DT even smaller. Default DT properties are pinctrl-0 pinctrl-names interrupt-parent interrupts which are already removed. The patch extends this list with iommus to get rid of above warnings. Also power-domains unused properties can be removed. Signed-off-by: Michal Simek --- configs/xilinx_zynqmp_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 8ffcd3dadd4..3233f347304 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -60,6 +60,7 @@ CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y CONFIG_CMD_UBI=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_LIST="avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1" +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent interrupts iommus power-domains" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_FAT=y CONFIG_ENV_IS_IN_NAND=y From 8e4e91465273acaa435b7e154c78ddff47cbd9ff Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Thu, 6 Sep 2018 16:34:44 +0530 Subject: [PATCH 25/71] arm64: zynqmp: Add support for encryption and decryption on data blob This patch adds support for encryption and decryption on a given data blob using different key sources such as userkey(KUP), device key and PUF key. Inorder to support this a new zynqmp command(zynqmp aes) has been introduced. Command: zynqmp aes srcaddr ivaddr len aesop keysrc dstaddr [keyaddr]\n" Encrypts or decrypts blob of data at src address and puts it\n" back to dstaddr using key and iv at keyaddr and ivaddr\n" respectively. keysrc values specifies from which source key\n" has to be used, it can be User/Device/PUF key. A value of 0\n" for KUP(user key),1 for DeviceKey and 2 for PUF key. The\n" aesop value would specify the operationwhich can be 0 for\n" decrypt and 1 for encrypt(1) operation\n"; Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/include/mach/sys_proto.h | 1 + board/xilinx/zynqmp/cmds.c | 82 ++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h index f2b3ceab135..df944bde09e 100644 --- a/arch/arm/mach-zynqmp/include/mach/sys_proto.h +++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.h @@ -9,6 +9,7 @@ #define ZYNQMP_CSU_SILICON_VER_MASK 0xF #define KEY_PTR_LEN 32 +#define IV_SIZE 12 #define ZYNQMP_FPGA_BIT_AUTH_DDR 1 #define ZYNQMP_FPGA_BIT_AUTH_OCM 2 diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c index c0d28a73e45..b816af73792 100644 --- a/board/xilinx/zynqmp/cmds.c +++ b/board/xilinx/zynqmp/cmds.c @@ -9,11 +9,22 @@ #include #include #include +#include #include #include #include #include +struct aes { + u64 srcaddr; + u64 ivaddr; + u64 keyaddr; + u64 dstaddr; + u64 len; + u64 op; + u64 keysrc; +}; + static int do_zynqmp_verify_secure(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -107,6 +118,66 @@ static int do_zynqmp_mmio_write(struct cmd_tbl *cmdtp, int flag, int argc, return ret; } +static int do_zynqmp_aes(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct aes, aes, 1); + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (zynqmp_firmware_version() <= PMUFW_V1_0) { + puts("ERR: PMUFW v1.0 or less is detected\n"); + puts("ERR: Encrypt/Decrypt feature is not supported\n"); + puts("ERR: Please upgrade PMUFW\n"); + return CMD_RET_FAILURE; + } + + if (argc < cmdtp->maxargs - 1) + return CMD_RET_USAGE; + + aes->srcaddr = simple_strtoul(argv[2], NULL, 16); + aes->ivaddr = simple_strtoul(argv[3], NULL, 16); + aes->len = simple_strtoul(argv[4], NULL, 16); + aes->op = simple_strtoul(argv[5], NULL, 16); + aes->keysrc = simple_strtoul(argv[6], NULL, 16); + aes->dstaddr = simple_strtoul(argv[7], NULL, 16); + + flush_dcache_range((ulong)aes, (ulong)(aes) + + roundup(sizeof(struct aes), ARCH_DMA_MINALIGN)); + + if (aes->srcaddr && aes->ivaddr && aes->dstaddr) { + flush_dcache_range(aes->srcaddr, + (aes->srcaddr + + roundup(aes->len, ARCH_DMA_MINALIGN))); + flush_dcache_range(aes->ivaddr, + (aes->ivaddr + + roundup(IV_SIZE, ARCH_DMA_MINALIGN))); + flush_dcache_range(aes->dstaddr, + (aes->dstaddr + + roundup(aes->len, ARCH_DMA_MINALIGN))); + } + + if (aes->keysrc == 0) { + if (argc < cmdtp->maxargs) + return CMD_RET_USAGE; + + aes->keyaddr = simple_strtoul(argv[8], NULL, 16); + if (aes->keyaddr) + flush_dcache_range(aes->keyaddr, + (aes->keyaddr + + roundup(KEY_PTR_LEN, + ARCH_DMA_MINALIGN))); + } + + ret = xilinx_pm_request(PM_SECURE_AES, upper_32_bits((ulong)aes), + lower_32_bits((ulong)aes), 0, 0, ret_payload); + if (ret || ret_payload[1]) + printf("Failed: AES op status:0x%x, errcode:0x%x\n", + ret, ret_payload[1]); + + return ret; +} + #ifdef CONFIG_DEFINE_TCM_OCM_MMAP static int do_zynqmp_tcm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) @@ -153,6 +224,7 @@ static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""), U_BOOT_CMD_MKENT(mmio_read, 3, 0, do_zynqmp_mmio_read, "", ""), U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""), + U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""), #ifdef CONFIG_DEFINE_TCM_OCM_MMAP U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""), #endif @@ -196,6 +268,14 @@ static char zynqmp_help_text[] = "zynqmp mmio_read address - read from address\n" "zynqmp mmio_write address mask value - write value after masking to\n" " address\n" + "zynqmp aes srcaddr ivaddr len aesop keysrc dstaddr [keyaddr] -\n" + " Encrypts or decrypts blob of data at src address and puts it\n" + " back to dstaddr using key and iv at keyaddr and ivaddr\n" + " respectively. keysrc value specifies from which source key\n" + " has to be used, it can be User/Device/PUF key. A value of 0\n" + " for KUP(user key),1 for DeviceKey and 2 for PUF key. The\n" + " aesop value specifies the operation which can be 0 for\n" + " decrypt and 1 for encrypt operation\n" #ifdef CONFIG_DEFINE_TCM_OCM_MMAP "zynqmp tcminit mode - Initialize the TCM with zeros. TCM needs to be\n" " initialized before accessing to avoid ECC\n" @@ -208,7 +288,7 @@ static char zynqmp_help_text[] = #endif U_BOOT_CMD( - zynqmp, 5, 1, do_zynqmp, + zynqmp, 9, 1, do_zynqmp, "ZynqMP sub-system", zynqmp_help_text ) From 650d02ae77192cc78ca0c432babde65971c8107f Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 7 Jan 2019 17:05:10 +0530 Subject: [PATCH 26/71] arm64: zynqmp: Add support for RSA command This patch adds support for RSA command, performs RSA encrypt & RSA decrypt on data blob of key size. Signed-off-by: T Karthik Reddy Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/include/mach/sys_proto.h | 4 ++ board/xilinx/zynqmp/cmds.c | 72 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h index df944bde09e..d52eccc7e6e 100644 --- a/arch/arm/mach-zynqmp/include/mach/sys_proto.h +++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.h @@ -10,6 +10,10 @@ #define ZYNQMP_CSU_SILICON_VER_MASK 0xF #define KEY_PTR_LEN 32 #define IV_SIZE 12 +#define RSA_KEY_SIZE 512 +#define MODULUS_LEN 512 +#define PRIV_EXPO_LEN 512 +#define PUB_EXPO_LEN 4 #define ZYNQMP_FPGA_BIT_AUTH_DDR 1 #define ZYNQMP_FPGA_BIT_AUTH_OCM 2 diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c index b816af73792..bccba098cc4 100644 --- a/board/xilinx/zynqmp/cmds.c +++ b/board/xilinx/zynqmp/cmds.c @@ -219,12 +219,76 @@ static int do_zynqmp_pmufw(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + u64 srcaddr, mod, exp; + u32 srclen, rsaop, size, ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (argc != cmdtp->maxargs) + return CMD_RET_USAGE; + + if (zynqmp_firmware_version() <= PMUFW_V1_0) { + puts("ERR: PMUFW v1.0 or less is detected\n"); + puts("ERR: Encrypt/Decrypt feature is not supported\n"); + puts("ERR: Please upgrade PMUFW\n"); + return CMD_RET_FAILURE; + } + + srcaddr = simple_strtoul(argv[2], NULL, 16); + srclen = simple_strtoul(argv[3], NULL, 16); + if (srclen != RSA_KEY_SIZE) { + puts("ERR: srclen should be equal to 0x200(512 bytes)\n"); + return CMD_RET_USAGE; + } + + mod = simple_strtoul(argv[4], NULL, 16); + exp = simple_strtoul(argv[5], NULL, 16); + rsaop = simple_strtoul(argv[6], NULL, 16); + if (!(rsaop == 0 || rsaop == 1)) { + puts("ERR: rsaop should be either 0 or 1\n"); + return CMD_RET_USAGE; + } + + memcpy((void *)srcaddr + srclen, (void *)mod, MODULUS_LEN); + + /* + * For encryption we load public exponent (key size 4096-bits), + * for decryption we load private exponent (32-bits) + */ + if (rsaop) { + memcpy((void *)srcaddr + srclen + MODULUS_LEN, + (void *)exp, PUB_EXPO_LEN); + size = srclen + MODULUS_LEN + PUB_EXPO_LEN; + } else { + memcpy((void *)srcaddr + srclen + MODULUS_LEN, + (void *)exp, PRIV_EXPO_LEN); + size = srclen + MODULUS_LEN + PRIV_EXPO_LEN; + } + + flush_dcache_range((ulong)srcaddr, + (ulong)(srcaddr) + roundup(size, ARCH_DMA_MINALIGN)); + + ret = xilinx_pm_request(PM_SECURE_RSA, upper_32_bits((ulong)srcaddr), + lower_32_bits((ulong)srcaddr), srclen, rsaop, + ret_payload); + if (ret || ret_payload[1]) { + printf("Failed: RSA status:0x%x, errcode:0x%x\n", + ret, ret_payload[1]); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""), U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""), U_BOOT_CMD_MKENT(mmio_read, 3, 0, do_zynqmp_mmio_read, "", ""), U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""), U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""), + U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""), #ifdef CONFIG_DEFINE_TCM_OCM_MMAP U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""), #endif @@ -284,6 +348,14 @@ static char zynqmp_help_text[] = " lock(0)/split(1)\n" #endif "zynqmp pmufw address size - load PMU FW configuration object\n" + "zynqmp rsa srcaddr srclen mod exp rsaop -\n" + " Performs RSA encryption and RSA decryption on blob of data\n" + " at srcaddr and puts it back in srcaddr using modulus and\n" + " public or private exponent\n" + " srclen : must be key size(4096 bits)\n" + " exp : private key exponent for RSA decryption(4096 bits)\n" + " public key exponent for RSA encryption(32 bits)\n" + " rsaop : 0 for RSA Decryption, 1 for RSA Encryption\n" ; #endif From 0af9de9a9042fe099d81c73ac4f4a479aa12f352 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 7 Jan 2019 17:05:11 +0530 Subject: [PATCH 27/71] arm64: zynqmp: Add support for SHA3 command This patch adds support for SHA3 command. It takes data blob as input and generates 48 bytes sha3 hash value. Signed-off-by: T Karthik Reddy Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- arch/arm/mach-zynqmp/include/mach/sys_proto.h | 5 ++ board/xilinx/zynqmp/cmds.c | 63 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h index d52eccc7e6e..1c12eac715e 100644 --- a/arch/arm/mach-zynqmp/include/mach/sys_proto.h +++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.h @@ -15,6 +15,11 @@ #define PRIV_EXPO_LEN 512 #define PUB_EXPO_LEN 4 +#define ZYNQMP_SHA3_INIT 1 +#define ZYNQMP_SHA3_UPDATE 2 +#define ZYNQMP_SHA3_FINAL 4 +#define ZYNQMP_SHA3_SIZE 48 + #define ZYNQMP_FPGA_BIT_AUTH_DDR 1 #define ZYNQMP_FPGA_BIT_AUTH_OCM 2 #define ZYNQMP_FPGA_BIT_ENC_USR_KEY 3 diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c index bccba098cc4..b1dc98d076d 100644 --- a/board/xilinx/zynqmp/cmds.c +++ b/board/xilinx/zynqmp/cmds.c @@ -282,6 +282,64 @@ static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) +{ + u64 srcaddr; + u32 srclen, ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (argc != cmdtp->maxargs) + return CMD_RET_USAGE; + + if (zynqmp_firmware_version() <= PMUFW_V1_0) { + puts("ERR: PMUFW v1.0 or less is detected\n"); + puts("ERR: Encrypt/Decrypt feature is not supported\n"); + puts("ERR: Please upgrade PMUFW\n"); + return CMD_RET_FAILURE; + } + + srcaddr = simple_strtoul(argv[2], NULL, 16); + srclen = simple_strtoul(argv[3], NULL, 16); + + /* Check srcaddr or srclen != 0 */ + if (!srcaddr || !srclen) { + puts("ERR: srcaddr & srclen should not be 0\n"); + return CMD_RET_USAGE; + } + + flush_dcache_range(srcaddr, + srcaddr + roundup(srclen, ARCH_DMA_MINALIGN)); + + ret = xilinx_pm_request(PM_SECURE_SHA, 0, 0, 0, + ZYNQMP_SHA3_INIT, ret_payload); + if (ret || ret_payload[1]) { + printf("Failed: SHA INIT status:0x%x, errcode:0x%x\n", + ret, ret_payload[1]); + return CMD_RET_FAILURE; + } + + ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr), + lower_32_bits((ulong)srcaddr), + srclen, ZYNQMP_SHA3_UPDATE, ret_payload); + if (ret || ret_payload[1]) { + printf("Failed: SHA UPDATE status:0x%x, errcode:0x%x\n", + ret, ret_payload[1]); + return CMD_RET_FAILURE; + } + + ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr), + lower_32_bits((ulong)srcaddr), ZYNQMP_SHA3_SIZE, + ZYNQMP_SHA3_FINAL, ret_payload); + if (ret || ret_payload[1]) { + printf("Failed: SHA FINAL status:0x%x, errcode:0x%x\n", + ret, ret_payload[1]); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""), U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""), @@ -289,6 +347,7 @@ static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""), U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""), U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""), + U_BOOT_CMD_MKENT(sha3, 4, 0, do_zynqmp_sha3, "", ""), #ifdef CONFIG_DEFINE_TCM_OCM_MMAP U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""), #endif @@ -356,6 +415,10 @@ static char zynqmp_help_text[] = " exp : private key exponent for RSA decryption(4096 bits)\n" " public key exponent for RSA encryption(32 bits)\n" " rsaop : 0 for RSA Decryption, 1 for RSA Encryption\n" + "zynqmp sha3 srcaddr srclen -\n" + " Generates sha3 hash value for data blob at srcaddr and puts\n" + " 48 bytes hash value into srcaddr\n" + " Note: srcaddr/srclen should not be 0\n" ; #endif From 768622b1d7ceb3351f6278a528df5315bd81ec17 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 20 Oct 2020 08:29:25 +0200 Subject: [PATCH 28/71] arm64: zynqmp: Add support for saving sha3 key to different address By default 48B sha3 hash value is written to srcaddr which is not the best solution in case of that you want to use data for other operations. That's why add key_addr optional parameters which enables to write 48B sha3 hash value to specified address. Signed-off-by: Michal Simek Tested-by: Ashok Reddy Soma --- board/xilinx/zynqmp/cmds.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c index b1dc98d076d..cf63ad97fab 100644 --- a/board/xilinx/zynqmp/cmds.c +++ b/board/xilinx/zynqmp/cmds.c @@ -285,11 +285,11 @@ static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { - u64 srcaddr; + u64 srcaddr, hashaddr; u32 srclen, ret_payload[PAYLOAD_ARG_CNT]; int ret; - if (argc != cmdtp->maxargs) + if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1)) return CMD_RET_USAGE; if (zynqmp_firmware_version() <= PMUFW_V1_0) { @@ -302,6 +302,15 @@ static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag, srcaddr = simple_strtoul(argv[2], NULL, 16); srclen = simple_strtoul(argv[3], NULL, 16); + if (argc == 5) { + hashaddr = simple_strtoul(argv[4], NULL, 16); + flush_dcache_range(hashaddr, + hashaddr + roundup(ZYNQMP_SHA3_SIZE, + ARCH_DMA_MINALIGN)); + } else { + hashaddr = srcaddr; + } + /* Check srcaddr or srclen != 0 */ if (!srcaddr || !srclen) { puts("ERR: srcaddr & srclen should not be 0\n"); @@ -328,9 +337,10 @@ static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; } - ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr), - lower_32_bits((ulong)srcaddr), ZYNQMP_SHA3_SIZE, - ZYNQMP_SHA3_FINAL, ret_payload); + ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)hashaddr), + lower_32_bits((ulong)hashaddr), + ZYNQMP_SHA3_SIZE, ZYNQMP_SHA3_FINAL, + ret_payload); if (ret || ret_payload[1]) { printf("Failed: SHA FINAL status:0x%x, errcode:0x%x\n", ret, ret_payload[1]); @@ -347,7 +357,7 @@ static struct cmd_tbl cmd_zynqmp_sub[] = { U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""), U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""), U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""), - U_BOOT_CMD_MKENT(sha3, 4, 0, do_zynqmp_sha3, "", ""), + U_BOOT_CMD_MKENT(sha3, 5, 0, do_zynqmp_sha3, "", ""), #ifdef CONFIG_DEFINE_TCM_OCM_MMAP U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""), #endif @@ -415,9 +425,10 @@ static char zynqmp_help_text[] = " exp : private key exponent for RSA decryption(4096 bits)\n" " public key exponent for RSA encryption(32 bits)\n" " rsaop : 0 for RSA Decryption, 1 for RSA Encryption\n" - "zynqmp sha3 srcaddr srclen -\n" + "zynqmp sha3 srcaddr srclen [key_addr] -\n" " Generates sha3 hash value for data blob at srcaddr and puts\n" " 48 bytes hash value into srcaddr\n" + " Optional key_addr can be specified for saving sha3 hash value\n" " Note: srcaddr/srclen should not be 0\n" ; #endif From 30f47c0f1bd84b9d46a3f99eca65f666991676a5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Apr 2019 13:43:51 +0200 Subject: [PATCH 29/71] dt-bindings: arm64: versal: Add clk and power headers Add power and reset headers to be sources by Versal dtses. Signed-off-by: Michal Simek --- include/dt-bindings/clock/xlnx-versal-clk.h | 123 ++++++++++++++++++ include/dt-bindings/power/xlnx-versal-power.h | 42 ++++++ 2 files changed, 165 insertions(+) create mode 100644 include/dt-bindings/clock/xlnx-versal-clk.h create mode 100644 include/dt-bindings/power/xlnx-versal-power.h diff --git a/include/dt-bindings/clock/xlnx-versal-clk.h b/include/dt-bindings/clock/xlnx-versal-clk.h new file mode 100644 index 00000000000..264d634d226 --- /dev/null +++ b/include/dt-bindings/clock/xlnx-versal-clk.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Xilinx Inc. + * + */ + +#ifndef _DT_BINDINGS_CLK_VERSAL_H +#define _DT_BINDINGS_CLK_VERSAL_H + +#define PMC_PLL 1 +#define APU_PLL 2 +#define RPU_PLL 3 +#define CPM_PLL 4 +#define NOC_PLL 5 +#define PLL_MAX 6 +#define PMC_PRESRC 7 +#define PMC_POSTCLK 8 +#define PMC_PLL_OUT 9 +#define PPLL 10 +#define NOC_PRESRC 11 +#define NOC_POSTCLK 12 +#define NOC_PLL_OUT 13 +#define NPLL 14 +#define APU_PRESRC 15 +#define APU_POSTCLK 16 +#define APU_PLL_OUT 17 +#define APLL 18 +#define RPU_PRESRC 19 +#define RPU_POSTCLK 20 +#define RPU_PLL_OUT 21 +#define RPLL 22 +#define CPM_PRESRC 23 +#define CPM_POSTCLK 24 +#define CPM_PLL_OUT 25 +#define CPLL 26 +#define PPLL_TO_XPD 27 +#define NPLL_TO_XPD 28 +#define APLL_TO_XPD 29 +#define RPLL_TO_XPD 30 +#define EFUSE_REF 31 +#define SYSMON_REF 32 +#define IRO_SUSPEND_REF 33 +#define USB_SUSPEND 34 +#define SWITCH_TIMEOUT 35 +#define RCLK_PMC 36 +#define RCLK_LPD 37 +#define WDT 38 +#define TTC0 39 +#define TTC1 40 +#define TTC2 41 +#define TTC3 42 +#define GEM_TSU 43 +#define GEM_TSU_LB 44 +#define MUXED_IRO_DIV2 45 +#define MUXED_IRO_DIV4 46 +#define PSM_REF 47 +#define GEM0_RX 48 +#define GEM0_TX 49 +#define GEM1_RX 50 +#define GEM1_TX 51 +#define CPM_CORE_REF 52 +#define CPM_LSBUS_REF 53 +#define CPM_DBG_REF 54 +#define CPM_AUX0_REF 55 +#define CPM_AUX1_REF 56 +#define QSPI_REF 57 +#define OSPI_REF 58 +#define SDIO0_REF 59 +#define SDIO1_REF 60 +#define PMC_LSBUS_REF 61 +#define I2C_REF 62 +#define TEST_PATTERN_REF 63 +#define DFT_OSC_REF 64 +#define PMC_PL0_REF 65 +#define PMC_PL1_REF 66 +#define PMC_PL2_REF 67 +#define PMC_PL3_REF 68 +#define CFU_REF 69 +#define SPARE_REF 70 +#define NPI_REF 71 +#define HSM0_REF 72 +#define HSM1_REF 73 +#define SD_DLL_REF 74 +#define FPD_TOP_SWITCH 75 +#define FPD_LSBUS 76 +#define ACPU 77 +#define DBG_TRACE 78 +#define DBG_FPD 79 +#define LPD_TOP_SWITCH 80 +#define ADMA 81 +#define LPD_LSBUS 82 +#define CPU_R5 83 +#define CPU_R5_CORE 84 +#define CPU_R5_OCM 85 +#define CPU_R5_OCM2 86 +#define IOU_SWITCH 87 +#define GEM0_REF 88 +#define GEM1_REF 89 +#define GEM_TSU_REF 90 +#define USB0_BUS_REF 91 +#define UART0_REF 92 +#define UART1_REF 93 +#define SPI0_REF 94 +#define SPI1_REF 95 +#define CAN0_REF 96 +#define CAN1_REF 97 +#define I2C0_REF 98 +#define I2C1_REF 99 +#define DBG_LPD 100 +#define TIMESTAMP_REF 101 +#define DBG_TSTMP 102 +#define CPM_TOPSW_REF 103 +#define USB3_DUAL_REF 104 +#define OUTCLK_MAX 105 +#define REF_CLK 106 +#define PL_ALT_REF_CLK 107 +#define MUXED_IRO 108 +#define PL_EXT 109 +#define PL_LB 110 +#define MIO_50_OR_51 111 +#define MIO_24_OR_25 112 + +#endif diff --git a/include/dt-bindings/power/xlnx-versal-power.h b/include/dt-bindings/power/xlnx-versal-power.h new file mode 100644 index 00000000000..1b75175edce --- /dev/null +++ b/include/dt-bindings/power/xlnx-versal-power.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 - 2020 Xilinx, Inc. + */ + +#ifndef _DT_BINDINGS_VERSAL_POWER_H +#define _DT_BINDINGS_VERSAL_POWER_H + +#define PM_DEV_USB_0 (0x18224018U) +#define PM_DEV_GEM_0 (0x18224019U) +#define PM_DEV_GEM_1 (0x1822401aU) +#define PM_DEV_SPI_0 (0x1822401bU) +#define PM_DEV_SPI_1 (0x1822401cU) +#define PM_DEV_I2C_0 (0x1822401dU) +#define PM_DEV_I2C_1 (0x1822401eU) +#define PM_DEV_CAN_FD_0 (0x1822401fU) +#define PM_DEV_CAN_FD_1 (0x18224020U) +#define PM_DEV_UART_0 (0x18224021U) +#define PM_DEV_UART_1 (0x18224022U) +#define PM_DEV_GPIO (0x18224023U) +#define PM_DEV_TTC_0 (0x18224024U) +#define PM_DEV_TTC_1 (0x18224025U) +#define PM_DEV_TTC_2 (0x18224026U) +#define PM_DEV_TTC_3 (0x18224027U) +#define PM_DEV_SWDT_FPD (0x18224029U) +#define PM_DEV_OSPI (0x1822402aU) +#define PM_DEV_QSPI (0x1822402bU) +#define PM_DEV_GPIO_PMC (0x1822402cU) +#define PM_DEV_SDIO_0 (0x1822402eU) +#define PM_DEV_SDIO_1 (0x1822402fU) +#define PM_DEV_RTC (0x18224034U) +#define PM_DEV_ADMA_0 (0x18224035U) +#define PM_DEV_ADMA_1 (0x18224036U) +#define PM_DEV_ADMA_2 (0x18224037U) +#define PM_DEV_ADMA_3 (0x18224038U) +#define PM_DEV_ADMA_4 (0x18224039U) +#define PM_DEV_ADMA_5 (0x1822403aU) +#define PM_DEV_ADMA_6 (0x1822403bU) +#define PM_DEV_ADMA_7 (0x1822403cU) +#define PM_DEV_AI (0x18224072U) + +#endif From c94b44c64bd8661bee0eb4b39a2aac176c466147 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Thu, 24 Sep 2020 04:32:15 -0600 Subject: [PATCH 30/71] spi: xilinx_spi: remove unused local variable Remove unused variable 'count' which is causing warning while compilation. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/spi/xilinx_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index c0cfe94d443..47a5571aecd 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -214,7 +214,7 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes, struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); const unsigned char *txp = dout; unsigned char *rxp = din; - u32 reg, count; + u32 reg; u32 txbytes = bytes; u32 rxbytes = bytes; @@ -224,10 +224,10 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes, * it sets txp to the initial value for the normal operation. */ for ( ; priv->startup < 2; priv->startup++) { - count = xilinx_spi_fill_txfifo(bus, txp, txbytes); + xilinx_spi_fill_txfifo(bus, txp, txbytes); reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; writel(reg, ®s->spicr); - count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes); + xilinx_spi_read_rxfifo(bus, rxp, rxbytes); txp = din; if (priv->startup) { From 305d31885f2f35db486594d051d9aa3a4ed201c5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 28 Jul 2020 12:51:08 +0200 Subject: [PATCH 31/71] dm: core: Add support for getting node from aliases Add support for getting a node/property from aliases. The similar functionality is provided for chosen node and this implemenatation is copy of it. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- drivers/core/ofnode.c | 22 ++++++++++++++++++++++ include/dm/ofnode.h | 22 ++++++++++++++++++++++ test/dm/ofnode.c | 22 ++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 7d1b89514c7..a68076bf351 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -476,6 +476,28 @@ ofnode ofnode_get_chosen_node(const char *name) return ofnode_path(prop); } +const void *ofnode_read_aliases_prop(const char *propname, int *sizep) +{ + ofnode node; + + node = ofnode_path("/aliases"); + + return ofnode_read_prop(node, propname, sizep); +} + +ofnode ofnode_get_aliases_node(const char *name) +{ + const char *prop; + + prop = ofnode_read_aliases_prop(name, NULL); + if (!prop) + return ofnode_null(); + + debug("%s: node_path: %s\n", __func__, prop); + + return ofnode_path(prop); +} + int ofnode_get_child_count(ofnode parent) { ofnode child; diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 4b7af370560..ced7f6ffb25 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -605,6 +605,28 @@ const char *ofnode_read_chosen_string(const char *propname); */ ofnode ofnode_get_chosen_node(const char *propname); +/** + * ofnode_read_aliases_prop() - get the value of a aliases property + * + * This looks for a property within the /aliases node and returns its value + * + * @propname: Property name to look for + * @sizep: Returns size of property, or FDT_ERR_... error code if function + * returns NULL + * @return property value if found, else NULL + */ +const void *ofnode_read_aliases_prop(const char *propname, int *sizep); + +/** + * ofnode_get_aliases_node() - get a referenced node from the aliases node + * + * This looks up a named property in the aliases node and uses that as a path to + * look up a code. + * + * @return the referenced node if present, else ofnode_null() + */ +ofnode ofnode_get_aliases_node(const char *propname); + struct display_timing; /** * ofnode_decode_display_timing() - decode display timings diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 01ac3c2094c..fb1ceb13180 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -207,6 +207,28 @@ static int dm_test_ofnode_read_chosen(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_read_chosen, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +static int dm_test_ofnode_read_aliases(struct unit_test_state *uts) +{ + const void *val; + ofnode node; + int size; + + node = ofnode_get_aliases_node("eth3"); + ut_assert(ofnode_valid(node)); + ut_asserteq_str("sbe5", ofnode_get_name(node)); + + node = ofnode_get_aliases_node("unknown"); + ut_assert(!ofnode_valid(node)); + + val = ofnode_read_aliases_prop("spi0", &size); + ut_assertnonnull(val); + ut_asserteq(7, size); + ut_asserteq_str("/spi@0", (const char *)val); + + return 0; +} +DM_TEST(dm_test_ofnode_read_aliases, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + static int dm_test_ofnode_get_child_count(struct unit_test_state *uts) { ofnode node, child_node; From d61728c8e87e4a318497a4b0873e8b656aa30a08 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Aug 2020 13:01:45 +0200 Subject: [PATCH 32/71] xilinx: board: Read the whole eeprom not just offset Starts to use new way how eeproms should be referenced. Reference is done via nvmem alias nodes. When this new way is specified code itself read the eeprom and decode xilinx legacy format and fill struct xilinx_board_description. Then based on information present there board_* variables are setup. If variables are saved and content can't be changed information is just shown on console. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 205 ++++++++++++++++++++++++++++++++++- board/xilinx/common/board.h | 2 + board/xilinx/versal/board.c | 3 + board/xilinx/zynqmp/zynqmp.c | 3 + 4 files changed, 212 insertions(+), 1 deletion(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index b0f60c40a5c..0aed84546d4 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2014 - 2019 Xilinx, Inc. + * (C) Copyright 2014 - 2020 Xilinx, Inc. * Michal Simek */ @@ -11,7 +11,11 @@ #include #include #include +#include #include "board.h" +#include +#include +#include #if defined(CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET) int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) @@ -41,6 +45,180 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) } #endif +#define EEPROM_HEADER_MAGIC 0xdaaddeed +#define EEPROM_HDR_MANUFACTURER_LEN 16 +#define EEPROM_HDR_NAME_LEN 16 +#define EEPROM_HDR_REV_LEN 8 +#define EEPROM_HDR_SERIAL_LEN 20 +#define EEPROM_HDR_NO_OF_MAC_ADDR 4 +#define EEPROM_HDR_ETH_ALEN ETH_ALEN + +struct xilinx_board_description { + u32 header; + char manufacturer[EEPROM_HDR_MANUFACTURER_LEN + 1]; + char name[EEPROM_HDR_NAME_LEN + 1]; + char revision[EEPROM_HDR_REV_LEN + 1]; + char serial[EEPROM_HDR_SERIAL_LEN + 1]; + u8 mac_addr[EEPROM_HDR_NO_OF_MAC_ADDR][EEPROM_HDR_ETH_ALEN + 1]; +}; + +static struct xilinx_board_description *board_info; + +#define XILINX_I2C_DETECTION_BITS 8 + +/* Variable which stores pointer to array which stores eeprom content */ +struct xilinx_legacy_format { + char board_sn[18]; /* 0x0 */ + char unused0[14]; /* 0x12 */ + char eth_mac[6]; /* 0x20 */ + char unused1[170]; /* 0x26 */ + char board_name[11]; /* 0xd0 */ + char unused2[5]; /* 0xdc */ + char board_revision[3]; /* 0xe0 */ + char unused3[29]; /* 0xe3 */ +}; + +static void xilinx_eeprom_legacy_cleanup(char *eeprom, int size) +{ + int i; + char byte; + + for (i = 0; i < size; i++) { + byte = eeprom[i]; + + /* Remove all ffs and spaces */ + if (byte == 0xff || byte == ' ') + eeprom[i] = 0; + + /* Convert strings to lower case */ + if (byte >= 'A' && byte <= 'Z') + eeprom[i] = byte + 'a' - 'A'; + } +} + +static int xilinx_read_eeprom_legacy(struct udevice *dev, char *name, + struct xilinx_board_description *desc) +{ + int ret, size; + struct xilinx_legacy_format *eeprom_content; + bool eth_valid = false; + + size = sizeof(*eeprom_content); + + eeprom_content = calloc(1, size); + if (!eeprom_content) + return -ENOMEM; + + debug("%s: I2C EEPROM read pass data at %p\n", __func__, + eeprom_content); + + ret = dm_i2c_read(dev, 0, (uchar *)eeprom_content, size); + if (ret) { + debug("%s: I2C EEPROM read failed\n", __func__); + free(eeprom_content); + return ret; + } + + xilinx_eeprom_legacy_cleanup((char *)eeprom_content, size); + + printf("Xilinx I2C Legacy format at %s:\n", name); + printf(" Board name:\t%s\n", eeprom_content->board_name); + printf(" Board rev:\t%s\n", eeprom_content->board_revision); + printf(" Board SN:\t%s\n", eeprom_content->board_sn); + + eth_valid = is_valid_ethaddr((const u8 *)eeprom_content->eth_mac); + if (eth_valid) + printf(" Ethernet mac:\t%pM\n", eeprom_content->eth_mac); + + /* Terminating \0 chars ensure end of string */ + strcpy(desc->name, eeprom_content->board_name); + strcpy(desc->revision, eeprom_content->board_revision); + strcpy(desc->serial, eeprom_content->board_sn); + if (eth_valid) + memcpy(desc->mac_addr[0], eeprom_content->eth_mac, ETH_ALEN); + + desc->header = EEPROM_HEADER_MAGIC; + + free(eeprom_content); + + return ret; +} + +static bool xilinx_detect_legacy(u8 *buffer) +{ + int i; + char c; + + for (i = 0; i < XILINX_I2C_DETECTION_BITS; i++) { + c = buffer[i]; + + if (c < '0' || c > '9') + return false; + } + + return true; +} + +static int xilinx_read_eeprom_single(char *name, + struct xilinx_board_description *desc) +{ + int ret; + struct udevice *dev; + ofnode eeprom; + u8 buffer[XILINX_I2C_DETECTION_BITS]; + + eeprom = ofnode_get_aliases_node(name); + if (!ofnode_valid(eeprom)) + return -ENODEV; + + ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, eeprom, &dev); + if (ret) + return ret; + + ret = dm_i2c_read(dev, 0, buffer, sizeof(buffer)); + if (ret) { + debug("%s: I2C EEPROM read failed\n", __func__); + return ret; + } + + debug("%s: i2c memory detected: %s\n", __func__, name); + + if (xilinx_detect_legacy(buffer)) + return xilinx_read_eeprom_legacy(dev, name, desc); + + return -ENODEV; +} + +__maybe_unused int xilinx_read_eeprom(void) +{ + int id, highest_id; + char name_buf[8]; /* 8 bytes should be enough for nvmem+number */ + + highest_id = dev_read_alias_highest_id("nvmem"); + /* No nvmem aliases present */ + if (highest_id < 0) + return -EINVAL; + + board_info = calloc(1, sizeof(*board_info)); + if (!board_info) + return -ENOMEM; + + debug("%s: Highest ID %d, board_info %p\n", __func__, + highest_id, board_info); + + for (id = 0; id <= highest_id; id++) { + snprintf(name_buf, sizeof(name_buf), "nvmem%d", id); + + /* Ignoring return value for supporting multiple chips */ + xilinx_read_eeprom_single(name_buf, board_info); + } + + if (board_info->header != EEPROM_HEADER_MAGIC) + free(board_info); + + return 0; +} + #if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) void *board_fdt_blob_setup(void) { @@ -78,6 +256,7 @@ void *board_fdt_blob_setup(void) int board_late_init_xilinx(void) { u32 ret = 0; + int i; phys_size_t bootm_size = gd->ram_size; if (CONFIG_IS_ENABLED(ARCH_ZYNQ)) @@ -88,6 +267,30 @@ int board_late_init_xilinx(void) ret |= env_set_addr("bootm_low", (void *)gd->ram_base); ret |= env_set_addr("bootm_size", (void *)bootm_size); + if (board_info) { + if (board_info->manufacturer) + ret |= env_set("manufacturer", + board_info->manufacturer); + if (board_info->name) + ret |= env_set("board_name", board_info->name); + if (board_info->revision) + ret |= env_set("board_rev", board_info->revision); + if (board_info->serial) + ret |= env_set("board_serial", board_info->serial); + + for (i = 0; i < EEPROM_HDR_NO_OF_MAC_ADDR; i++) { + if (!board_info->mac_addr[i]) + continue; + + if (!CONFIG_IS_ENABLED(NET)) + continue; + + if (is_valid_ethaddr((const u8 *)board_info->mac_addr[i])) + ret |= eth_env_set_enetaddr_by_index("eth", i, + board_info->mac_addr[i]); + } + } + if (ret) printf("%s: Saving run time variables FAILED\n", __func__); diff --git a/board/xilinx/common/board.h b/board/xilinx/common/board.h index 180dfbca108..69e642429b8 100644 --- a/board/xilinx/common/board.h +++ b/board/xilinx/common/board.h @@ -9,4 +9,6 @@ int board_late_init_xilinx(void); +int xilinx_read_eeprom(void); + #endif /* BOARD_XILINX_COMMON_BOARD_H */ diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index a5ca4ca8740..912c1143a8a 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -36,6 +36,9 @@ int board_init(void) fpga_add(fpga_xilinx, &versalpl); #endif + if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM)) + xilinx_read_eeprom(); + return 0; } diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 362c6e3dd6f..db3f5978a92 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -324,6 +324,9 @@ int board_init(void) if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1) zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj, zynqmp_pm_cfg_obj_size); +#else + if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM)) + xilinx_read_eeprom(); #endif printf("EL Level:\tEL%d\n", current_el()); From a03b594738f8b5980fecda9946b1be31cc087e56 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Aug 2020 12:57:05 +0200 Subject: [PATCH 33/71] xilinx: board: Add support for additional card detection The most of Xilinx evaluation boards have FMC connectors which contain small eeprom for card identification. That's why read content of eeprom and record it. Also generate cardX_ variables for easier script handling. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 85 ++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 0aed84546d4..0d0c21ca3d4 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -62,7 +62,8 @@ struct xilinx_board_description { u8 mac_addr[EEPROM_HDR_NO_OF_MAC_ADDR][EEPROM_HDR_ETH_ALEN + 1]; }; -static struct xilinx_board_description *board_info; +static int highest_id = -1; +static struct xilinx_board_description **board_info; #define XILINX_I2C_DETECTION_BITS 8 @@ -191,15 +192,16 @@ static int xilinx_read_eeprom_single(char *name, __maybe_unused int xilinx_read_eeprom(void) { - int id, highest_id; + int id, ret; char name_buf[8]; /* 8 bytes should be enough for nvmem+number */ + struct xilinx_board_description *desc; highest_id = dev_read_alias_highest_id("nvmem"); /* No nvmem aliases present */ if (highest_id < 0) return -EINVAL; - board_info = calloc(1, sizeof(*board_info)); + board_info = calloc(1, sizeof(desc) * highest_id); if (!board_info) return -ENOMEM; @@ -209,12 +211,28 @@ __maybe_unused int xilinx_read_eeprom(void) for (id = 0; id <= highest_id; id++) { snprintf(name_buf, sizeof(name_buf), "nvmem%d", id); + /* Alloc structure */ + desc = board_info[id]; + if (!desc) { + desc = calloc(1, sizeof(*desc)); + if (!desc) + return -ENOMEM; + + board_info[id] = desc; + } + /* Ignoring return value for supporting multiple chips */ - xilinx_read_eeprom_single(name_buf, board_info); + ret = xilinx_read_eeprom_single(name_buf, desc); + if (ret) { + free(desc); + board_info[id] = NULL; + } } - if (board_info->header != EEPROM_HEADER_MAGIC) - free(board_info); + /* + * Consider to clean board_info structure when board/cards are not + * detected. + */ return 0; } @@ -253,10 +271,23 @@ void *board_fdt_blob_setup(void) } #endif +static int env_set_by_index(const char *name, int index, char *data) +{ + char var[32]; + + if (!index) + sprintf(var, "board_%s", name); + else + sprintf(var, "card%d_%s", index, name); + + return env_set(var, data); +} + int board_late_init_xilinx(void) { u32 ret = 0; - int i; + int i, id, macid = 0; + struct xilinx_board_description *desc; phys_size_t bootm_size = gd->ram_size; if (CONFIG_IS_ENABLED(ARCH_ZYNQ)) @@ -267,27 +298,33 @@ int board_late_init_xilinx(void) ret |= env_set_addr("bootm_low", (void *)gd->ram_base); ret |= env_set_addr("bootm_size", (void *)bootm_size); - if (board_info) { - if (board_info->manufacturer) - ret |= env_set("manufacturer", - board_info->manufacturer); - if (board_info->name) - ret |= env_set("board_name", board_info->name); - if (board_info->revision) - ret |= env_set("board_rev", board_info->revision); - if (board_info->serial) - ret |= env_set("board_serial", board_info->serial); - - for (i = 0; i < EEPROM_HDR_NO_OF_MAC_ADDR; i++) { - if (!board_info->mac_addr[i]) - continue; + for (id = 0; id <= highest_id; id++) { + desc = board_info[id]; + if (desc && desc->header == EEPROM_HEADER_MAGIC) { + if (desc->manufacturer[0]) + ret |= env_set_by_index("manufacturer", id, + desc->manufacturer); + if (desc->name[0]) + ret |= env_set_by_index("name", id, + desc->name); + if (desc->revision[0]) + ret |= env_set_by_index("rev", id, + desc->revision); + if (desc->serial[0]) + ret |= env_set_by_index("serial", id, + desc->serial); if (!CONFIG_IS_ENABLED(NET)) continue; - if (is_valid_ethaddr((const u8 *)board_info->mac_addr[i])) - ret |= eth_env_set_enetaddr_by_index("eth", i, - board_info->mac_addr[i]); + for (i = 0; i < EEPROM_HDR_NO_OF_MAC_ADDR; i++) { + if (!desc->mac_addr[i]) + continue; + + if (is_valid_ethaddr((const u8 *)desc->mac_addr[i])) + ret |= eth_env_set_enetaddr_by_index("eth", + macid++, desc->mac_addr[i]); + } } } From 6c9662df49abeefffe9987cb51f47c41b8457d10 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 13 Oct 2020 15:00:24 +0200 Subject: [PATCH 34/71] serial: pl01x: Add error value checking There also a need to check return values to make sure that clocks were enabled and setup properly. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- drivers/serial/serial_pl01x.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 2772c25f1d2..d9e35c6a2b4 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "serial_pl01x_internal.h" @@ -362,8 +363,18 @@ int pl01x_serial_ofdata_to_platdata(struct udevice *dev) plat->clock = dev_read_u32_default(dev, "clock", CONFIG_PL011_CLOCK); ret = clk_get_by_index(dev, 0, &clk); if (!ret) { - clk_enable(&clk); + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + plat->clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(plat->clock)) { + dev_err(dev, "failed to get rate\n"); + return plat->clock; + } + debug("%s: CLK %d\n", __func__, plat->clock); } plat->type = dev_get_driver_data(dev); plat->skip_init = dev_read_bool(dev, "skip-init"); From b79a7030c31d4fdc3d37e41391a8272bc7f0f21a Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 4 Feb 2020 05:47:44 -0700 Subject: [PATCH 35/71] spi: zynq_spi: Use clk subsystem to get reference spi clk Remove fixed reference clk used by plat->frequency and use clk subsystem to get reference clk. As per spi dt bindings "spi-max-frequency" property should be used by the slave devices. This property is read by spi-uclass driver for the slave device. So avoid reading above property from the platform driver. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/spi/zynq_spi.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 9923931e36e..cb911c34f68 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -8,10 +8,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -79,17 +81,10 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus) plat->regs = dev_read_addr_ptr(bus); - /* FIXME: Use 250MHz as a suitable default */ - plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", - 250000000); plat->deactivate_delay_us = fdtdec_get_int(blob, node, "spi-deactivate-delay", 0); plat->activate_delay_us = fdtdec_get_int(blob, node, "spi-activate-delay", 0); - plat->speed_hz = plat->frequency / 2; - - debug("%s: regs=%p max-frequency=%d\n", __func__, - plat->regs, plat->frequency); return 0; } @@ -128,13 +123,39 @@ static int zynq_spi_probe(struct udevice *bus) { struct zynq_spi_platdata *plat = dev_get_platdata(bus); struct zynq_spi_priv *priv = dev_get_priv(bus); + struct clk clk; + unsigned long clock; + int ret; priv->regs = plat->regs; priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH; + ret = clk_get_by_name(bus, "ref_clk", &clk); + if (ret < 0) { + dev_err(bus, "failed to get clock\n"); + return ret; + } + + clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(clock)) { + dev_err(bus, "failed to get rate\n"); + return clock; + } + + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS) { + dev_err(bus, "failed to enable clock\n"); + return ret; + } + /* init the zynq spi hw */ zynq_spi_init_hw(priv); + plat->frequency = clock; + plat->speed_hz = plat->frequency / 2; + + debug("%s: max-frequency=%d\n", __func__, plat->speed_hz); + return 0; } From ea836be1e7b9e5a88637a87cf7219f96761d1b70 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 4 Feb 2020 05:47:45 -0700 Subject: [PATCH 36/71] spi: zynq_qspi: Use clk subsystem to get reference qspi clk Remove fixed reference clk used by plat->frequency and use clk subsystem to get reference clk. As per spi dt bindings "spi-max-frequency" property should be used by the slave devices. This property is read by spi-uclass driver for the slave device. So avoid reading above property from the platform driver. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/spi/zynq_qspi.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index 3f39ef05f2d..4219a35c840 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -6,8 +6,10 @@ * Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only) */ +#include #include #include +#include #include #include #include @@ -105,14 +107,6 @@ static int zynq_qspi_ofdata_to_platdata(struct udevice *bus) plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob, node, "reg"); - /* FIXME: Use 166MHz as a suitable default */ - plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", - 166666666); - plat->speed_hz = plat->frequency / 2; - - debug("%s: regs=%p max-frequency=%d\n", __func__, - plat->regs, plat->frequency); - return 0; } @@ -159,13 +153,39 @@ static int zynq_qspi_probe(struct udevice *bus) { struct zynq_qspi_platdata *plat = dev_get_platdata(bus); struct zynq_qspi_priv *priv = dev_get_priv(bus); + struct clk clk; + unsigned long clock; + int ret; priv->regs = plat->regs; priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH; + ret = clk_get_by_name(bus, "ref_clk", &clk); + if (ret < 0) { + dev_err(bus, "failed to get clock\n"); + return ret; + } + + clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(clock)) { + dev_err(bus, "failed to get rate\n"); + return clock; + } + + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS) { + dev_err(bus, "failed to enable clock\n"); + return ret; + } + /* init the zynq spi hw */ zynq_qspi_init_hw(priv); + plat->frequency = clock; + plat->speed_hz = plat->frequency / 2; + + debug("%s: max-frequency=%d\n", __func__, plat->speed_hz); + return 0; } From caa7fc2c57750f323d53aef38c7ee2e01898c4ba Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 3 Sep 2020 11:24:28 +0200 Subject: [PATCH 37/71] spl: Use standard FIT entries SPL is creating fit-images DT node when loadables are recorded in selected configuration. Entries which are created are using entry-point and load-addr property names. But there shouldn't be a need to use non standard properties because entry/load are standard FIT properties. But using standard FIT properties enables option to use generic FIT functions to descrease SPL size. Here is result for ZynqMP virt configuration: xilinx_zynqmp_virt: spl/u-boot-spl:all -82 spl/u-boot-spl:rodata -22 spl/u-boot-spl:text -60 The patch causes change in run time fit image record. Before: fit-images { uboot { os = "u-boot"; type = "firmware"; size = <0xfd520>; entry-point = <0x8000000>; load-addr = <0x8000000>; }; }; After: fit-images { uboot { os = "u-boot"; type = "firmware"; size = <0xfd520>; entry = <0x8000000>; load = <0x8000000>; }; }; Replacing calling fdt_getprop_u32() by fit_image_get_entry/load() also enables support for reading entry/load properties recorded in 64bit format. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- common/fdt_support.c | 4 +- common/spl/spl_atf.c | 7 ++-- common/spl/spl_fit.c | 8 +++- common/spl/spl_opensbi.c | 8 ++-- doc/uImage.FIT/howto.txt | 84 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 11 deletions(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index a565b470f81..b8a8768a214 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -616,9 +616,9 @@ int fdt_record_loadable(void *blob, u32 index, const char *name, * However, spl_fit.c is not 64bit safe either: i.e. we should not * have an issue here. */ - fdt_setprop_u32(blob, node, "load-addr", load_addr); + fdt_setprop_u32(blob, node, "load", load_addr); if (entry_point != -1) - fdt_setprop_u32(blob, node, "entry-point", entry_point); + fdt_setprop_u32(blob, node, "entry", entry_point); fdt_setprop_u32(blob, node, "size", size); if (type) fdt_setprop_string(blob, node, "type", type); diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index b54b4f0d22e..9bd25f6b32c 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -132,10 +132,11 @@ static int spl_fit_images_find(void *blob, int os) uintptr_t spl_fit_images_get_entry(void *blob, int node) { ulong val; + int ret; - val = fdt_getprop_u32(blob, node, "entry-point"); - if (val == FDT_ERROR) - val = fdt_getprop_u32(blob, node, "load-addr"); + ret = fit_image_get_entry(blob, node, &val); + if (ret) + ret = fit_image_get_load(blob, node, &val); debug("%s: entry point 0x%lx\n", __func__, val); return val; diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index fd6086a65c3..f5109e86d14 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -332,9 +332,15 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, } if (image_info) { + ulong entry_point; + image_info->load_addr = load_addr; image_info->size = length; - image_info->entry_point = fdt_getprop_u32(fit, node, "entry"); + + if (!fit_image_get_entry(fit, node, &entry_point)) + image_info->entry_point = entry_point; + else + image_info->entry_point = FDT_ERROR; } return 0; diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c index 14f335f75f0..41e0746bb01 100644 --- a/common/spl/spl_opensbi.c +++ b/common/spl/spl_opensbi.c @@ -61,11 +61,9 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image) } /* Get U-Boot entry point */ - uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node, - "entry-point"); - if (uboot_entry == FDT_ERROR) - uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node, - "load-addr"); + ret = fit_image_get_entry(spl_image->fdt_addr, uboot_node, &uboot_entry); + if (ret) + ret = fit_image_get_load(spl_image->fdt_addr, uboot_node, &uboot_entry); /* Prepare obensbi_info object */ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE; diff --git a/doc/uImage.FIT/howto.txt b/doc/uImage.FIT/howto.txt index 8592719685e..019dda24a08 100644 --- a/doc/uImage.FIT/howto.txt +++ b/doc/uImage.FIT/howto.txt @@ -66,6 +66,90 @@ can point to a script which generates this image source file during the build process. It gets passed a list of device tree files (taken from the CONFIG_OF_LIST symbol). +The SPL also records to a DT all additional images (called loadables) which are +loaded. The information about loadables locations is passed via the DT node with +fit-images name. + +Loadables Example +----------------- +Consider the following case for an ARM64 platform where U-Boot runs in EL2 +started by ATF where SPL is loading U-Boot (as loadables) and ATF (as firmware). + +/dts-v1/; + +/ { + description = "Configuration to load ATF before U-Boot"; + + images { + uboot { + description = "U-Boot (64-bit)"; + data = /incbin/("u-boot-nodtb.bin"); + type = "firmware"; + os = "u-boot"; + arch = "arm64"; + compression = "none"; + load = <0x8 0x8000000>; + entry = <0x8 0x8000000>; + hash { + algo = "md5"; + }; + }; + atf { + description = "ARM Trusted Firmware"; + data = /incbin/("bl31.bin"); + type = "firmware"; + os = "arm-trusted-firmware"; + arch = "arm64"; + compression = "none"; + load = <0xfffea000>; + entry = <0xfffea000>; + hash { + algo = "md5"; + }; + }; + fdt_1 { + description = "zynqmp-zcu102-revA"; + data = /incbin/("arch/arm/dts/zynqmp-zcu102-revA.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x100000>; + hash { + algo = "md5"; + }; + }; + }; + configurations { + default = "config_1"; + + config_1 { + description = "zynqmp-zcu102-revA"; + firmware = "atf"; + loadables = "uboot"; + fdt = "fdt_1"; + }; + }; +}; + +In this case the SPL records via fit-images DT node the information about +loadables U-Boot image. + +ZynqMP> fdt addr $fdtcontroladdr +ZynqMP> fdt print /fit-images +fit-images { + uboot { + os = "u-boot"; + type = "firmware"; + size = <0x001017c8>; + entry = <0x00000008 0x08000000>; + load = <0x00000008 0x08000000>; + }; +}; + +As you can see entry and load properties are 64bit wide to support loading +images above 4GB (in past entry and load properties where just 32bit). + + Example 1 -- old-style (non-FDT) kernel booting ----------------------------------------------- From 13d1ca8742ab714d4238f7b1598931bb6aaa1ea4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 3 Sep 2020 12:44:51 +0200 Subject: [PATCH 38/71] spl: fdt: Record load/entry fit-images entries in 64bit format The commit 9f45aeb93727 ("spl: fit: implement fdt_record_loadable") which introduced fdt_record_loadable() state there spl_fit.c is not 64bit safe. Based on my tests on Xilinx ZynqMP zcu102 platform there shouldn't be a problem to record these addresses in 64bit format. The patch adds support for systems which need to load images above 4GB. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- common/fdt_support.c | 9 ++------- common/image-fit.c | 11 ++++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index b8a8768a214..5ae75df3c65 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -611,14 +611,9 @@ int fdt_record_loadable(void *blob, u32 index, const char *name, if (node < 0) return node; - /* - * We record these as 32bit entities, possibly truncating addresses. - * However, spl_fit.c is not 64bit safe either: i.e. we should not - * have an issue here. - */ - fdt_setprop_u32(blob, node, "load", load_addr); + fdt_setprop_u64(blob, node, "load", load_addr); if (entry_point != -1) - fdt_setprop_u32(blob, node, "entry", entry_point); + fdt_setprop_u64(blob, node, "entry", entry_point); fdt_setprop_u32(blob, node, "size", size); if (type) fdt_setprop_string(blob, node, "type", type); diff --git a/common/image-fit.c b/common/image-fit.c index d54eff9033c..c82d4d8015f 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -791,17 +791,18 @@ static int fit_image_get_address(const void *fit, int noffset, char *name, return -1; } - if (len > sizeof(ulong)) { - printf("Unsupported %s address size\n", name); - return -1; - } - cell_len = len >> 2; /* Use load64 to avoid compiling warning for 32-bit target */ while (cell_len--) { load64 = (load64 << 32) | uimage_to_cpu(*cell); cell++; } + + if (len > sizeof(ulong) && (uint32_t)(load64 >> 32)) { + printf("Unsupported %s address size\n", name); + return -1; + } + *load = (ulong)load64; return 0; From 83594f3c01c1afb765f8e2b08feea10f24c01d7f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 14 Oct 2020 17:08:14 +0200 Subject: [PATCH 39/71] xilinx: common: Move ZYNQ_GEM_I2C_MAC_OFFSET to board Kconfig There is no reason to have ZYNQ specific Kconfig macro in generic location to be visible for all other SoCs. That's why move it to Xilinx common location to be visible only for us. Also introduce new bool entry ZYNQ_MAC_IN_EEPROM to have also an option to disable it or enable. This has connection to code which is reading the whole content of i2c and also work with the rest of date not just with MAC address. Signed-off-by: Michal Simek --- board/xilinx/Kconfig | 17 +++++++++++++++++ ...azedev_cc_v1_0_ultrazedev_som_v1_0_defconfig | 3 ++- configs/syzygy_hub_defconfig | 3 ++- configs/xilinx_zynqmp_virt_defconfig | 3 ++- drivers/misc/Kconfig | 7 ------- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/board/xilinx/Kconfig b/board/xilinx/Kconfig index c80d0a88128..01d7f8eac1c 100644 --- a/board/xilinx/Kconfig +++ b/board/xilinx/Kconfig @@ -56,3 +56,20 @@ config BOOT_SCRIPT_OFFSET default 0x7F80000 if ARCH_VERSAL help Specifies distro boot script offset in NAND/NOR flash. + +config ZYNQ_MAC_IN_EEPROM + bool "Reading MAC address from EEPROM" + help + Enable this option if your MAC address is saved in eeprom and + xlnx,eeprom DT property in chosen node points to it. + +if ZYNQ_MAC_IN_EEPROM + +config ZYNQ_GEM_I2C_MAC_OFFSET + hex "Set the I2C MAC offset" + default 0x0 + depends on DM_I2C + help + Set the MAC offset for i2C. + +endif diff --git a/configs/avnet_ultrazedev_cc_v1_0_ultrazedev_som_v1_0_defconfig b/configs/avnet_ultrazedev_cc_v1_0_ultrazedev_som_v1_0_defconfig index 25282ba428a..2426179d442 100644 --- a/configs/avnet_ultrazedev_cc_v1_0_ultrazedev_som_v1_0_defconfig +++ b/configs/avnet_ultrazedev_cc_v1_0_ultrazedev_som_v1_0_defconfig @@ -8,6 +8,8 @@ CONFIG_DEBUG_UART_BASE=0xff000000 CONFIG_DEBUG_UART_CLOCK=100000000 CONFIG_SPL_SPI_FLASH_SUPPORT=y CONFIG_SPL_SPI_SUPPORT=y +CONFIG_ZYNQ_MAC_IN_EEPROM=y +CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0xfa CONFIG_DEFAULT_DEVICE_TREE="avnet-ultrazedev-cc-v1.0-ultrazedev-som-v1.0" CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y @@ -42,7 +44,6 @@ CONFIG_I2C_MUX=y CONFIG_I2C_MUX_PCA954x=y CONFIG_MISC=y CONFIG_I2C_EEPROM=y -CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0xfa CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_SPI_FLASH_BAR=y diff --git a/configs/syzygy_hub_defconfig b/configs/syzygy_hub_defconfig index 8f6900661ac..276c476baeb 100644 --- a/configs/syzygy_hub_defconfig +++ b/configs/syzygy_hub_defconfig @@ -9,6 +9,8 @@ CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_SPL=y CONFIG_DEBUG_UART_BASE=0xe0000000 CONFIG_DEBUG_UART_CLOCK=50000000 +CONFIG_ZYNQ_MAC_IN_EEPROM=y +CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0xFA CONFIG_DEFAULT_DEVICE_TREE="zynq-syzygy-hub" CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y @@ -40,7 +42,6 @@ CONFIG_FPGA_XILINX=y CONFIG_FPGA_ZYNQPL=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_CADENCE=y -CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0xFA CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_PHY_MARVELL=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 3233f347304..01b2f18a057 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -7,6 +7,8 @@ CONFIG_DM_GPIO=y CONFIG_SPL=y CONFIG_SPL_SPI_FLASH_SUPPORT=y CONFIG_SPL_SPI_SUPPORT=y +CONFIG_ZYNQ_MAC_IN_EEPROM=y +CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0x20 CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu100-revC" CONFIG_AHCI=y @@ -91,7 +93,6 @@ CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_MISC=y CONFIG_I2C_EEPROM=y -CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0x20 CONFIG_SYS_I2C_EEPROM_ADDR=0x0 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW=0x0 CONFIG_SUPPORT_EMMC_BOOT=y diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b67e906a76b..29432ae7eb4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -376,13 +376,6 @@ config SPL_I2C_EEPROM This option is an SPL-variant of the I2C_EEPROM option. See the help of I2C_EEPROM for details. -config ZYNQ_GEM_I2C_MAC_OFFSET - hex "Set the I2C MAC offset" - default 0x0 - depends on DM_I2C - help - Set the MAC offset for i2C. - if I2C_EEPROM config SYS_I2C_EEPROM_ADDR From 7c553ac0ffef5a6bc2f524d11f00338ef59ba7cb Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 11:14:20 +0200 Subject: [PATCH 40/71] xilinx: common: Protect board_late_init_xilinx() Do not call board_late_init_xilinx() when BOARD_LATE_INIT is not enabled. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 0d0c21ca3d4..410b4cd998e 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -271,6 +271,7 @@ void *board_fdt_blob_setup(void) } #endif +#if defined(CONFIG_BOARD_LATE_INIT) static int env_set_by_index(const char *name, int index, char *data) { char var[32]; @@ -333,3 +334,4 @@ int board_late_init_xilinx(void) return 0; } +#endif From 0b88e4516dc1dbba7ba041756315843a28a6bf74 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Oct 2020 07:51:04 +0200 Subject: [PATCH 41/71] microblaze: Enable i2c DM by default Microblaze has been converted fully to DM that's why enabled DM for I2C too. Signed-off-by: Michal Simek --- configs/microblaze-generic_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/microblaze-generic_defconfig b/configs/microblaze-generic_defconfig index df79206ac27..7cf736954b4 100644 --- a/configs/microblaze-generic_defconfig +++ b/configs/microblaze-generic_defconfig @@ -43,6 +43,7 @@ CONFIG_NET_RANDOM_ETHADDR=y CONFIG_NETCONSOLE=y CONFIG_SPL_DM=y CONFIG_XILINX_GPIO=y +CONFIG_DM_I2C=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_MTD=y From 3e315f31cc74e897aebb180aa43d572f5d289949 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 20 Oct 2020 12:05:14 +0200 Subject: [PATCH 42/71] xilinx: common: Add Makefile to common folder There is no need to reference files in common folder back. Simply adding Makefile to this folder does the job because this "common" location is already wired in main Makefile. Signed-off-by: Michal Simek --- board/xilinx/common/Makefile | 7 +++++++ board/xilinx/versal/Makefile | 1 - board/xilinx/zynq/Makefile | 1 - board/xilinx/zynqmp/Makefile | 1 - 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 board/xilinx/common/Makefile diff --git a/board/xilinx/common/Makefile b/board/xilinx/common/Makefile new file mode 100644 index 00000000000..3600da464b8 --- /dev/null +++ b/board/xilinx/common/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# (C) Copyright 2020 Xilinx, Inc. +# Michal Simek +# + +obj-y += board.o diff --git a/board/xilinx/versal/Makefile b/board/xilinx/versal/Makefile index 90e03431540..4a46ca02d70 100644 --- a/board/xilinx/versal/Makefile +++ b/board/xilinx/versal/Makefile @@ -6,4 +6,3 @@ obj-y := board.o obj-$(CONFIG_CMD_VERSAL) += cmds.o -obj-y += ../common/board.o diff --git a/board/xilinx/zynq/Makefile b/board/xilinx/zynq/Makefile index 096a7aceb93..85661715891 100644 --- a/board/xilinx/zynq/Makefile +++ b/board/xilinx/zynq/Makefile @@ -4,7 +4,6 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-y := board.o -obj-y += ../common/board.o ifneq ($(CONFIG_XILINX_PS_INIT_FILE),"") PS_INIT_FILE := $(shell cd $(srctree); readlink -f $(CONFIG_XILINX_PS_INIT_FILE)) diff --git a/board/xilinx/zynqmp/Makefile b/board/xilinx/zynqmp/Makefile index 398c6aaa452..7d8277ca400 100644 --- a/board/xilinx/zynqmp/Makefile +++ b/board/xilinx/zynqmp/Makefile @@ -4,7 +4,6 @@ # Michal Simek obj-y := zynqmp.o -obj-y += ../common/board.o ifneq ($(CONFIG_XILINX_PS_INIT_FILE),"") PS_INIT_FILE := $(shell cd $(srctree); readlink -f $(CONFIG_XILINX_PS_INIT_FILE)) From f1b97b5f18a8e03c534cb7dbde22cd23d5d753f7 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Wed, 10 Apr 2019 12:38:10 +0530 Subject: [PATCH 43/71] xilinx: cmd: Add support for FRU commands This patch adds support for fru commands "fru capture" and "fru display". The fru capture parses the FRU table present at an address and stores in a structure for later use. The fru display prints the content of captured structured in a readable format. As of now, it supports only common header and board area of FRU. Also, it supports only English language code and ASCII8/BINARY formats. fru_data variable is placed to data section because fru parser can be called very early before bss is initialized. And also information needs to be shared that's why it is exported via header. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- board/xilinx/Kconfig | 8 + board/xilinx/common/Makefile | 3 + board/xilinx/common/fru.c | 73 +++++++++ board/xilinx/common/fru.h | 66 ++++++++ board/xilinx/common/fru_ops.c | 263 ++++++++++++++++++++++++++++++++ board/xilinx/zynqmp/MAINTAINERS | 1 + 6 files changed, 414 insertions(+) create mode 100644 board/xilinx/common/fru.c create mode 100644 board/xilinx/common/fru.h create mode 100644 board/xilinx/common/fru_ops.c diff --git a/board/xilinx/Kconfig b/board/xilinx/Kconfig index 01d7f8eac1c..51f6d2bac8a 100644 --- a/board/xilinx/Kconfig +++ b/board/xilinx/Kconfig @@ -73,3 +73,11 @@ config ZYNQ_GEM_I2C_MAC_OFFSET Set the MAC offset for i2C. endif + +config CMD_FRU + bool "FRU information for product" + help + This option enables FRU commands to capture and display FRU + information present in the device. The FRU Information is used + to primarily to provide "inventory" information about the boards + that the FRU Information Device is located on. diff --git a/board/xilinx/common/Makefile b/board/xilinx/common/Makefile index 3600da464b8..212028478c0 100644 --- a/board/xilinx/common/Makefile +++ b/board/xilinx/common/Makefile @@ -5,3 +5,6 @@ # obj-y += board.o +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_CMD_FRU) += fru.o fru_ops.o +endif diff --git a/board/xilinx/common/fru.c b/board/xilinx/common/fru.c new file mode 100644 index 00000000000..0ab9f2a78bd --- /dev/null +++ b/board/xilinx/common/fru.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2019 - 2020 Xilinx, Inc. + */ + +#include +#include +#include +#include + +#include "fru.h" + +static int do_fru_capture(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + unsigned long addr; + char *endp; + + if (argc < cmdtp->maxargs) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[2], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + return -1; + + return fru_capture(addr); +} + +static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + fru_display(1); + return CMD_RET_SUCCESS; +} + +static struct cmd_tbl cmd_fru_sub[] = { + U_BOOT_CMD_MKENT(capture, 3, 0, do_fru_capture, "", ""), + U_BOOT_CMD_MKENT(display, 2, 0, do_fru_display, "", ""), +}; + +static int do_fru(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *c; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + c = find_cmd_tbl(argv[1], &cmd_fru_sub[0], + ARRAY_SIZE(cmd_fru_sub)); + if (!c) + return CMD_RET_USAGE; + + ret = c->cmd(c, flag, argc, argv); + + return cmd_process_error(c, ret); +} + +/***************************************************/ +#ifdef CONFIG_SYS_LONGHELP +static char fru_help_text[] = + "capture - Parse and capture FRU table present at address.\n" + "fru display - Displays content of FRU table that was captured using\n" + " fru capture command\n" + ; +#endif + +U_BOOT_CMD( + fru, 3, 1, do_fru, + "FRU table info", + fru_help_text +) diff --git a/board/xilinx/common/fru.h b/board/xilinx/common/fru.h new file mode 100644 index 00000000000..a0413cf7f69 --- /dev/null +++ b/board/xilinx/common/fru.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Xilinx, Inc. + * Siva Durga Prasad Paladugu + */ + +#ifndef __FRU_H +#define __FRU_H + +struct fru_common_hdr { + u8 version; + u8 off_internal; + u8 off_chassis; + u8 off_board; + u8 off_product; + u8 off_multirec; + u8 pad; + u8 crc; +}; + +#define FRU_BOARD_MAX_LEN 32 + +struct fru_board_data { + u8 ver; + u8 len; + u8 lang_code; + u8 time[3]; + u8 manufacturer_type_len; + u8 manufacturer_name[FRU_BOARD_MAX_LEN]; + u8 product_name_type_len; + u8 product_name[FRU_BOARD_MAX_LEN]; + u8 serial_number_type_len; + u8 serial_number[FRU_BOARD_MAX_LEN]; + u8 part_number_type_len; + u8 part_number[FRU_BOARD_MAX_LEN]; + u8 file_id_type_len; + u8 file_id[FRU_BOARD_MAX_LEN]; +}; + +struct fru_table { + bool captured; + struct fru_common_hdr hdr; + struct fru_board_data brd; +}; + +#define FRU_TYPELEN_CODE_MASK 0xC0 +#define FRU_TYPELEN_LEN_MASK 0x3F +#define FRU_COMMON_HDR_VER_MASK 0xF +#define FRU_COMMON_HDR_LEN_MULTIPLIER 8 +#define FRU_LANG_CODE_ENGLISH 0 +#define FRU_LANG_CODE_ENGLISH_1 25 +#define FRU_TYPELEN_EOF 0xC1 + +/* This should be minimum of fields */ +#define FRU_BOARD_AREA_TOTAL_FIELDS 5 +#define FRU_TYPELEN_TYPE_SHIFT 6 +#define FRU_TYPELEN_TYPE_BINARY 0 +#define FRU_TYPELEN_TYPE_ASCII8 3 + +int fru_display(int verbose); +int fru_capture(unsigned long addr); +u8 fru_checksum(u8 *addr, u8 len); + +extern struct fru_table fru_data; + +#endif /* FRU_H */ diff --git a/board/xilinx/common/fru_ops.c b/board/xilinx/common/fru_ops.c new file mode 100644 index 00000000000..491e92a7afb --- /dev/null +++ b/board/xilinx/common/fru_ops.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2019 - 2020 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fru.h" + +struct fru_table fru_data __section(.data); + +static u16 fru_cal_area_len(u8 len) +{ + return len * FRU_COMMON_HDR_LEN_MULTIPLIER; +} + +static u8 fru_version(u8 ver) +{ + return ver & FRU_COMMON_HDR_VER_MASK; +} + +static int fru_check_language(u8 code) +{ + if (code != FRU_LANG_CODE_ENGLISH && code != FRU_LANG_CODE_ENGLISH_1) { + printf("FRU_ERROR: Only English Language is supported\n"); + return -EINVAL; + } + + return 0; +} + +u8 fru_checksum(u8 *addr, u8 len) +{ + u8 checksum = 0; + + while (len--) { + checksum += *addr; + addr++; + } + + return checksum; +} + +static int fru_check_type_len(u8 type_len, u8 language, u8 *type) +{ + int len; + + if (type_len == FRU_TYPELEN_EOF) + return -EINVAL; + + *type = (type_len & FRU_TYPELEN_CODE_MASK) >> FRU_TYPELEN_TYPE_SHIFT; + + len = type_len & FRU_TYPELEN_LEN_MASK; + + return len; +} + +static int fru_parse_board(unsigned long addr) +{ + u8 i, type; + int len; + u8 *data, *term; + + memcpy(&fru_data.brd.ver, (void *)addr, 6); + addr += 6; + data = (u8 *)&fru_data.brd.manufacturer_type_len; + + for (i = 0; ; i++, data += FRU_BOARD_MAX_LEN) { + len = fru_check_type_len(*(u8 *)addr, fru_data.brd.lang_code, + &type); + /* + * Stop cature if it end of fields + */ + if (len == -EINVAL) + break; + + /* This record type/len field */ + *data++ = *(u8 *)addr; + + /* Add offset to match data */ + addr += 1; + + /* If len is 0 it means empty field that's why skip writing */ + if (!len) + continue; + + /* Record data field */ + memcpy(data, (u8 *)addr, len); + term = data + (u8)len; + *term = 0; + addr += len; + } + + if (i < FRU_BOARD_AREA_TOTAL_FIELDS) { + printf("Board area require minimum %d fields\n", + FRU_BOARD_AREA_TOTAL_FIELDS); + return -EINVAL; + } + + return 0; +} + +int fru_capture(unsigned long addr) +{ + struct fru_common_hdr *hdr; + u8 checksum = 0; + + checksum = fru_checksum((u8 *)addr, sizeof(struct fru_common_hdr)); + if (checksum) { + printf("%s Common header CRC error\n", __func__); + return -EINVAL; + } + + hdr = (struct fru_common_hdr *)addr; + + memcpy((void *)&fru_data.hdr, (void *)hdr, + sizeof(struct fru_common_hdr)); + + fru_data.captured = true; + + if (hdr->off_board) { + addr += fru_cal_area_len(hdr->off_board); + fru_parse_board(addr); + } + + env_set_hex("fru_addr", addr); + + return 0; +} + +static int fru_display_board(struct fru_board_data *brd, int verbose) +{ + u32 time = 0; + u8 type; + int len; + u8 *data; + static const char * const typecode[] = { + "Binary/Unspecified", + "BCD plus", + "6-bit ASCII", + "8-bit ASCII", + "2-byte UNICODE" + }; + static const char * const boardinfo[] = { + "Manufacturer Name", + "Product Name", + "Serial No", + "Part Number", + "File ID" + }; + + if (verbose) { + printf("*****BOARD INFO*****\n"); + printf("Version:%d\n", fru_version(brd->ver)); + printf("Board Area Length:%d\n", fru_cal_area_len(brd->len)); + } + + if (fru_check_language(brd->lang_code)) + return -EINVAL; + + time = brd->time[2] << 16 | brd->time[1] << 8 | + brd->time[0]; + + if (verbose) + printf("Time in Minutes from 0:00hrs 1/1/96: %d\n", time); + + data = (u8 *)&brd->manufacturer_type_len; + + for (u8 i = 0; i < (sizeof(boardinfo) / sizeof(*boardinfo)); i++) { + len = fru_check_type_len(*data++, brd->lang_code, + &type); + if (len == -EINVAL) { + printf("**** EOF for Board Area ****\n"); + break; + } + + if (type <= FRU_TYPELEN_TYPE_ASCII8 && + (brd->lang_code == FRU_LANG_CODE_ENGLISH || + brd->lang_code == FRU_LANG_CODE_ENGLISH_1)) + debug("Type code: %s\n", typecode[type]); + else + debug("Type code: %s\n", typecode[type + 1]); + + if (!len) { + debug("%s not found\n", boardinfo[i]); + continue; + } + + switch (type) { + case FRU_TYPELEN_TYPE_BINARY: + debug("Length: %d\n", len); + printf(" %s: 0x%x\n", boardinfo[i], *data); + break; + case FRU_TYPELEN_TYPE_ASCII8: + debug("Length: %d\n", len); + printf(" %s: %s\n", boardinfo[i], data); + break; + default: + debug("Unsupported type %x\n", type); + } + + data += FRU_BOARD_MAX_LEN; + } + + return 0; +} + +static void fru_display_common_hdr(struct fru_common_hdr *hdr, int verbose) +{ + if (!verbose) + return; + + printf("*****COMMON HEADER*****\n"); + printf("Version:%d\n", fru_version(hdr->version)); + if (hdr->off_internal) + printf("Internal Use Area Offset:%d\n", + fru_cal_area_len(hdr->off_internal)); + else + printf("*** No Internal Area ***\n"); + + if (hdr->off_chassis) + printf("Chassis Info Area Offset:%d\n", + fru_cal_area_len(hdr->off_chassis)); + else + printf("*** No Chassis Info Area ***\n"); + + if (hdr->off_board) + printf("Board Area Offset:%d\n", + fru_cal_area_len(hdr->off_board)); + else + printf("*** No Board Area ***\n"); + + if (hdr->off_product) + printf("Product Info Area Offset:%d\n", + fru_cal_area_len(hdr->off_product)); + else + printf("*** No Product Info Area ***\n"); + + if (hdr->off_multirec) + printf("MultiRecord Area Offset:%d\n", + fru_cal_area_len(hdr->off_multirec)); + else + printf("*** No MultiRecord Area ***\n"); +} + +int fru_display(int verbose) +{ + if (!fru_data.captured) { + printf("FRU data not available please run fru parse\n"); + return -EINVAL; + } + + fru_display_common_hdr(&fru_data.hdr, verbose); + + return fru_display_board(&fru_data.brd, verbose); +} diff --git a/board/xilinx/zynqmp/MAINTAINERS b/board/xilinx/zynqmp/MAINTAINERS index 04fc7f32fe8..9cd4f3f53ef 100644 --- a/board/xilinx/zynqmp/MAINTAINERS +++ b/board/xilinx/zynqmp/MAINTAINERS @@ -3,6 +3,7 @@ M: Michal Simek S: Maintained F: arch/arm/dts/zynqmp-* F: arch/arm/dts/avnet-ultra96* +F: board/xilinx/common/ F: board/xilinx/zynqmp/ F: include/configs/xilinx_zynqmp* F: configs/xilinx_zynqmp* From 4489e0aa9b5548a2ad1beb2853bbc0db56cf1db5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 15 Apr 2019 13:54:09 +0200 Subject: [PATCH 44/71] xilinx: cmd: Add basic fru format generator Idea is to have something what can be used for board bringup from generic board perspective. There is a violation compare to spec that FRU ID is ASCII8 instead of binary format but this is really for having something to pass boot and boot to OS which has better generating options. Also time should be filled properly. For example: fru board_gen 1000 XILINX versal-x-prc-01-revA serialX partX There is also support for revision field which is Xilinx specific field. Signed-off-by: Michal Simek --- board/xilinx/common/fru.c | 20 ++++++- board/xilinx/common/fru.h | 17 ++++++ board/xilinx/common/fru_ops.c | 101 +++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/board/xilinx/common/fru.c b/board/xilinx/common/fru.c index 0ab9f2a78bd..ccf48723ff8 100644 --- a/board/xilinx/common/fru.c +++ b/board/xilinx/common/fru.c @@ -33,9 +33,23 @@ static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + unsigned long addr; + + if (argc < cmdtp->maxargs) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[2], NULL, 16); + + return fru_generate(addr, argv[3], argv[4], argv[5], argv[6], argv[7]); +} + static struct cmd_tbl cmd_fru_sub[] = { U_BOOT_CMD_MKENT(capture, 3, 0, do_fru_capture, "", ""), U_BOOT_CMD_MKENT(display, 2, 0, do_fru_display, "", ""), + U_BOOT_CMD_MKENT(board_gen, 8, 0, do_fru_generate, "", ""), }; static int do_fru(struct cmd_tbl *cmdtp, int flag, int argc, @@ -63,11 +77,15 @@ static char fru_help_text[] = "capture - Parse and capture FRU table present at address.\n" "fru display - Displays content of FRU table that was captured using\n" " fru capture command\n" + "fru board_gen \n" + " - Generate FRU format with\n" + " board info area filled based on parameters. is\n" + " pointing to place where FRU is generated.\n" ; #endif U_BOOT_CMD( - fru, 3, 1, do_fru, + fru, 8, 1, do_fru, "FRU table info", fru_help_text ) diff --git a/board/xilinx/common/fru.h b/board/xilinx/common/fru.h index a0413cf7f69..a3e65202571 100644 --- a/board/xilinx/common/fru.h +++ b/board/xilinx/common/fru.h @@ -20,6 +20,18 @@ struct fru_common_hdr { #define FRU_BOARD_MAX_LEN 32 +struct __packed fru_board_info_header { + u8 ver; + u8 len; + u8 lang_code; + u8 time[3]; +}; + +struct __packed fru_board_info_member { + u8 type_len; + u8 *name; +}; + struct fru_board_data { u8 ver; u8 len; @@ -35,6 +47,9 @@ struct fru_board_data { u8 part_number[FRU_BOARD_MAX_LEN]; u8 file_id_type_len; u8 file_id[FRU_BOARD_MAX_LEN]; + /* Xilinx custom fields */ + u8 rev_type_len; + u8 rev[FRU_BOARD_MAX_LEN]; }; struct fru_table { @@ -59,6 +74,8 @@ struct fru_table { int fru_display(int verbose); int fru_capture(unsigned long addr); +int fru_generate(unsigned long addr, char *manufacturer, char *board_name, + char *serial_no, char *part_no, char *revision); u8 fru_checksum(u8 *addr, u8 len); extern struct fru_table fru_data; diff --git a/board/xilinx/common/fru_ops.c b/board/xilinx/common/fru_ops.c index 491e92a7afb..fc3add7d93d 100644 --- a/board/xilinx/common/fru_ops.c +++ b/board/xilinx/common/fru_ops.c @@ -62,6 +62,103 @@ static int fru_check_type_len(u8 type_len, u8 language, u8 *type) return len; } +/* Return len */ +static u8 fru_gen_type_len(u8 *addr, char *name) +{ + int len = strlen(name); + struct fru_board_info_member *member; + + member = (struct fru_board_info_member *)addr; + member->type_len = FRU_TYPELEN_TYPE_ASCII8 << FRU_TYPELEN_TYPE_SHIFT; + member->type_len |= len; + + debug("%lx/%lx: Add %s to 0x%lx (len 0x%x)\n", (ulong)addr, + (ulong)&member->type_len, name, (ulong)&member->name, len); + memcpy(&member->name, name, len); + + /* Add +1 for type_len parameter */ + return 1 + len; +} + +int fru_generate(unsigned long addr, char *manufacturer, char *board_name, + char *serial_no, char *part_no, char *revision) +{ + struct fru_common_hdr *header = (struct fru_common_hdr *)addr; + struct fru_board_info_header *board_info; + u8 *member; + u8 len, pad, modulo; + + header->version = 1; /* Only version 1.0 is supported now */ + header->off_internal = 0; /* not present */ + header->off_chassis = 0; /* not present */ + header->off_board = (sizeof(*header)) / 8; /* Starting offset 8 */ + header->off_product = 0; /* not present */ + header->off_multirec = 0; /* not present */ + header->pad = 0; + /* + * This unsigned byte can be used to calculate a zero checksum + * for the data area following the header. I.e. the modulo 256 sum of + * the record data bytes plus the checksum byte equals zero. + */ + header->crc = 0; /* Clear before calculation */ + header->crc = 0 - fru_checksum((u8 *)header, sizeof(*header)); + + /* board info is just right after header */ + board_info = (void *)((u8 *)header + sizeof(*header)); + + debug("header %lx, board_info %lx\n", (ulong)header, (ulong)board_info); + + board_info->ver = 1; /* 1.0 spec */ + board_info->lang_code = 0; /* English */ + board_info->time[0] = 0; /* unspecified */ + board_info->time[1] = 0; /* unspecified */ + board_info->time[2] = 0; /* unspecified */ + + /* Member fields are just after board_info header */ + member = (u8 *)board_info + sizeof(*board_info); + + len = fru_gen_type_len(member, manufacturer); /* Board Manufacturer */ + member += len; + len = fru_gen_type_len(member, board_name); /* Board Product name */ + member += len; + len = fru_gen_type_len(member, serial_no); /* Board Serial number */ + member += len; + len = fru_gen_type_len(member, part_no); /* Board part number */ + member += len; + len = fru_gen_type_len(member, "U-Boot generator"); /* File ID */ + member += len; + len = fru_gen_type_len(member, revision); /* Revision */ + member += len; + + *member++ = 0xc1; /* Indication of no more fields */ + + len = member - (u8 *)board_info; /* Find current length */ + len += 1; /* Add checksum there too for calculation */ + + modulo = len % 8; + + if (modulo) { + /* Do not fill last item which is checksum */ + for (pad = 0; pad < 8 - modulo; pad++) + *member++ = 0; + + /* Increase structure size */ + len += 8 - modulo; + } + + board_info->len = len / 8; /* Size in multiples of 8 bytes */ + + *member = 0; /* Clear before calculation */ + *member = 0 - fru_checksum((u8 *)board_info, len); + + debug("checksum %x(addr %x)\n", *member, len); + + env_set_hex("fru_addr", addr); + env_set_hex("filesize", (unsigned long)member - addr + 1); + + return 0; +} + static int fru_parse_board(unsigned long addr) { u8 i, type; @@ -153,7 +250,9 @@ static int fru_display_board(struct fru_board_data *brd, int verbose) "Product Name", "Serial No", "Part Number", - "File ID" + "File ID", + /* Xilinx spec */ + "Revision Number", }; if (verbose) { From f149b39ca3afbe3645f3e50ebd8a1e8af9a445a3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Aug 2020 16:14:23 +0200 Subject: [PATCH 45/71] xilinx: board: Add FRU decoder support FMC cards are using FRU format for card identification. That's why add support for this format. Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 83 ++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 410b4cd998e..821ee836dd8 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -17,6 +17,8 @@ #include #include +#include "fru.h" + #if defined(CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET) int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) { @@ -65,7 +67,7 @@ struct xilinx_board_description { static int highest_id = -1; static struct xilinx_board_description **board_info; -#define XILINX_I2C_DETECTION_BITS 8 +#define XILINX_I2C_DETECTION_BITS sizeof(struct fru_common_hdr) /* Variable which stores pointer to array which stores eeprom content */ struct xilinx_legacy_format { @@ -160,6 +162,82 @@ static bool xilinx_detect_legacy(u8 *buffer) return true; } +static int xilinx_read_eeprom_fru(struct udevice *dev, char *name, + struct xilinx_board_description *desc) +{ + int ret, eeprom_size; + u8 *fru_content; + + /* FIXME this is shortcut - if eeprom type is wrong it will fail */ + eeprom_size = i2c_eeprom_size(dev); + + fru_content = calloc(1, eeprom_size); + if (!fru_content) + return -ENOMEM; + + debug("%s: I2C EEPROM read pass data at %p\n", __func__, + fru_content); + + ret = dm_i2c_read(dev, 0, (uchar *)fru_content, + eeprom_size); + if (ret) { + debug("%s: I2C EEPROM read failed\n", __func__); + free(fru_content); + return ret; + } + + printf("Xilinx I2C FRU format at %s:\n", name); + fru_capture((unsigned long)fru_content); + ret = fru_display(0); + if (ret) { + printf("FRU format decoding failed.\n"); + return ret; + } + + if (desc->header == EEPROM_HEADER_MAGIC) { + debug("Information already filled\n"); + return -EINVAL; + } + + /* It is clear that FRU was captured and structures were filled */ + strncpy(desc->manufacturer, (char *)fru_data.brd.manufacturer_name, + sizeof(desc->manufacturer)); + strncpy(desc->name, (char *)fru_data.brd.product_name, + sizeof(desc->name)); + strncpy(desc->revision, (char *)fru_data.brd.rev, + sizeof(desc->revision)); + strncpy(desc->serial, (char *)fru_data.brd.serial_number, + sizeof(desc->serial)); + desc->header = EEPROM_HEADER_MAGIC; + + return 0; +} + +static bool xilinx_detect_fru(u8 *buffer) +{ + u8 checksum = 0; + int i; + + checksum = fru_checksum((u8 *)buffer, sizeof(struct fru_common_hdr)); + if (checksum) { + debug("%s Common header CRC FAIL\n", __func__); + return false; + } + + bool all_zeros = true; + /* Checksum over all zeros is also zero that's why detect this case */ + for (i = 0; i < sizeof(struct fru_common_hdr); i++) { + if (buffer[i] != 0) + all_zeros = false; + } + + if (all_zeros) + return false; + + debug("%s Common header CRC PASS\n", __func__); + return true; +} + static int xilinx_read_eeprom_single(char *name, struct xilinx_board_description *desc) { @@ -184,6 +262,9 @@ static int xilinx_read_eeprom_single(char *name, debug("%s: i2c memory detected: %s\n", __func__, name); + if (CONFIG_IS_ENABLED(CMD_FRU) && xilinx_detect_fru(buffer)) + return xilinx_read_eeprom_fru(dev, name, desc); + if (xilinx_detect_legacy(buffer)) return xilinx_read_eeprom_legacy(dev, name, desc); From d026aa1de3330face74ccecb265bcfe722bcd20a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 21 Oct 2020 12:16:02 +0200 Subject: [PATCH 46/71] xilinx: zynqmp: Check return value from xilinx_pm_request() xilinx_pm_request() can failed that's why also check return value. Fixes: 050f10f103cd ("xilinx: zynqmp: remove chip_id function") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index db3f5978a92..e6582454080 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -192,7 +192,11 @@ static char *zynqmp_get_silicon_idcode_name(void) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + if (ret) { + debug("%s: Getting chipid failed\n", __func__); + return "unknown"; + } /* * Firmware returns: From 16df2f1edb82124e21da32404771d8947882ebe2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 21 Oct 2020 12:16:50 +0200 Subject: [PATCH 47/71] xilinx: zynqmp: Fix debug message in zynqmp_get_silicon_idcode_name() Fix hex format from 0x%0X to 0x%0x to show correct numbers. Fixes: fa793165daf7 ("xilinx: zynqmp: refactor silicon name function") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index e6582454080..7ba2c789751 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -209,7 +209,7 @@ static char *zynqmp_get_silicon_idcode_name(void) idcode = ret_payload[1]; idcode2 = ret_payload[2] >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT; - debug("%s, IDCODE: 0x%0X, IDCODE2: 0x%0X\r\n", __func__, idcode, + debug("%s, IDCODE: 0x%0x, IDCODE2: 0x%0x\r\n", __func__, idcode, idcode2); for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { From 07499daf507cecbe85e959d54aa1b6972905d8c7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 21 Oct 2020 12:17:44 +0200 Subject: [PATCH 48/71] xilinx: zynqmp: Do not check 0 as invalid return from snprintf U-Boot SPL on ZynqMP is using CONFIG_SPL_USE_TINY_PRINTF which doesn't return any return value and all the time returns 0. That's why even correct snprintf was returning in SPL chip ID as "unknown". Change checking condition and allow snprintf to return 0 which is according manual patch successful return. "If an output error is encountered, a negative value is returned." Fixes: 43a138956f7e ("arm64: zynqmp: Get rid of simple_itoa and replace it by snprintf") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 7ba2c789751..c4f24982843 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -223,7 +223,7 @@ static char *zynqmp_get_silicon_idcode_name(void) /* Add device prefix to the name */ ret = snprintf(name, ZYNQMP_VERSION_SIZE, "zu%d", zynqmp_devices[i].device); - if (ret <= 0) + if (ret < 0) return "unknown"; if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_EV) { From 2fbdbee732aeaaa1cc541403e916221169d86bbf Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 21 Oct 2020 12:23:17 +0200 Subject: [PATCH 49/71] xilinx: zynqmp: Use tab for macro indentation Trivial fix. Fixes: fa793165daf7 ("xilinx: zynqmp: refactor silicon name function") Signed-off-by: Michal Simek --- board/xilinx/zynqmp/zynqmp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index c4f24982843..731285a7367 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -40,12 +40,12 @@ #include "pm_cfg_obj.h" #define ZYNQMP_VERSION_SIZE 7 -#define EFUSE_VCU_DIS_MASK 0x100 -#define EFUSE_VCU_DIS_SHIFT 8 -#define EFUSE_GPU_DIS_MASK 0x20 -#define EFUSE_GPU_DIS_SHIFT 5 -#define IDCODE2_PL_INIT_MASK 0x200 -#define IDCODE2_PL_INIT_SHIFT 9 +#define EFUSE_VCU_DIS_MASK 0x100 +#define EFUSE_VCU_DIS_SHIFT 8 +#define EFUSE_GPU_DIS_MASK 0x20 +#define EFUSE_GPU_DIS_SHIFT 5 +#define IDCODE2_PL_INIT_MASK 0x200 +#define IDCODE2_PL_INIT_SHIFT 9 DECLARE_GLOBAL_DATA_PTR; From d93fbac512a44bd05bae9db5834b22945911d70c Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 22 Jul 2020 02:27:34 -0600 Subject: [PATCH 50/71] arm64: zynqmp: Fix zynqmp mini qspi max frequency For zynqmp qspi, frequencies up to 40MHz will work irrespective of feedback clock enabled or disabled. If we want higher than 40Mhz the feedback clock should be enabled. With spi-max-frequency 108MHz it is not working when the feedback clock is disabled. Change it to 40MHz so that it works irrespective of feedback clock enabled or disabled. Signed-off-by: T Karthik Reddy Acked-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- arch/arm/dts/zynqmp-mini-qspi.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/zynqmp-mini-qspi.dts b/arch/arm/dts/zynqmp-mini-qspi.dts index a76e6404661..9b4320fe6e2 100644 --- a/arch/arm/dts/zynqmp-mini-qspi.dts +++ b/arch/arm/dts/zynqmp-mini-qspi.dts @@ -70,7 +70,7 @@ reg = <0x0>; spi-tx-bus-width = <1>; spi-rx-bus-width = <4>; - spi-max-frequency = <108000000>; + spi-max-frequency = <40000000>; }; }; From d388cedd466ade3265490be841bd24a1ad8539af Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 1 Apr 2020 06:01:21 -0600 Subject: [PATCH 51/71] xilinx: Add DDR base address to bootscript address Add ram base address to scriptaddr env variable to make boot script address to be a valid address when ddr base address changes. This works properly if the first memory region is the region where uboot runs. Also the solution was taken in respect of a lot of jtag script putting u-boot script to certain address. For standard cases bd->bi_dram[0].start is 0 all the time. Only for systems with DDR placed out of this location it does calculation. This is not the best solution and should be done differently in future but enough for now till we don't have full solution ready yet. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 821ee836dd8..857a66a5040 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -371,6 +371,15 @@ int board_late_init_xilinx(void) int i, id, macid = 0; struct xilinx_board_description *desc; phys_size_t bootm_size = gd->ram_size; + struct bd_info *bd = gd->bd; + + if (bd->bi_dram[0].start) { + ulong scriptaddr; + + scriptaddr = env_get_hex("scriptaddr", 0); + ret |= env_set_hex("scriptaddr", + bd->bi_dram[0].start + scriptaddr); + } if (CONFIG_IS_ENABLED(ARCH_ZYNQ)) bootm_size = min(bootm_size, (phys_size_t)(SZ_512M + SZ_256M)); From a0c26f74a926a6d7e92f23d1a370940e6d4ffef4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 10:33:29 +0200 Subject: [PATCH 52/71] xilinx: Enable FRU command for all ARM based platforms Enable it by default for board detection. Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 + configs/xilinx_zynq_virt_defconfig | 1 + configs/xilinx_zynqmp_virt_defconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index b6ca566ed8c..34ff8ddde0c 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -4,6 +4,7 @@ CONFIG_ARCH_VERSAL=y CONFIG_SYS_TEXT_BASE=0x8000000 CONFIG_SYS_MALLOC_F_LEN=0x100000 CONFIG_DM_GPIO=y +CONFIG_CMD_FRU=y CONFIG_DEFINE_TCM_OCM_MMAP=y CONFIG_COUNTER_FREQUENCY=100000000 CONFIG_DISTRO_DEFAULTS=y diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index df3da763c50..439a4fe6e53 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -6,6 +6,7 @@ CONFIG_SYS_SPI_U_BOOT_OFFS=0x100000 CONFIG_DM_GPIO=y CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_SPL=y +CONFIG_CMD_FRU=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc706" CONFIG_DISTRO_DEFAULTS=y CONFIG_SYS_CUSTOM_LDSCRIPT=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 01b2f18a057..8937658a25d 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -9,6 +9,7 @@ CONFIG_SPL_SPI_FLASH_SUPPORT=y CONFIG_SPL_SPI_SUPPORT=y CONFIG_ZYNQ_MAC_IN_EEPROM=y CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0x20 +CONFIG_CMD_FRU=y CONFIG_ZYNQMP_USB=y CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu100-revC" CONFIG_AHCI=y From c2a2c83278666cacb85761b8db55a3de8031c459 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 10:59:08 +0200 Subject: [PATCH 53/71] xilinx: zynq: Change types from u32 to uint32_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change parameter type to avoid compilation error: In file included from ./tools/../lib/rsa/rsa-verify.c:23:0, from tools/lib/rsa/rsa-verify.c:1: include/u-boot/rsa-mod-exp.h:69:18: error: unknown type name ‘u32’; did you mean ‘__u32’? int zynq_pow_mod(u32 *keyptr, u32 *inout); ^~~ __u32 include/u-boot/rsa-mod-exp.h:69:31: error: unknown type name ‘u32’; did you mean ‘__u32’? int zynq_pow_mod(u32 *keyptr, u32 *inout); ^~~ __u32 Fixes: 37e3a36a5475 ("xilinx: zynq: Add support to secure images") Signed-off-by: Michal Simek --- include/u-boot/rsa-mod-exp.h | 2 +- lib/rsa/rsa-mod-exp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h index 1da8af1bb83..7b7c2915a94 100644 --- a/include/u-boot/rsa-mod-exp.h +++ b/include/u-boot/rsa-mod-exp.h @@ -66,7 +66,7 @@ int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len, struct key_prop *node, uint8_t *out); #if defined(CONFIG_CMD_ZYNQ_RSA) -int zynq_pow_mod(u32 *keyptr, u32 *inout); +int zynq_pow_mod(uint32_t *keyptr, uint32_t *inout); #endif /** diff --git a/lib/rsa/rsa-mod-exp.c b/lib/rsa/rsa-mod-exp.c index 78c688d14c3..74f9eb16cc2 100644 --- a/lib/rsa/rsa-mod-exp.c +++ b/lib/rsa/rsa-mod-exp.c @@ -321,7 +321,7 @@ int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len, * pow_mod calculation required for zynq is bit different from * pw_mod above here, hence defined zynq specific routine. */ -int zynq_pow_mod(u32 *keyptr, u32 *inout) +int zynq_pow_mod(uint32_t *keyptr, uint32_t *inout) { u32 *result, *ptr; uint i; From 483a31c8aa173e0f3d9acc135235d95da274e559 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 10:34:00 +0200 Subject: [PATCH 54/71] xilinx: zynq: Enable AES command Enable AES command to be able to use it directly. Signed-off-by: Michal Simek --- configs/xilinx_zynq_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index 439a4fe6e53..09820d76a61 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -7,6 +7,7 @@ CONFIG_DM_GPIO=y CONFIG_SPL_STACK_R_ADDR=0x200000 CONFIG_SPL=y CONFIG_CMD_FRU=y +CONFIG_CMD_ZYNQ_AES=y CONFIG_DEFAULT_DEVICE_TREE="zynq-zc706" CONFIG_DISTRO_DEFAULTS=y CONFIG_SYS_CUSTOM_LDSCRIPT=y From 6a136e53f019d5458842f32ab6455bd7629e7f2c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 10:34:43 +0200 Subject: [PATCH 55/71] xilinx: Enable SF_TEST command for all ARM based platforms Enable this command by default. Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 + configs/xilinx_zynq_virt_defconfig | 1 + configs/xilinx_zynqmp_virt_defconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index 34ff8ddde0c..40a8cfd5ccc 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -28,6 +28,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_MTD=y +CONFIG_CMD_SF_TEST=y CONFIG_CMD_USB=y CONFIG_CMD_TFTPPUT=y CONFIG_CMD_CACHE=y diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index 09820d76a61..da84c01b0a1 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -42,6 +42,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_MTD=y CONFIG_CMD_NAND_LOCK_UNLOCK=y +CONFIG_CMD_SF_TEST=y CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_TFTPPUT=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 8937658a25d..0c816de707a 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -49,6 +49,7 @@ CONFIG_CMD_MTD=y CONFIG_CMD_NAND_LOCK_UNLOCK=y CONFIG_CMD_POWEROFF=y CONFIG_CMD_SDRAM=y +CONFIG_CMD_SF_TEST=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y From f2b03760104acf7ede36fc9958aa2dee3b8238ae Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 10:37:00 +0200 Subject: [PATCH 56/71] xilinx: Remove additional newline in config files Trivial fix. Fixes: e519f03a1846 ("cmd: mem: Remove CONFIG_SYS_MEMTEST_SCRATCH mapping") Signed-off-by: Michal Simek --- include/configs/xilinx_versal.h | 1 - include/configs/xilinx_versal_mini.h | 1 - include/configs/xilinx_zynqmp_mini.h | 1 - 3 files changed, 3 deletions(-) diff --git a/include/configs/xilinx_versal.h b/include/configs/xilinx_versal.h index 8b416327b57..f1d2594f3b3 100644 --- a/include/configs/xilinx_versal.h +++ b/include/configs/xilinx_versal.h @@ -18,7 +18,6 @@ #define GICD_BASE 0xF9000000 #define GICR_BASE 0xF9080000 - #define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE /* Generic Timer Definitions - setup in EL3. Setup by ATF for other cases */ diff --git a/include/configs/xilinx_versal_mini.h b/include/configs/xilinx_versal_mini.h index 0b201a2b4d6..00c97188198 100644 --- a/include/configs/xilinx_versal_mini.h +++ b/include/configs/xilinx_versal_mini.h @@ -10,7 +10,6 @@ #ifndef __CONFIG_VERSAL_MINI_H #define __CONFIG_VERSAL_MINI_H - #define CONFIG_EXTRA_ENV_SETTINGS #include diff --git a/include/configs/xilinx_zynqmp_mini.h b/include/configs/xilinx_zynqmp_mini.h index 3f57423b789..ef9c768e48e 100644 --- a/include/configs/xilinx_zynqmp_mini.h +++ b/include/configs/xilinx_zynqmp_mini.h @@ -10,7 +10,6 @@ #ifndef __CONFIG_ZYNQMP_MINI_H #define __CONFIG_ZYNQMP_MINI_H - #define CONFIG_EXTRA_ENV_SETTINGS #include From 92dc9210635a73ed80d7aa77932f64a8af516a68 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Oct 2020 11:08:58 +0200 Subject: [PATCH 57/71] xilinx: Merge together BOOT_SCRIPT_OFFSET between MB and ARM There is no reason not to use commong Kconfig by Microblaze too. Signed-off-by: Michal Simek --- arch/microblaze/Kconfig | 1 + board/xilinx/Kconfig | 6 +++--- board/xilinx/microblaze-generic/Kconfig | 5 ----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 2755cce884c..99a17bccb38 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -23,6 +23,7 @@ config TARGET_MICROBLAZE_GENERIC endchoice +source "board/xilinx/Kconfig" source "board/xilinx/microblaze-generic/Kconfig" endmenu diff --git a/board/xilinx/Kconfig b/board/xilinx/Kconfig index 51f6d2bac8a..64507b5d843 100644 --- a/board/xilinx/Kconfig +++ b/board/xilinx/Kconfig @@ -50,12 +50,12 @@ config XILINX_OF_BOARD_DTB_ADDR config BOOT_SCRIPT_OFFSET hex "Boot script offset" - depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL - default 0xFC0000 if ARCH_ZYNQ + depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || MICROBLAZE + default 0xFC0000 if ARCH_ZYNQ || MICROBLAZE default 0x3E80000 if ARCH_ZYNQMP default 0x7F80000 if ARCH_VERSAL help - Specifies distro boot script offset in NAND/NOR flash. + Specifies distro boot script offset in NAND/QSPI/NOR flash. config ZYNQ_MAC_IN_EEPROM bool "Reading MAC address from EEPROM" diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index 7a97211a1ec..f2fa0f72b13 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -38,9 +38,4 @@ config XILINX_MICROBLAZE0_HW_VER string "Core version number" default "7.10.d" -config BOOT_SCRIPT_OFFSET - hex "Boot script offset" - default 0xFC0000 - help - Specifies distro boot script offset in NAND/QSPI flash. endif From 123058215079a733b6f1f1237f738d254df56857 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Oct 2020 07:54:18 +0200 Subject: [PATCH 58/71] microblaze: Wire generic xilinx board_late_init_xilinx() Call generic board_late_init_xilinx() to be aligned with the rest of xilinx platforms. Also getting rid of initrd_high/fdt_high and use bootm_low/boot_size instead. Reported-by: Tom Rini Signed-off-by: Michal Simek --- board/xilinx/common/board.c | 4 ++-- .../microblaze-generic/microblaze-generic.c | 15 +++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 857a66a5040..bcdd3ae4f14 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -373,7 +373,7 @@ int board_late_init_xilinx(void) phys_size_t bootm_size = gd->ram_size; struct bd_info *bd = gd->bd; - if (bd->bi_dram[0].start) { + if (!CONFIG_IS_ENABLED(MICROBLAZE) && bd->bi_dram[0].start) { ulong scriptaddr; scriptaddr = env_get_hex("scriptaddr", 0); @@ -381,7 +381,7 @@ int board_late_init_xilinx(void) bd->bi_dram[0].start + scriptaddr); } - if (CONFIG_IS_ENABLED(ARCH_ZYNQ)) + if (CONFIG_IS_ENABLED(ARCH_ZYNQ) || CONFIG_IS_ENABLED(MICROBLAZE)) bootm_size = min(bootm_size, (phys_size_t)(SZ_512M + SZ_256M)); ret |= env_set_hex("script_offset_f", CONFIG_BOOT_SCRIPT_OFFSET); diff --git a/board/xilinx/microblaze-generic/microblaze-generic.c b/board/xilinx/microblaze-generic/microblaze-generic.c index c1ae8fbfe74..e5909997690 100644 --- a/board/xilinx/microblaze-generic/microblaze-generic.c +++ b/board/xilinx/microblaze-generic/microblaze-generic.c @@ -18,6 +18,7 @@ #include #include #include +#include "../common/board.h" DECLARE_GLOBAL_DATA_PTR; @@ -36,7 +37,7 @@ int dram_init(void) int board_late_init(void) { - ulong max_size, lowmem_size; + ulong max_size; u32 status = 0; #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE) @@ -56,14 +57,6 @@ int board_late_init(void) max_size = gd->start_addr_sp - CONFIG_STACK_SIZE; max_size = round_down(max_size, SZ_16M); - /* Linux default LOWMEM_SIZE is 0x30000000 = 768MB */ - lowmem_size = gd->ram_base + 768 * 1024 * 1024; - - status |= env_set_addr("initrd_high", (void *)min_t(ulong, max_size, - lowmem_size)); - status |= env_set_addr("fdt_high", (void *)min_t(ulong, max_size, - lowmem_size)); - status |= env_set_hex("scriptaddr", max_size + SZ_2M); status |= env_set_hex("pxefile_addr_r", max_size + SZ_1M); @@ -75,10 +68,8 @@ int board_late_init(void) status |= env_set_hex("ramdisk_addr_r", gd->ram_base + SZ_32M + SZ_4M + SZ_2M); - status |= env_set_hex("script_offset_f", CONFIG_BOOT_SCRIPT_OFFSET); - if (status) printf("%s: Saving run time variables FAILED\n", __func__); - return 0; + return board_late_init_xilinx(); } From 262bcedf106d24970c93aded851a258856d49e3e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Oct 2020 09:36:36 +0200 Subject: [PATCH 59/71] microblaze: Enable board_late_init() In board_late_init() several variables are setup to match the current configuration. Signed-off-by: Michal Simek --- configs/microblaze-generic_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/microblaze-generic_defconfig b/configs/microblaze-generic_defconfig index 7cf736954b4..08c88856dcd 100644 --- a/configs/microblaze-generic_defconfig +++ b/configs/microblaze-generic_defconfig @@ -22,6 +22,7 @@ CONFIG_USE_PREBOOT=y CONFIG_PREBOOT="echo U-BOOT for ${hostname};setenv preboot;echo" CONFIG_SYS_CONSOLE_IS_IN_ENV=y CONFIG_DISPLAY_BOARDINFO=y +CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_NOR_SUPPORT=y From 89b7f1010f0b835a6d082356889c409eb827763b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 26 Oct 2020 11:28:27 +0100 Subject: [PATCH 60/71] mtd: spi: Fix incorrect indentation Use tabs to be aligned with the rest of the code. Fixes: 658df8bd9464 ("mtd: spi-nor-core: Add octal mode support") Signed-off-by: Michal Simek --- drivers/mtd/spi/sf_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index dabd40a4cc1..9ceff0e7c12 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -67,7 +67,7 @@ struct flash_info { #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ #define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */ -#define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */ +#define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */ }; extern const struct flash_info spi_nor_ids[]; From 17fbb598f64bcc9612281d81e946fedbdc63781a Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Tue, 28 Jan 2020 07:39:04 -0700 Subject: [PATCH 61/71] spi: zynq_qspi: Add function description Add function description for zynq_qspi_init_hw and zynq_qspi_chipselect. Fix zqspi to priv in function descriptions. Change the description of priv as pointer to zynq_qspi_priv structure. Fix other function descriptions to kernel-doc style. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- drivers/spi/zynq_qspi.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index 4219a35c840..f2eddec950a 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -110,6 +110,26 @@ static int zynq_qspi_ofdata_to_platdata(struct udevice *bus) return 0; } +/** + * zynq_qspi_init_hw - Initialize the hardware + * @priv: Pointer to the zynq_qspi_priv structure + * + * The default settings of the QSPI controller's configurable parameters on + * reset are + * - Master mode + * - Baud rate divisor is set to 2 + * - Threshold value for TX FIFO not full interrupt is set to 1 + * - Flash memory interface mode enabled + * - Size of the word to be transferred as 8 bit + * This function performs the following actions + * - Disable and clear all the interrupts + * - Enable manual slave select + * - Enable auto start + * - Deselect all the chip select lines + * - Set the size of the word to be transferred as 32 bit + * - Set the little endian mode of TX FIFO and + * - Enable the QSPI controller + */ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) { struct zynq_qspi_regs *regs = priv->regs; @@ -189,9 +209,9 @@ static int zynq_qspi_probe(struct udevice *bus) return 0; } -/* +/** * zynq_qspi_read_data - Copy data to RX buffer - * @zqspi: Pointer to the zynq_qspi structure + * @priv: Pointer to the zynq_qspi_priv structure * @data: The 32 bit variable where data is stored * @size: Number of bytes to be copied from data to RX buffer */ @@ -234,9 +254,9 @@ static void zynq_qspi_read_data(struct zynq_qspi_priv *priv, u32 data, u8 size) priv->bytes_to_receive = 0; } -/* +/** * zynq_qspi_write_data - Copy data from TX buffer - * @zqspi: Pointer to the zynq_qspi structure + * @priv: Pointer to the zynq_qspi_priv structure * @data: Pointer to the 32 bit variable where data is to be copied * @size: Number of bytes to be copied from TX buffer to data */ @@ -283,6 +303,11 @@ static void zynq_qspi_write_data(struct zynq_qspi_priv *priv, priv->bytes_to_transfer = 0; } +/** + * zynq_qspi_chipselect - Select or deselect the chip select line + * @priv: Pointer to the zynq_qspi_priv structure + * @is_on: Select(1) or deselect (0) the chip select line + */ static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on) { u32 confr; @@ -302,9 +327,10 @@ static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on) writel(confr, ®s->cr); } -/* +/** * zynq_qspi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible - * @zqspi: Pointer to the zynq_qspi structure + * @priv: Pointer to the zynq_qspi_priv structure + * @size: Number of bytes to be copied to fifo */ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size) { @@ -342,9 +368,9 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size) } } -/* +/** * zynq_qspi_irq_poll - Interrupt service routine of the QSPI controller - * @zqspi: Pointer to the zynq_qspi structure + * @priv: Pointer to the zynq_qspi structure * * This function handles TX empty and Mode Fault interrupts only. * On TX empty interrupt this function reads the received data from RX FIFO and @@ -430,11 +456,9 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv) return 0; } -/* +/** * zynq_qspi_start_transfer - Initiates the QSPI transfer - * @qspi: Pointer to the spi_device structure - * @transfer: Pointer to the spi_transfer structure which provide information - * about next transfer parameters + * @priv: Pointer to the zynq_qspi_priv structure * * This function fills the TX FIFO, starts the QSPI transfer, and waits for the * transfer to be completed. From 7a49a16ec54e03ea6a383c1b97a78acc059c2df8 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:58:57 -0600 Subject: [PATCH 62/71] Revert "mmc: zynq: parse dt when probing" This reverts commit 942b5fc03218d1c94468fc658e7dec65dabcc830. This is partial revert of the above commit. mmc_of_parse() is reading no-1-8-v from device tree and if set, it is clearing the UHS speed capabilities of cfg->host_caps. cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400 | MMC_MODE_HS400_ES); This is still missing to clear UHS speeds like SDHCI_SUPPORT_SDR104, SDHCI_SUPPORT_SDR50 and SDHCI_SUPPORT_DDR50. Even if we clear the flags SDHCI_SUPPORT_XXX in mmc_of_parse(), these speed flags are getting set again in cfg->host_caps in sdhci_setup_cfg(). The reason for this is, SDHCI_SUPPORT_XXX flags are cleared only if controller is not capable of supporting MMC_VDD_165_195 volts. if (caps & SDHCI_CAN_VDD_180) cfg->voltages |= MMC_VDD_165_195; if (!(cfg->voltages & MMC_VDD_165_195)) caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); It means "no-1-8-v", which is read from DT is not coming in to effect. So it is better we keep the host quirks(SDHCI_QUIRK_NO_1_8_V) to clear UHS speeds based on no-1-8-v from device tree. Hence revert the functionality related to no-1-8-v only, rest is fine in the patch. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Jaehoon Chung Reviewed-by: Peng Fan --- drivers/mmc/sdhci.c | 3 ++- drivers/mmc/zynq_sdhci.c | 5 +++++ include/sdhci.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d549a264d73..06289343124 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -812,7 +812,8 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } - if (!(cfg->voltages & MMC_VDD_165_195)) + 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); diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 775c17baac5..88e478ee11c 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -28,6 +28,7 @@ struct arasan_sdhci_priv { struct sdhci_host *host; u8 deviceid; u8 bank; + u8 no_1p8; }; #if defined(CONFIG_ARCH_ZYNQMP) @@ -236,6 +237,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; + plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ; ret = mmc_of_parse(dev, &plat->cfg); @@ -277,6 +281,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1); priv->bank = dev_read_u32_default(dev, "xlnx,mio-bank", 0); + priv->no_1p8 = dev_read_bool(dev, "no-1-8-v"); return 0; } diff --git a/include/sdhci.h b/include/sdhci.h index f69d5f81fb1..1fd20ec0860 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -244,6 +244,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 17a42abb40dd006b5f0e96d69e4894bef4c04ba8 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:58:58 -0600 Subject: [PATCH 63/71] mmc: Define timing macro's Define timing macro's for all the available speeds of mmc. This is done similar to linux. Replace speed macro's used with these new timing macro's wherever applicable. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan --- board/xilinx/zynqmp/tap_delays.c | 10 +--------- drivers/mmc/zynq_sdhci.c | 24 +++++++++++------------- include/mmc.h | 13 +++++++++++++ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/board/xilinx/zynqmp/tap_delays.c b/board/xilinx/zynqmp/tap_delays.c index 5fde0aed7db..13683701f64 100644 --- a/board/xilinx/zynqmp/tap_delays.c +++ b/board/xilinx/zynqmp/tap_delays.c @@ -8,6 +8,7 @@ #include #include #include +#include #define SD_DLL_CTRL 0xFF180358 #define SD_ITAP_DLY 0xFF180314 @@ -54,15 +55,6 @@ #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 */ diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 88e478ee11c..4f62bd008d2 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -32,20 +32,18 @@ struct arasan_sdhci_priv { }; #if defined(CONFIG_ARCH_ZYNQMP) -#define MMC_HS200_BUS_SPEED 5 - static const u8 mode2timing[] = { - [MMC_LEGACY] = UHS_SDR12_BUS_SPEED, - [MMC_HS] = HIGH_SPEED_BUS_SPEED, - [SD_HS] = HIGH_SPEED_BUS_SPEED, - [MMC_HS_52] = HIGH_SPEED_BUS_SPEED, - [MMC_DDR_52] = HIGH_SPEED_BUS_SPEED, - [UHS_SDR12] = UHS_SDR12_BUS_SPEED, - [UHS_SDR25] = UHS_SDR25_BUS_SPEED, - [UHS_SDR50] = UHS_SDR50_BUS_SPEED, - [UHS_DDR50] = UHS_DDR50_BUS_SPEED, - [UHS_SDR104] = UHS_SDR104_BUS_SPEED, - [MMC_HS_200] = MMC_HS200_BUS_SPEED, + [MMC_LEGACY] = MMC_TIMING_LEGACY, + [MMC_HS] = MMC_TIMING_MMC_HS, + [SD_HS] = MMC_TIMING_SD_HS, + [MMC_HS_52] = MMC_TIMING_UHS_SDR50, + [MMC_DDR_52] = MMC_TIMING_UHS_DDR50, + [UHS_SDR12] = MMC_TIMING_UHS_SDR12, + [UHS_SDR25] = MMC_TIMING_UHS_SDR25, + [UHS_SDR50] = MMC_TIMING_UHS_SDR50, + [UHS_DDR50] = MMC_TIMING_UHS_DDR50, + [UHS_SDR104] = MMC_TIMING_UHS_SDR104, + [MMC_HS_200] = MMC_TIMING_MMC_HS200, }; #define SDHCI_TUNING_LOOP_COUNT 40 diff --git a/include/mmc.h b/include/mmc.h index ac7b54f1a7e..1d377e0281f 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -360,6 +360,19 @@ enum mmc_voltage { #define MMC_NUM_BOOT_PARTITION 2 #define MMC_PART_RPMB 3 /* RPMB partition number */ +/* timing specification used */ +#define MMC_TIMING_LEGACY 0 +#define MMC_TIMING_MMC_HS 1 +#define MMC_TIMING_SD_HS 2 +#define MMC_TIMING_UHS_SDR12 3 +#define MMC_TIMING_UHS_SDR25 4 +#define MMC_TIMING_UHS_SDR50 5 +#define MMC_TIMING_UHS_SDR104 6 +#define MMC_TIMING_UHS_DDR50 7 +#define MMC_TIMING_MMC_DDR52 8 +#define MMC_TIMING_MMC_HS200 9 +#define MMC_TIMING_MMC_HS400 10 + /* Driver model support */ /** From 9851f50d3d8e8a933a072b11f7f497846b068fb8 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Oct 2020 04:58:59 -0600 Subject: [PATCH 64/71] mmc: zynq_sdhci: Move macro to the top Just group macros below headers. Other patches will be using this location too. Signed-off-by: Michal Simek Signed-off-by: Ashok Reddy Soma Reviewed-by: Peng Fan Reviewed-by: Jaehoon Chung --- drivers/mmc/zynq_sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 4f62bd008d2..998a3845068 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -19,6 +19,8 @@ #include #include +#define SDHCI_TUNING_LOOP_COUNT 40 + struct arasan_sdhci_plat { struct mmc_config cfg; struct mmc mmc; @@ -46,8 +48,6 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_TIMING_MMC_HS200, }; -#define SDHCI_TUNING_LOOP_COUNT 40 - static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) { u16 clk; From 80355ae40dfceb2304ed287846a3d3292e65d323 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 23 Oct 2020 04:59:00 -0600 Subject: [PATCH 65/71] mmc: zynq_sdhci: Read clock phase delays from dt Define input and output clock phase delays with pre-defined values. Define arasan_sdhci_clk_data type structure and add it to priv structure and store these clock phase delays in it. Read input and output clock phase delays from dt. If these values are not passed through dt, use pre-defined values. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan Reviewed-by: Jaehoon Chung --- drivers/mmc/zynq_sdhci.c | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 998a3845068..e69f375cce0 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -20,6 +20,12 @@ #include #define SDHCI_TUNING_LOOP_COUNT 40 +#define MMC_BANK2 0x2 + +struct arasan_sdhci_clk_data { + int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; + int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; +}; struct arasan_sdhci_plat { struct mmc_config cfg; @@ -28,12 +34,17 @@ struct arasan_sdhci_plat { struct arasan_sdhci_priv { struct sdhci_host *host; + struct arasan_sdhci_clk_data clk_data; u8 deviceid; u8 bank; u8 no_1p8; }; #if defined(CONFIG_ARCH_ZYNQMP) +/* Default settings for ZynqMP Clock Phases */ +const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0}; +const u32 zynqmp_oclk_phases[] = {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}; + static const u8 mode2timing[] = { [MMC_LEGACY] = MMC_TIMING_LEGACY, [MMC_HS] = MMC_TIMING_MMC_HS, @@ -168,6 +179,79 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) priv->bank); } +static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing, + const char *prop) +{ + struct arasan_sdhci_priv *priv = dev_get_priv(dev); + struct arasan_sdhci_clk_data *clk_data = &priv->clk_data; + u32 clk_phase[2] = {0}; + + /* + * Read Tap Delay values from DT, if the DT does not contain the + * Tap Values then use the pre-defined values + */ + if (dev_read_u32_array(dev, prop, &clk_phase[0], 2)) { + dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", + prop, clk_data->clk_phase_in[timing], + clk_data->clk_phase_out[timing]); + return; + } + + /* The values read are Input and Output Clock Delays in order */ + clk_data->clk_phase_in[timing] = clk_phase[0]; + clk_data->clk_phase_out[timing] = clk_phase[1]; +} + +/** + * arasan_dt_parse_clk_phases - Read Tap Delay values from DT + * + * Called at initialization to parse the values of Tap Delays. + * + * @dev: Pointer to our struct udevice. + */ +static void arasan_dt_parse_clk_phases(struct udevice *dev) +{ + struct arasan_sdhci_priv *priv = dev_get_priv(dev); + struct arasan_sdhci_clk_data *clk_data = &priv->clk_data; + int i; + + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && + device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { + clk_data->clk_phase_in[i] = zynqmp_iclk_phases[i]; + clk_data->clk_phase_out[i] = zynqmp_oclk_phases[i]; + } + + if (priv->bank == MMC_BANK2) { + clk_data->clk_phase_out[MMC_TIMING_UHS_SDR104] = 90; + clk_data->clk_phase_out[MMC_TIMING_MMC_HS200] = 90; + } + } + + arasan_dt_read_clk_phase(dev, MMC_TIMING_LEGACY, + "clk-phase-legacy"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS, + "clk-phase-mmc-hs"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_SD_HS, + "clk-phase-sd-hs"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR12, + "clk-phase-uhs-sdr12"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR25, + "clk-phase-uhs-sdr25"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR50, + "clk-phase-uhs-sdr50"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR104, + "clk-phase-uhs-sdr104"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_DDR50, + "clk-phase-uhs-ddr50"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_DDR52, + "clk-phase-mmc-ddr52"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS200, + "clk-phase-mmc-hs200"); + arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS400, + "clk-phase-mmc-hs400"); +} + static void arasan_sdhci_set_control_reg(struct sdhci_host *host) { struct mmc *mmc = (struct mmc *)host->mmc; @@ -271,6 +355,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) #if defined(CONFIG_ARCH_ZYNQMP) priv->host->ops = &arasan_ops; + arasan_dt_parse_clk_phases(dev); #endif priv->host->ioaddr = (void *)dev_read_addr(dev); From f4b297bbfde3ab53e5682ff779a13c61c6e12b37 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:59:01 -0600 Subject: [PATCH 66/71] mmc: zynq_sdhci: Set tapdelays based on clk phase delays Define and use functions for setting input and output tapdelays based on clk phase delays. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan Reviewed-by: Jaehoon Chung --- drivers/mmc/zynq_sdhci.c | 130 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e69f375cce0..8871765711d 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -166,17 +166,135 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) return 0; } -static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) +/** + * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays + * + * Set the SD Output Clock Tap Delays for Output path + * + * @host: Pointer to the sdhci_host structure. + * @degrees: The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host, + int degrees) { struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); struct mmc *mmc = (struct mmc *)host->mmc; - u8 uhsmode; + u8 tap_delay, tap_max = 0; + int ret; + int timing = mode2timing[mmc->selected_mode]; - uhsmode = mode2timing[mmc->selected_mode]; + /* + * This is applicable for SDHCI_SPEC_300 and above + * ZynqMP does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 || + timing == MMC_TIMING_LEGACY || + timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; - if (uhsmode >= UHS_SDR25_BUS_SPEED) - arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode, - priv->bank); + switch (timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 30 Taps are available */ + tap_max = 30; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 15 Taps are available */ + tap_max = 15; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 8 Taps are available */ + tap_max = 8; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + arasan_zynqmp_set_tapdelay(priv->deviceid, 0, tap_delay); + + return ret; +} + +/** + * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays + * + * Set the SD Input Clock Tap Delays for Input path + * + * @host: Pointer to the sdhci_host structure. + * @degrees: The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host, + int degrees) +{ + struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); + struct mmc *mmc = (struct mmc *)host->mmc; + u8 tap_delay, tap_max = 0; + int ret; + int timing = mode2timing[mmc->selected_mode]; + + /* + * This is applicable for SDHCI_SPEC_300 and above + * ZynqMP does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 || + timing == MMC_TIMING_LEGACY || + timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; + + switch (timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 120 Taps are available */ + tap_max = 120; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 60 Taps are available */ + tap_max = 60; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 30 Taps are available */ + tap_max = 30; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + arasan_zynqmp_set_tapdelay(priv->deviceid, tap_delay, 0); + + return ret; +} + +static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) +{ + struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); + struct arasan_sdhci_clk_data *clk_data = &priv->clk_data; + struct mmc *mmc = (struct mmc *)host->mmc; + struct udevice *dev = mmc->dev; + u8 timing = mode2timing[mmc->selected_mode]; + u32 iclk_phase = clk_data->clk_phase_in[timing]; + u32 oclk_phase = clk_data->clk_phase_out[timing]; + + dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing); + + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && + device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); + sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase); + } } static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing, From 2e819a77b9f5c011fd4ec9ac575494f9b77b1ac7 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:59:02 -0600 Subject: [PATCH 67/71] mmc: zynq_sdhci: Add clock phase delays for Versal Define default values for input and output clock phase delays for Versal. Also define functions for setting tapdelays based on these clock phase delays. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan Reviewed-by: Jaehoon Chung --- drivers/mmc/zynq_sdhci.c | 160 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 8871765711d..d55ba74b2c3 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -19,6 +19,12 @@ #include #include +#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 +#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC +#define SDHCI_ITAPDLY_CHGWIN 0x200 +#define SDHCI_ITAPDLY_ENABLE 0x100 +#define SDHCI_OTAPDLY_ENABLE 0x40 + #define SDHCI_TUNING_LOOP_COUNT 40 #define MMC_BANK2 0x2 @@ -40,11 +46,15 @@ struct arasan_sdhci_priv { u8 no_1p8; }; -#if defined(CONFIG_ARCH_ZYNQMP) +#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) /* Default settings for ZynqMP Clock Phases */ const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0}; const u32 zynqmp_oclk_phases[] = {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}; +/* Default settings for Versal Clock Phases */ +const u32 versal_iclk_phases[] = {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}; +const u32 versal_oclk_phases[] = {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0}; + static const u8 mode2timing[] = { [MMC_LEGACY] = MMC_TIMING_LEGACY, [MMC_HS] = MMC_TIMING_MMC_HS, @@ -278,6 +288,138 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host, return ret; } +/** + * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays + * + * Set the SD Output Clock Tap Delays for Output path + * + * @host: Pointer to the sdhci_host structure. + * @degrees The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_versal_sdcardclk_set_phase(struct sdhci_host *host, + int degrees) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u8 tap_delay, tap_max = 0; + int ret; + int timing = mode2timing[mmc->selected_mode]; + + /* + * This is applicable for SDHCI_SPEC_300 and above + * Versal does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 || + timing == MMC_TIMING_LEGACY || + timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; + + switch (timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 30 Taps are available */ + tap_max = 30; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 15 Taps are available */ + tap_max = 15; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 8 Taps are available */ + tap_max = 8; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + u32 regval; + + regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); + regval |= SDHCI_OTAPDLY_ENABLE; + sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); + regval |= tap_delay; + sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); + } + + return ret; +} + +/** + * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays + * + * Set the SD Input Clock Tap Delays for Input path + * + * @host: Pointer to the sdhci_host structure. + * @degrees The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_versal_sampleclk_set_phase(struct sdhci_host *host, + int degrees) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u8 tap_delay, tap_max = 0; + int ret; + int timing = mode2timing[mmc->selected_mode]; + + /* + * This is applicable for SDHCI_SPEC_300 and above + * Versal does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 || + timing == MMC_TIMING_LEGACY || + timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; + + switch (timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 120 Taps are available */ + tap_max = 120; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 60 Taps are available */ + tap_max = 60; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 30 Taps are available */ + tap_max = 30; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + u32 regval; + + regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= SDHCI_ITAPDLY_CHGWIN; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= SDHCI_ITAPDLY_ENABLE; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= tap_delay; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval &= ~SDHCI_ITAPDLY_CHGWIN; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + } + + return ret; +} + static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) { struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev); @@ -294,6 +436,10 @@ static void arasan_sdhci_set_tapdelay(struct sdhci_host *host) device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase); + } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) && + device_is_compatible(dev, "xlnx,versal-8.9a")) { + sdhci_versal_sampleclk_set_phase(host, iclk_phase); + sdhci_versal_sdcardclk_set_phase(host, oclk_phase); } } @@ -346,6 +492,14 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) } } + if (IS_ENABLED(CONFIG_ARCH_VERSAL) && + device_is_compatible(dev, "xlnx,versal-8.9a")) { + for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { + clk_data->clk_phase_in[i] = versal_iclk_phases[i]; + clk_data->clk_phase_out[i] = versal_oclk_phases[i]; + } + } + arasan_dt_read_clk_phase(dev, MMC_TIMING_LEGACY, "clk-phase-legacy"); arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS, @@ -388,9 +542,7 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) mmc->selected_mode <= UHS_DDR50) sdhci_set_uhs_timing(host); } -#endif -#if defined(CONFIG_ARCH_ZYNQMP) const struct sdhci_ops arasan_ops = { .platform_execute_tuning = &arasan_sdhci_execute_tuning, .set_delay = &arasan_sdhci_set_tapdelay, @@ -471,7 +623,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) priv->host->name = dev->name; -#if defined(CONFIG_ARCH_ZYNQMP) +#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) priv->host->ops = &arasan_ops; arasan_dt_parse_clk_phases(dev); #endif From d3d880b41a7cd72d2cdf5656ea2dd108a81560b6 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:59:03 -0600 Subject: [PATCH 68/71] mmc: zynq_sdhci: Extend UHS timings till hs200 Fix the condition to set UHS timings for speeds upto HS200. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan Reviewed-by: Jaehoon Chung --- drivers/mmc/zynq_sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index d55ba74b2c3..147ecc0d708 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -539,7 +539,7 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) } if (mmc->selected_mode > SD_HS && - mmc->selected_mode <= UHS_DDR50) + mmc->selected_mode <= MMC_HS_200) sdhci_set_uhs_timing(host); } From 728d21b8c75e3c13a19b4a555d08a4478efa8fe6 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 23 Oct 2020 04:59:04 -0600 Subject: [PATCH 69/71] mmc: zynq_sdhci: Add common function to set input/output tapdelays Remove setting tapdelays for different speeds separately. Instead use the ITAP and OTAP delay values which are read from the device tree. If the DT does not contain tap delay values, the predefined values will be used for the same. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Peng Fan --- board/xilinx/zynqmp/tap_delays.c | 198 ++++++------------------------- include/zynqmp_tap_delay.h | 5 +- 2 files changed, 40 insertions(+), 163 deletions(-) diff --git a/board/xilinx/zynqmp/tap_delays.c b/board/xilinx/zynqmp/tap_delays.c index 13683701f64..1cab25f00a5 100644 --- a/board/xilinx/zynqmp/tap_delays.c +++ b/board/xilinx/zynqmp/tap_delays.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -26,34 +27,9 @@ #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 void zynqmp_dll_reset(u8 deviceid) { @@ -74,149 +50,49 @@ void zynqmp_dll_reset(u8 deviceid) zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0); } -static void arasan_zynqmp_tap_sdr104(u8 deviceid, u8 timing, u8 bank) +void arasan_zynqmp_set_tapdelay(u8 deviceid, u32 itap_delay, u32 otap_delay) { 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 + /* Program ITAP */ + if (itap_delay) { + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, + SD0_ITAPCHGWIN); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK, + SD0_ITAPDLYENA); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK, + itap_delay); + zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, + 0x0); + } + + /* Program OTAP */ + if (otap_delay) + zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, + otap_delay); + + zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0); + } else { zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, SD1_DLL_RST); + /* Program ITAP */ + if (itap_delay) { + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, + SD1_ITAPCHGWIN); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK, + SD1_ITAPDLYENA); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK, + (itap_delay << 16)); + zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, + 0x0); + } - 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; - } + /* Program OTAP */ + if (otap_delay) + zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK, + (otap_delay << 16)); - 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/include/zynqmp_tap_delay.h b/include/zynqmp_tap_delay.h index b07e3e06922..7b713438f75 100644 --- a/include/zynqmp_tap_delay.h +++ b/include/zynqmp_tap_delay.h @@ -10,10 +10,11 @@ #ifdef CONFIG_ARCH_ZYNQMP void zynqmp_dll_reset(u8 deviceid); -void arasan_zynqmp_set_tapdelay(u8 device_id, u8 uhsmode, u8 bank); +void arasan_zynqmp_set_tapdelay(u8 device_id, u32 itap_delay, u32 otap_delay); #else inline void zynqmp_dll_reset(u8 deviceid) {} -inline void arasan_zynqmp_set_tapdelay(u8 device_id, u8 uhsmode, u8 bank) {} +inline void arasan_zynqmp_set_tapdelay(u8 device_id, u32 itap_delay, + u32 otap_delay) {} #endif #endif From 05af4834ad6b78377cb5eb50659a5d08b83e3813 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 26 Oct 2020 12:26:13 +0100 Subject: [PATCH 70/71] xilinx: Consolidate board_fit_config_name_match() for Xilinx platforms Move board_fit_config_name_match() from Zynq/ZynqMP to common location. This change will open a way to use it also by Microblaze and Versal. Through this function there is a way to handle images with multiple DTBs. For now match it with DEVICE_TREE as is done for Zynq. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/spl.c | 14 -------------- arch/arm/mach-zynqmp/spl.c | 10 ---------- board/xilinx/common/board.c | 11 +++++++++++ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index cb8cfd2f353..d09141c3bc7 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -86,16 +85,3 @@ void spl_board_prepare_for_boot(void) ps7_post_config(); debug("SPL bye\n"); } - -#ifdef CONFIG_SPL_LOAD_FIT -int board_fit_config_name_match(const char *name) -{ - /* Just empty function now - can't decide what to choose */ - debug("%s: Check %s, default %s\n", __func__, name, DEVICE_TREE); - - if (!strcmp(name, DEVICE_TREE)) - return 0; - - return -1; -} -#endif diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c index 9dd61e25f6f..88386b23e5d 100644 --- a/arch/arm/mach-zynqmp/spl.c +++ b/arch/arm/mach-zynqmp/spl.c @@ -119,13 +119,3 @@ int spl_start_uboot(void) return 0; } #endif - -#ifdef CONFIG_SPL_LOAD_FIT -int board_fit_config_name_match(const char *name) -{ - /* Just empty function now - can't decide what to choose */ - debug("%s: %s\n", __func__, name); - - return -1; -} -#endif diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index bcdd3ae4f14..cdc06a39ce5 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "fru.h" @@ -425,3 +426,13 @@ int board_late_init_xilinx(void) return 0; } #endif + +int __maybe_unused board_fit_config_name_match(const char *name) +{ + debug("%s: Check %s, default %s\n", __func__, name, DEVICE_TREE); + + if (!strcmp(name, DEVICE_TREE)) + return 0; + + return -1; +} From 908daf86f96a44176ecd1e04f1ec71e143aa45f5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 27 Oct 2020 10:04:17 +0100 Subject: [PATCH 71/71] xilinx: Enable SPI driver for Versal Enable Zynq SPI driver for Versal. Signed-off-by: Michal Simek --- configs/xilinx_versal_virt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index 40a8cfd5ccc..7291c51c2dc 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -86,6 +86,7 @@ CONFIG_PL01X_SERIAL=y CONFIG_XILINX_UARTLITE=y CONFIG_SPI=y CONFIG_DM_SPI=y +CONFIG_ZYNQ_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y