From 49df685d32593fa5b28ab56d7283220c77098ce6 Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Thu, 2 Jun 2022 22:27:06 +0200 Subject: [PATCH 01/22] ARM: dts: omap3-devkit8000: Add support for Devkit8000 This commit adds OMAP3 BeagleBoard devicetree files from Linux v5.16.0. This commit fixes CONFIG_DM_MMC warning. v3: patch clean-up Signed-off-by: Anthoine Bourgeois --- arch/arm/dts/Makefile | 2 + arch/arm/dts/omap3-devkit8000-u-boot.dtsi | 14 + arch/arm/dts/omap3-devkit8000.dts | 349 ++++++++++++++++++++++ configs/devkit8000_defconfig | 21 +- include/configs/devkit8000.h | 16 +- 5 files changed, 385 insertions(+), 17 deletions(-) create mode 100644 arch/arm/dts/omap3-devkit8000-u-boot.dtsi create mode 100644 arch/arm/dts/omap3-devkit8000.dts diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 85346c5e84..2fa3957162 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1069,6 +1069,8 @@ dtb-$(CONFIG_TARGET_OMAP3_BEAGLE) += \ omap3-beagle-xm.dtb \ omap3-beagle.dtb +dtb-$(CONFIG_TARGET_DEVKIT8000) += omap3-devkit8000.dtb + dtb-$(CONFIG_TARGET_OMAP3_IGEP00X0) += \ omap3-igep0020.dtb diff --git a/arch/arm/dts/omap3-devkit8000-u-boot.dtsi b/arch/arm/dts/omap3-devkit8000-u-boot.dtsi new file mode 100644 index 0000000000..2c03701c89 --- /dev/null +++ b/arch/arm/dts/omap3-devkit8000-u-boot.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * U-Boot additions + * + * (C) Copyright 2017 Derald D. Woods + */ + +#include "omap3-u-boot.dtsi" + +/ { + chosen { + stdout-path = &uart3; + }; +}; diff --git a/arch/arm/dts/omap3-devkit8000.dts b/arch/arm/dts/omap3-devkit8000.dts new file mode 100644 index 0000000000..eee3ba073b --- /dev/null +++ b/arch/arm/dts/omap3-devkit8000.dts @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Anthoine Bourgeois + */ +/dts-v1/; + +#include "omap34xx.dtsi" +/ { + model = "TimLL OMAP3 Devkit8000"; + compatible = "timll,omap3-devkit8000", "ti,omap3430", "ti,omap3"; + + aliases { + display1 = &dvi0; + display2 = &tv0; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x10000000>; /* 256 MB */ + }; + + leds { + compatible = "gpio-leds"; + + heartbeat { + label = "devkit8000::led1"; + gpios = <&gpio6 26 GPIO_ACTIVE_HIGH>; /* 186 -> LED1 */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + mmc { + label = "devkit8000::led2"; + gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 -> LED2 */ + default-state = "on"; + linux,default-trigger = "none"; + }; + + usr { + label = "devkit8000::led3"; + gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* 164 -> LED3 */ + default-state = "on"; + linux,default-trigger = "usr"; + }; + + pmu_stat { + label = "devkit8000::pmu_stat"; + gpios = <&twl_gpio 19 GPIO_ACTIVE_HIGH>; /* LEDB */ + }; + }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "devkit8000"; + + ti,mcbsp = <&mcbsp2>; + ti,audio-routing = + "Ext Spk", "PREDRIVEL", + "Ext Spk", "PREDRIVER", + "MAINMIC", "Main Mic", + "Main Mic", "Mic Bias 1"; + }; + + tfp410: encoder0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&twl_gpio 7 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint { + remote-endpoint = <&dpi_dvi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c2>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tv0: connector1 { + compatible = "svideo-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; + }; +}; + +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + codec { + }; + }; + }; +}; + +&i2c2 { + clock-frequency = <400000>; +}; + +&i2c3 { + status = "disabled"; +}; + +#include "twl4030.dtsi" +#include "twl4030_omap3.dtsi" + +&mmc1 { + vmmc-supply = <&vmmc1>; + vqmmc-supply = <&vsim>; + bus-width = <8>; +}; + +&mmc2 { + status = "disabled"; +}; + +&mmc3 { + status = "disabled"; +}; + +&twl_gpio { + ti,use-leds; + /* + * pulldowns: + * BIT(1), BIT(2), BIT(6), BIT(7), BIT(8), BIT(13) + * BIT(15), BIT(16), BIT(17) + */ + ti,pulldowns = <0x03a1c6>; +}; + +&wdt2 { + status = "disabled"; +}; + +&mcbsp2 { + status = "okay"; +}; + +&gpmc { + ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */ + 6 0 0x2c000000 0x1000000>; /* CS6: 16MB for DM9000 */ + + nand@0,0 { + compatible = "ti,omap2-nand"; + reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ + interrupt-parent = <&gpmc>; + interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ + <1 IRQ_TYPE_NONE>; /* termcount */ + nand-bus-width = <16>; + gpmc,device-width = <2>; + ti,nand-ecc-opt = "sw"; + + gpmc,sync-clk-ps = <0>; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <44>; + gpmc,cs-wr-off-ns = <44>; + gpmc,adv-on-ns = <6>; + gpmc,adv-rd-off-ns = <34>; + gpmc,adv-wr-off-ns = <44>; + gpmc,we-off-ns = <40>; + gpmc,oe-off-ns = <54>; + gpmc,access-ns = <64>; + gpmc,rd-cycle-ns = <82>; + gpmc,wr-cycle-ns = <82>; + gpmc,wr-access-ns = <40>; + gpmc,wr-data-mux-bus-ns = <0>; + + #address-cells = <1>; + #size-cells = <1>; + + x-loader@0 { + label = "X-Loader"; + reg = <0 0x80000>; + }; + + bootloaders@80000 { + label = "U-Boot"; + reg = <0x80000 0x1e0000>; + }; + + bootloaders_env@260000 { + label = "U-Boot Env"; + reg = <0x260000 0x20000>; + }; + + kernel@280000 { + label = "Kernel"; + reg = <0x280000 0x400000>; + }; + + filesystem@680000 { + label = "File System"; + reg = <0x680000 0xf980000>; + }; + }; + + ethernet@6,0 { + compatible = "davicom,dm9000"; + reg = <6 0x000 2 + 6 0x400 2>; /* CS6, offset 0 and 0x400, IO size 2 */ + bank-width = <2>; + interrupt-parent = <&gpio1>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + davicom,no-eeprom; + + gpmc,mux-add-data = <0>; + gpmc,device-width = <1>; + gpmc,wait-pin = <0>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + gpmc,cs-on-ns = <6>; + gpmc,cs-rd-off-ns = <180>; + gpmc,cs-wr-off-ns = <180>; + gpmc,adv-on-ns = <0>; + gpmc,adv-rd-off-ns = <18>; + gpmc,adv-wr-off-ns = <48>; + gpmc,oe-on-ns = <54>; + gpmc,oe-off-ns = <168>; + gpmc,we-on-ns = <54>; + gpmc,we-off-ns = <168>; + gpmc,rd-cycle-ns = <186>; + gpmc,wr-cycle-ns = <186>; + gpmc,access-ns = <144>; + gpmc,page-burst-access-ns = <24>; + gpmc,bus-turnaround-ns = <90>; + gpmc,cycle2cycle-delay-ns = <90>; + gpmc,wait-monitoring-ns = <0>; + gpmc,clk-activation-ns = <0>; + gpmc,wr-data-mux-bus-ns = <0>; + gpmc,wr-access-ns = <0>; + }; +}; + +&omap3_pmx_core { + dss_dpi_pins: pinmux_dss_dpi_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */ + OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */ + OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */ + OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */ + OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */ + OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */ + OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */ + OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */ + OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */ + OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */ + OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */ + OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */ + OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */ + OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */ + OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */ + OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */ + OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */ + OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */ + OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */ + OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */ + OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */ + OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */ + OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */ + OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */ + OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */ + OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */ + OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */ + OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */ + >; + }; +}; + +&vpll1 { + /* Needed for DSS */ + regulator-name = "vdds_dsi"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; + +&dss { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins>; + + vdds_dsi-supply = <&vpll1>; + vdda_dac-supply = <&vdac>; + + port { + #address-cells = <1>; + #size-cells = <0>; + dpi_dvi_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + + endpoint@1 { + reg = <1>; + }; + }; +}; + +&venc { + status = "okay"; + + vdda-supply = <&vdac>; + + port { + venc_out: endpoint { + remote-endpoint = <&tv_connector_in>; + ti,channels = <2>; + }; + }; +}; diff --git a/configs/devkit8000_defconfig b/configs/devkit8000_defconfig index 4e144a9c16..ecc3090486 100644 --- a/configs/devkit8000_defconfig +++ b/configs/devkit8000_defconfig @@ -2,21 +2,26 @@ CONFIG_ARM=y CONFIG_ARCH_OMAP2PLUS=y CONFIG_SYS_TEXT_BASE=0x80100000 CONFIG_SYS_MALLOC_LEN=0x40000 -CONFIG_SYS_MALLOC_F_LEN=0x400 +CONFIG_SYS_MALLOC_F_LEN=0x4000 CONFIG_NR_DRAM_BANKS=2 +CONFIG_DEFAULT_DEVICE_TREE="omap3-devkit8000" CONFIG_SPL_TEXT_BASE=0x40200000 CONFIG_TARGET_DEVKIT8000=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x400 CONFIG_SPL=y CONFIG_DISTRO_DEFAULTS=y CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x4020ff00 CONFIG_BOOTCOMMAND="run autoboot" +CONFIG_USE_PREBOOT=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_SPL_MAX_SIZE=0xec00 CONFIG_SPL_BSS_START_ADDR=0x80000500 +CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SYS_SPL_MALLOC=y CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x80208000 +# CONFIG_SPL_FS_EXT4 is not set CONFIG_SPL_NAND_DRIVERS=y CONFIG_SPL_NAND_ECC=y CONFIG_SPL_NAND_SIMPLE=y @@ -31,8 +36,8 @@ CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS=8 CONFIG_SYS_MAXARGS=64 # CONFIG_CMD_IMI is not set CONFIG_CMD_SPL=y -CONFIG_CMD_SPL_NAND_OFS=0x680000 -CONFIG_CMD_SPL_WRITE_SIZE=0x400 +CONFIG_CMD_SPL_NAND_OFS=0x280000 +CONFIG_CMD_SPL_WRITE_SIZE=0x20000 # CONFIG_CMD_FLASH is not set CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y @@ -50,12 +55,20 @@ CONFIG_JFFS2_PART_SIZE=0xF980000 CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nand0=nand" CONFIG_MTDPARTS_DEFAULT="mtdparts=nand:512k(x-loader),1920k(u-boot),128k(u-boot-env),4m(kernel),-(fs)" +# CONFIG_ISO_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_SPL_REMOVE_PROPS="clocks clock-names interrupt-parent" CONFIG_ENV_OVERWRITE=y CONFIG_ENV_IS_IN_NAND=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_VERSION_VARIABLE=y CONFIG_NET_RETRY_COUNT=20 CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_SPL_DM=y +CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_SPL_OF_TRANSLATE=y CONFIG_SYS_I2C_LEGACY=y CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_TWL4030_LED=y @@ -71,6 +84,4 @@ CONFIG_SYS_NAND_BUSWIDTH_16BIT=y CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y CONFIG_SYS_NAND_U_BOOT_OFFS=0x80000 CONFIG_DRIVER_DM9000=y -CONFIG_CONS_INDEX=3 CONFIG_JFFS2_NAND=y -CONFIG_OF_LIBFDT=y diff --git a/include/configs/devkit8000.h b/include/configs/devkit8000.h index 4e91f8caa3..d45115bdf6 100644 --- a/include/configs/devkit8000.h +++ b/include/configs/devkit8000.h @@ -14,17 +14,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -/* High Level Configuration Options */ - -/* - * 1MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM - * 64 bytes before this address should be set aside for u-boot.img's - * header. That is 0x800FFFC0--0x80100000 should not be used for any - * other needs. - */ - -/* Physical Memory Map */ - #include /* Hardware drivers */ @@ -40,9 +29,12 @@ /* BOOTP/DHCP options */ +#define MEM_LAYOUT_ENV_SETTINGS \ + DEFAULT_LINUX_BOOT_ENV + /* Environment information */ #define CONFIG_EXTRA_ENV_SETTINGS \ - "loadaddr=0x82000000\0" \ + MEM_LAYOUT_ENV_SETTINGS \ "console=ttyO2,115200n8\0" \ "mmcdev=0\0" \ "vram=12M\0" \ From 8d09c7b774af20660e5baae28210e92a20ffda04 Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Thu, 2 Jun 2022 22:27:07 +0200 Subject: [PATCH 02/22] ARM: dts: omap3-devkit8000: Fix CONFIG_DM_I2C warning Seems that u-boot can't probe i2c bus at 2.6Mhz speed, so lower the speed to the default value 100Khz. v2: fix i2c1 frequency in the root omap3-u-boot.dtsi include. Signed-off-by: Anthoine Bourgeois --- arch/arm/dts/omap3-u-boot.dtsi | 1 + configs/devkit8000_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/dts/omap3-u-boot.dtsi b/arch/arm/dts/omap3-u-boot.dtsi index 32bea6b6d9..96d8ac5453 100644 --- a/arch/arm/dts/omap3-u-boot.dtsi +++ b/arch/arm/dts/omap3-u-boot.dtsi @@ -78,4 +78,5 @@ &i2c1 { u-boot,dm-spl; + clock-frequency = <100000>; }; diff --git a/configs/devkit8000_defconfig b/configs/devkit8000_defconfig index ecc3090486..76371e3074 100644 --- a/configs/devkit8000_defconfig +++ b/configs/devkit8000_defconfig @@ -73,6 +73,7 @@ CONFIG_SYS_I2C_LEGACY=y CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_TWL4030_LED=y CONFIG_MMC_OMAP_HS=y +CONFIG_DM_I2C=y CONFIG_MTD=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_OMAP_ECCSCHEME_HAM1_CODE_HW=y From a47ce34403f27178c1264bf60496bbb9a21e5842 Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Thu, 2 Jun 2022 22:27:08 +0200 Subject: [PATCH 03/22] ARM: dts: omap3-devkit8000: Fix CONFIG_DM_ETH warning Add the missing ethernet node in u-boot dts. Signed-off-by: Anthoine Bourgeois --- arch/arm/dts/omap3-devkit8000-u-boot.dtsi | 6 ++++++ configs/devkit8000_defconfig | 1 + 2 files changed, 7 insertions(+) diff --git a/arch/arm/dts/omap3-devkit8000-u-boot.dtsi b/arch/arm/dts/omap3-devkit8000-u-boot.dtsi index 2c03701c89..a5768b7281 100644 --- a/arch/arm/dts/omap3-devkit8000-u-boot.dtsi +++ b/arch/arm/dts/omap3-devkit8000-u-boot.dtsi @@ -11,4 +11,10 @@ chosen { stdout-path = &uart3; }; + + ethernet@2c000000 { + compatible = "davicom,dm9000"; + reg = <0x2c000000 2 0x2c000400 2>; + bank-width = <2>; + }; }; diff --git a/configs/devkit8000_defconfig b/configs/devkit8000_defconfig index 76371e3074..a5e9f614df 100644 --- a/configs/devkit8000_defconfig +++ b/configs/devkit8000_defconfig @@ -84,5 +84,6 @@ CONFIG_SYS_NAND_OOBSIZE=0x40 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y CONFIG_SYS_NAND_U_BOOT_OFFS=0x80000 +CONFIG_DM_ETH=y CONFIG_DRIVER_DM9000=y CONFIG_JFFS2_NAND=y From bfef72e4dd1c1d6dfc680867bf24a78597ab0438 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Wed, 11 May 2022 10:55:40 +0100 Subject: [PATCH 04/22] cmd: load: add load command for memory mapped cp.b is used a lot as a way to load binaries to memory and execute them, however we may need to integrate this with the efi subsystem to set it up as a bootdev. So, introduce a loadm command that will be consistent with the other loadX commands and will call the efi API's. ex: loadm $kernel_addr $kernel_addr_r $kernel_size with this a kernel with CONFIG_EFI_STUB enabled will be loaded and then subsequently booted with bootefi command. Signed-off-by: Rui Miguel Silva Reviewed-by: Tom Rini --- README | 1 + cmd/Kconfig | 5 +++ cmd/bootefi.c | 12 ++++++ cmd/load.c | 48 +++++++++++++++++++++ configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + doc/usage/cmd/loadm.rst | 49 ++++++++++++++++++++++ doc/usage/index.rst | 1 + include/efi_loader.h | 2 + include/test/suites.h | 1 + lib/efi_loader/efi_device_path.c | 9 ++++ test/cmd/Makefile | 1 + test/cmd/loadm.c | 72 ++++++++++++++++++++++++++++++++ test/cmd_ut.c | 6 +++ 14 files changed, 209 insertions(+) create mode 100644 doc/usage/cmd/loadm.rst create mode 100644 test/cmd/loadm.c diff --git a/README b/README index 9800359e5d..f3304229d8 100644 --- a/README +++ b/README @@ -2415,6 +2415,7 @@ rarpboot- boot image via network using RARP/TFTP protocol diskboot- boot from IDE devicebootd - boot default, i.e., run 'bootcmd' loads - load S-Record file over serial line loadb - load binary file over serial line (kermit mode) +loadm - load binary blob from source address to destination address md - memory display mm - memory modify (auto-incrementing) nm - memory modify (constant address) diff --git a/cmd/Kconfig b/cmd/Kconfig index 9a0b720311..dea3729d13 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1160,6 +1160,11 @@ config CMD_LOADB help Load a binary file over serial line. +config CMD_LOADM + bool "loadm" + help + Load a binary over memory mapped. + config CMD_LOADS bool "loads" default y diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 827fcd97df..37ce659fa1 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -34,6 +34,18 @@ static struct efi_device_path *bootefi_device_path; static void *image_addr; static size_t image_size; +/** + * efi_get_image_parameters() - return image parameters + * + * @img_addr: address of loaded image in memory + * @img_size: size of loaded image + */ +void efi_get_image_parameters(void **img_addr, size_t *img_size) +{ + *img_addr = image_addr; + *img_size = image_size; +} + /** * efi_clear_bootdev() - clear boot device */ diff --git a/cmd/load.c b/cmd/load.c index 7e4a552d90..1224a7f85b 100644 --- a/cmd/load.c +++ b/cmd/load.c @@ -1063,6 +1063,44 @@ static ulong load_serial_ymodem(ulong offset, int mode) #endif +#if defined(CONFIG_CMD_LOADM) +static int do_load_memory_bin(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr, dest, size; + void *src, *dst; + + if (argc != 4) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + + dest = simple_strtoul(argv[2], NULL, 16); + + size = simple_strtoul(argv[3], NULL, 16); + + if (!size) { + printf("loadm: can not load zero bytes\n"); + return 1; + } + + src = map_sysmem(addr, size); + dst = map_sysmem(dest, size); + + memcpy(dst, src, size); + + unmap_sysmem(src); + unmap_sysmem(dst); + + if (IS_ENABLED(CONFIG_CMD_BOOTEFI)) + efi_set_bootdev("Mem", "", "", map_sysmem(dest, 0), size); + + printf("loaded bin to memory: size: %lu\n", size); + + return 0; +} +#endif + /* -------------------------------------------------------------------- */ #if defined(CONFIG_CMD_LOADS) @@ -1137,3 +1175,13 @@ U_BOOT_CMD( ); #endif /* CONFIG_CMD_LOADB */ + +#if defined(CONFIG_CMD_LOADM) +U_BOOT_CMD( + loadm, 4, 0, do_load_memory_bin, + "load binary blob from source address to destination address", + "[src_addr] [dst_addr] [size]\n" + " - load a binary blob from one memory location to other" + " from src_addr to dst_addr by size bytes" +); +#endif /* CONFIG_CMD_LOADM */ diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 9d72e39bc2..46a9b16ad3 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -47,6 +47,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y +CONFIG_CMD_LOADM=y CONFIG_CMD_OSD=y CONFIG_CMD_PCI=y CONFIG_CMD_READ=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index be40562cc3..86204c7908 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -67,6 +67,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y +CONFIG_CMD_LOADM=y CONFIG_CMD_LSBLK=y CONFIG_CMD_MUX=y CONFIG_CMD_OSD=y diff --git a/doc/usage/cmd/loadm.rst b/doc/usage/cmd/loadm.rst new file mode 100644 index 0000000000..b657114043 --- /dev/null +++ b/doc/usage/cmd/loadm.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +loadm command +============= + +Synopsis +-------- + +:: + + loadm + +Description +----------- + +The loadm command is used to copy memory content from source address +to destination address and, if efi is enabled, will setup a "Mem" efi +boot device. + +The number of transferred bytes must be set by bytes parameter + +src_addr + start address of the memory location to be loaded + +dst_addr + destination address of the byte stream to be loaded + +len + number of bytes to be copied in hexadecimal. Can not be 0 (zero). + +Example +------- + +:: + + => loadm ${kernel_addr} ${kernel_addr_r} ${kernel_size} + loaded bin to memory: size: 12582912 + +Configuration +------------- + +The command is only available if CONFIG_CMD_LOADM=y. + +Return value +------------ + +The return value $? is set 0 (true) if the loading is succefull, and +is set to 1 (false) in case of error. + diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 770418434a..8d08ea14b0 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -44,6 +44,7 @@ Shell commands cmd/fatload cmd/for cmd/load + cmd/loadm cmd/loady cmd/mbr cmd/md diff --git a/include/efi_loader.h b/include/efi_loader.h index c1e00ebac3..31de191e3d 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -591,6 +591,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void efi_save_gd(void); /* Call this to relocate the runtime section to an address space */ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); +/* Call this to get image parameters */ +void efi_get_image_parameters(void **img_addr, size_t *img_size); /* Add a new object to the object list. */ void efi_add_handle(efi_handle_t obj); /* Create handle */ diff --git a/include/test/suites.h b/include/test/suites.h index ee6858a802..ddb8827fdb 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -39,6 +39,7 @@ int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc, int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]); int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 171661b897..2493d74326 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -1158,6 +1158,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, { struct blk_desc *desc = NULL; struct disk_partition fs_partition; + size_t image_size; + void *image_addr; int part = 0; char *filename; char *s; @@ -1173,6 +1175,13 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, } else if (!strcmp(dev, "Uart")) { if (device) *device = efi_dp_from_uart(); + } else if (!strcmp(dev, "Mem")) { + efi_get_image_parameters(&image_addr, &image_size); + + if (device) + *device = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, + (uintptr_t)image_addr, + image_size); } else { part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); diff --git a/test/cmd/Makefile b/test/cmd/Makefile index a59adb1e6d..4b2d7df0d2 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_CONSOLE_RECORD) += test_echo.o endif obj-y += mem.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o +obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PWM) += pwm.o diff --git a/test/cmd/loadm.c b/test/cmd/loadm.c new file mode 100644 index 0000000000..41e005ac59 --- /dev/null +++ b/test/cmd/loadm.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for loadm command + * + * Copyright 2022 ARM Limited + * Copyright 2022 Linaro + * + * Authors: + * Rui Miguel Silva + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 0x100 + +#define LOADM_TEST(_name, _flags) UNIT_TEST(_name, _flags, loadm_test) + +static int loadm_test_params(struct unit_test_state *uts) +{ + ut_assertok(console_record_reset_enable()); + run_command("loadm", 0); + ut_assert_nextline("loadm - load binary blob from source address to destination address"); + + ut_assertok(console_record_reset_enable()); + run_command("loadm 0x12345678", 0); + ut_assert_nextline("loadm - load binary blob from source address to destination address"); + + ut_assertok(console_record_reset_enable()); + run_command("loadm 0x12345678 0x12345678", 0); + ut_assert_nextline("loadm - load binary blob from source address to destination address"); + + ut_assertok(console_record_reset_enable()); + run_command("loadm 0x12345678 0x12345678 0", 0); + ut_assert_nextline("loadm: can not load zero bytes"); + + return 0; +} +LOADM_TEST(loadm_test_params, UT_TESTF_CONSOLE_REC); + +static int loadm_test_load (struct unit_test_state *uts) +{ + char *buf; + + buf = map_sysmem(0, BUF_SIZE); + memset(buf, '\0', BUF_SIZE); + memset(buf, 0xaa, BUF_SIZE / 2); + + ut_assertok(console_record_reset_enable()); + run_command("loadm 0x0 0x80 0x80", 0); + ut_assert_nextline("loaded bin to memory: size: 128"); + + unmap_sysmem(buf); + + return 0; +} +LOADM_TEST(loadm_test_load, UT_TESTF_CONSOLE_REC); + +int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(loadm_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(loadm_test); + + return cmd_ut_category("loadm", "loadm_test_", tests, n_ents, argc, + argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 67a13ee32b..d70b72678a 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -74,6 +74,9 @@ static struct cmd_tbl cmd_ut_sub[] = { #ifdef CONFIG_CMD_ADDRMAP U_BOOT_CMD_MKENT(addrmap, CONFIG_SYS_MAXARGS, 1, do_ut_addrmap, "", ""), #endif +#ifdef CONFIG_CMD_LOADM + U_BOOT_CMD_MKENT(loadm, CONFIG_SYS_MAXARGS, 1, do_ut_loadm, "", ""), +#endif }; static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, @@ -155,6 +158,9 @@ static char ut_help_text[] = #endif #ifdef CONFIG_CMD_ADDRMAP "ut addrmap - Very basic test of addrmap command\n" +#endif +#ifdef CONFIG_CMD_LOADM + "ut loadm [test-name]- test of parameters and load memory blob\n" #endif ; #endif /* CONFIG_SYS_LONGHELP */ From f98457d70a35ad6bda284577a8a2a8ad7868b13b Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Wed, 11 May 2022 10:55:41 +0100 Subject: [PATCH 05/22] arm: add support to corstone1000 platform Corstone1000 is a platform from arm, which includes pre verified Corstone SSE710 sub-system that combines Cortex-A and Cortex-M processors [0]. This code adds the support for the Cortex-A35 implementation at host side, it contains also the necessary bits to support the Corstone 1000 FVP (Fixed Virtual Platform) [1] and also the FPGA MPS3 board implementation of this platform. [2] 0: https://developer.arm.com/documentation/102360/0000 1: https://developer.arm.com/tools-and-software/open-source-software/arm-platforms-software/arm-ecosystem-fvps 2: https://developer.arm.com/documentation/dai0550/c/ Signed-off-by: Rui Miguel Silva Reviewed-by: Tom Rini --- arch/arm/Kconfig | 8 +- arch/arm/dts/Makefile | 3 + arch/arm/dts/corstone1000-fvp.dts | 51 +++++++ arch/arm/dts/corstone1000-mps3.dts | 32 +++++ arch/arm/dts/corstone1000.dtsi | 164 +++++++++++++++++++++++ board/armltd/corstone1000/Kconfig | 12 ++ board/armltd/corstone1000/MAINTAINERS | 7 + board/armltd/corstone1000/Makefile | 7 + board/armltd/corstone1000/corstone1000.c | 91 +++++++++++++ configs/corstone1000_defconfig | 52 +++++++ include/configs/corstone1000.h | 41 ++++++ 11 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/corstone1000-fvp.dts create mode 100644 arch/arm/dts/corstone1000-mps3.dts create mode 100644 arch/arm/dts/corstone1000.dtsi create mode 100644 board/armltd/corstone1000/Kconfig create mode 100644 board/armltd/corstone1000/MAINTAINERS create mode 100644 board/armltd/corstone1000/Makefile create mode 100644 board/armltd/corstone1000/corstone1000.c create mode 100644 configs/corstone1000_defconfig create mode 100644 include/configs/corstone1000.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c618aad801..95f92538d7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1352,6 +1352,12 @@ config ARCH_VEXPRESS64 select ENV_IS_IN_FLASH if MTD imply DISTRO_DEFAULTS +config TARGET_CORSTONE1000 + bool "Support Corstone1000 Platform" + select ARM64 + select PL01X_SERIAL + select DM + config TARGET_TOTAL_COMPUTE bool "Support Total Compute Platform" select ARM64 @@ -2300,7 +2306,7 @@ source "arch/arm/mach-nexell/Kconfig" source "arch/arm/mach-npcm/Kconfig" source "board/armltd/total_compute/Kconfig" - +source "board/armltd/corstone1000/Kconfig" source "board/bosch/shc/Kconfig" source "board/bosch/guardian/Kconfig" source "board/Marvell/octeontx/Kconfig" diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 2fa3957162..2873d048cd 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1273,6 +1273,9 @@ dtb-$(CONFIG_TARGET_EA_LPC3250DEVKITV2) += lpc3250-ea3250.dtb dtb-$(CONFIG_ARCH_QEMU) += qemu-arm.dtb qemu-arm64.dtb +dtb-$(CONFIG_TARGET_CORSTONE1000) += corstone1000-mps3.dtb \ + corstone1000-fvp.dtb + include $(srctree)/scripts/Makefile.dts targets += $(dtb-y) diff --git a/arch/arm/dts/corstone1000-fvp.dts b/arch/arm/dts/corstone1000-fvp.dts new file mode 100644 index 0000000000..26b0f1b3ce --- /dev/null +++ b/arch/arm/dts/corstone1000-fvp.dts @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro Limited. All rights reserved. + * + */ + +/dts-v1/; + +#include "corstone1000.dtsi" + +/ { + model = "ARM Corstone1000 FVP (Fixed Virtual Platform)"; + compatible = "arm,corstone1000-fvp"; + + smsc: ethernet@4010000 { + compatible = "smsc,lan91c111"; + reg = <0x40100000 0x10000>; + phy-mode = "mii"; + interrupts = ; + reg-io-width = <2>; + }; + + vmmc_v3_3d: fixed_v3_3d { + compatible = "regulator-fixed"; + regulator-name = "vmmc_supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + sdmmc0: mmc@40300000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x40300000 0x1000>; + interrupts = ; + max-frequency = <12000000>; + vmmc-supply = <&vmmc_v3_3d>; + clocks = <&smbclk>, <&refclk100mhz>; + clock-names = "smclk", "apb_pclk"; + }; + + sdmmc1: mmc@50000000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x50000000 0x10000>; + interrupts = ; + max-frequency = <12000000>; + vmmc-supply = <&vmmc_v3_3d>; + clocks = <&smbclk>, <&refclk100mhz>; + clock-names = "smclk", "apb_pclk"; + }; +}; diff --git a/arch/arm/dts/corstone1000-mps3.dts b/arch/arm/dts/corstone1000-mps3.dts new file mode 100644 index 0000000000..e3146747c2 --- /dev/null +++ b/arch/arm/dts/corstone1000-mps3.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro Limited. All rights reserved. + * + */ + +/dts-v1/; + +#include "corstone1000.dtsi" + +/ { + model = "ARM Corstone1000 FPGA MPS3 board"; + compatible = "arm,corstone1000-mps3"; + + smsc: ethernet@4010000 { + compatible = "smsc,lan9220", "smsc,lan9115"; + reg = <0x40100000 0x10000>; + phy-mode = "mii"; + interrupts = ; + reg-io-width = <2>; + smsc,irq-push-pull; + }; + + usb_host: usb@40200000 { + compatible = "nxp,usb-isp1763"; + reg = <0x40200000 0x100000>; + interrupts = ; + bus-width = <16>; + dr_mode = "host"; + }; +}; diff --git a/arch/arm/dts/corstone1000.dtsi b/arch/arm/dts/corstone1000.dtsi new file mode 100644 index 0000000000..4e46826f88 --- /dev/null +++ b/arch/arm/dts/corstone1000.dtsi @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro Limited. All rights reserved. + * + */ + +#include + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a35"; + reg = <0>; + next-level-cache = <&L2_0>; + }; + }; + + memory@88200000 { + device_type = "memory"; + reg = <0x88200000 0x77e00000>; + }; + + gic: interrupt-controller@1c000000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x1c010000 0x1000>, + <0x1c02f000 0x2000>, + <0x1c04f000 0x1000>, + <0x1c06f000 0x2000>; + interrupts = ; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <1024>; + }; + + refclk100mhz: refclk100mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "apb_pclk"; + }; + + smbclk: refclk24mhzx2 { + /* Reference 24MHz clock x 2 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + clock-output-names = "smclk"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + uartclk: uartclk { + /* UART clock - 50MHz */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "uartclk"; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + ranges; + + timer@1a220000 { + compatible = "arm,armv7-timer-mem"; + reg = <0x1a220000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + clock-frequency = <50000000>; + ranges; + + frame@1a230000 { + frame-number = <0>; + interrupts = ; + reg = <0x1a230000 0x1000>; + }; + }; + + uart0: serial@1a510000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1a510000 0x1000>; + interrupts = ; + clocks = <&uartclk>, <&refclk100mhz>; + clock-names = "uartclk", "apb_pclk"; + }; + + uart1: serial@1a520000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x1a520000 0x1000>; + interrupts = ; + clocks = <&uartclk>, <&refclk100mhz>; + clock-names = "uartclk", "apb_pclk"; + }; + + mhu_hse1: mailbox@1b820000 { + compatible = "arm,mhuv2-tx", "arm,primecell"; + reg = <0x1b820000 0x1000>; + clocks = <&refclk100mhz>; + clock-names = "apb_pclk"; + interrupts = ; + #mbox-cells = <2>; + arm,mhuv2-protocols = <0 0>; + secure-status = "okay"; /* secure-world-only */ + status = "disabled"; + }; + + mhu_seh1: mailbox@1b830000 { + compatible = "arm,mhuv2-rx", "arm,primecell"; + reg = <0x1b830000 0x1000>; + clocks = <&refclk100mhz>; + clock-names = "apb_pclk"; + interrupts = ; + #mbox-cells = <2>; + arm,mhuv2-protocols = <0 0>; + secure-status = "okay"; /* secure-world-only */ + status = "disabled"; + }; + }; +}; diff --git a/board/armltd/corstone1000/Kconfig b/board/armltd/corstone1000/Kconfig new file mode 100644 index 0000000000..709674d4cf --- /dev/null +++ b/board/armltd/corstone1000/Kconfig @@ -0,0 +1,12 @@ +if TARGET_CORSTONE1000 + +config SYS_BOARD + default "corstone1000" + +config SYS_VENDOR + default "armltd" + +config SYS_CONFIG_NAME + default "corstone1000" + +endif diff --git a/board/armltd/corstone1000/MAINTAINERS b/board/armltd/corstone1000/MAINTAINERS new file mode 100644 index 0000000000..8c905686de --- /dev/null +++ b/board/armltd/corstone1000/MAINTAINERS @@ -0,0 +1,7 @@ +CORSTONE1000 BOARD +M: Rui Miguel Silva +M: Vishnu Banavath +S: Maintained +F: board/armltd/corstone1000/ +F: include/configs/corstone1000.h +F: configs/corstone1000_defconfig diff --git a/board/armltd/corstone1000/Makefile b/board/armltd/corstone1000/Makefile new file mode 100644 index 0000000000..77a82c2892 --- /dev/null +++ b/board/armltd/corstone1000/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2022 Arm Limited +# (C) Copyright 2022 Linaro +# Rui Miguel Silva + +obj-y := corstone1000.o diff --git a/board/armltd/corstone1000/corstone1000.c b/board/armltd/corstone1000/corstone1000.c new file mode 100644 index 0000000000..4f4b96a095 --- /dev/null +++ b/board/armltd/corstone1000/corstone1000.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * (C) Copyright 2022 Linaro + * Rui Miguel Silva + */ + +#include +#include +#include +#include +#include +#include + +static struct mm_region corstone1000_mem_map[] = { + { + /* CVM */ + .virt = 0x02000000UL, + .phys = 0x02000000UL, + .size = 0x02000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* QSPI */ + .virt = 0x08000000UL, + .phys = 0x08000000UL, + .size = 0x08000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* Host Peripherals */ + .virt = 0x1A000000UL, + .phys = 0x1A000000UL, + .size = 0x26000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* USB */ + .virt = 0x40200000UL, + .phys = 0x40200000UL, + .size = 0x00100000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* ethernet */ + .virt = 0x40100000UL, + .phys = 0x40100000UL, + .size = 0x00100000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* OCVM */ + .virt = 0x80000000UL, + .phys = 0x80000000UL, + .size = 0x80000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* List terminator */ + 0, + } +}; + +struct mm_region *mem_map = corstone1000_mem_map; + +int board_init(void) +{ + return 0; +} + +int dram_init(void) +{ + gd->ram_size = PHYS_SDRAM_1_SIZE; + + return 0; +} + +int dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return 0; +} + +void reset_cpu(ulong addr) +{ +} diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig new file mode 100644 index 0000000000..49a651aba2 --- /dev/null +++ b/configs/corstone1000_defconfig @@ -0,0 +1,52 @@ +CONFIG_ARM=y +CONFIG_SKIP_LOWLEVEL_INIT=y +CONFIG_TARGET_CORSTONE1000=y +CONFIG_SYS_TEXT_BASE=0x80000000 +CONFIG_SYS_MALLOC_LEN=0x2000000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_DEFAULT_DEVICE_TREE="corstone1000-mps3" +CONFIG_IDENT_STRING=" corstone1000 aarch64 " +CONFIG_SYS_LOAD_ADDR=0x82100000 +CONFIG_DISTRO_DEFAULTS=y +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x83f00000 +CONFIG_FIT=y +CONFIG_BOOTDELAY=3 +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="console=ttyAMA0 loglevel=9 ip=dhcp earlyprintk" +CONFIG_BOOTCOMMAND="run retrieve_kernel_load_addr; echo Loading kernel from $kernel_addr to memory ... ; loadm $kernel_addr $kernel_addr_r 0xc00000; usb start; usb reset; run distro_bootcmd; bootefi $kernel_addr_r $fdtcontroladdr;" +CONFIG_CONSOLE_RECORD=y +CONFIG_LOGLEVEL=7 +# CONFIG_DISPLAY_CPUINFO is not set +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_SYS_PROMPT="corstone1000# " +CONFIG_SYS_MAXARGS=64 +CONFIG_SYS_CBSIZE=512 +# CONFIG_CMD_CONSOLE is not set +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_XIMG is not set +CONFIG_CMD_LOADM=y +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_NFS is not set +CONFIG_CMD_CACHE=y +CONFIG_CMD_RTC=y +CONFIG_CMD_TIME=y +CONFIG_CMD_GETTIME=y +CONFIG_OF_CONTROL=y +CONFIG_VERSION_VARIABLE=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_REGMAP=y +CONFIG_MISC=y +# CONFIG_MMC is not set +CONFIG_PHYLIB=y +CONFIG_PHY_SMSC=y +CONFIG_DM_ETH=y +CONFIG_SMC911X=y +CONFIG_PHY=y +CONFIG_RAM=y +CONFIG_DM_RTC=y +CONFIG_RTC_EMULATION=y +CONFIG_DM_SERIAL=y +CONFIG_USB=y +CONFIG_ERRNO_STR=y diff --git a/include/configs/corstone1000.h b/include/configs/corstone1000.h new file mode 100644 index 0000000000..eba5cba0fb --- /dev/null +++ b/include/configs/corstone1000.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * (C) Copyright 2022 Linaro + * Rui Miguel Silva + * Abdellatif El Khlifi + * + * Configuration for Corstone1000. Parts were derived from other ARM + * configurations. + */ + +#ifndef __CORSTONE1000_H +#define __CORSTONE1000_H + +#include + +#define V2M_BASE 0x80000000 + +#define CONFIG_PL011_CLOCK 50000000 + +/* Physical Memory Map */ +#define PHYS_SDRAM_1 (V2M_BASE) +#define PHYS_SDRAM_1_SIZE 0x80000000 + +#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "usb_pgood_delay=250\0" \ + "boot_bank_flag=0x08002000\0" \ + "kernel_addr_bank_0=0x083EE000\0" \ + "kernel_addr_bank_1=0x0936E000\0" \ + "retrieve_kernel_load_addr=" \ + "if itest.l *${boot_bank_flag} == 0; then " \ + "setenv kernel_addr $kernel_addr_bank_0;" \ + "else " \ + "setenv kernel_addr $kernel_addr_bank_1;" \ + "fi;" \ + "\0" \ + "kernel_addr_r=0x88200000\0" + +#endif From c4645fc87e96e730a6c140d7d7820be2da1b2743 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 22 Jun 2022 16:08:56 -0400 Subject: [PATCH 06/22] cmd/misc: Stop using a function pointer Currently, enabling CMD_MISC gives: cmd/misc.c:67:25: warning: assignment to 'int (*)(struct udevice *, int, void *, int)' from incompatible pointer type 'int (*)(struct udevice *, int, const void *, int)' [-Wincompatible-pointer-types] Because 'misc_read' takes a void * and 'misc_write' takes a const void *, both of which make sense for their operation. Given there's one place we make use of the function pointer, just call read or write directly for the operation we're called with. Reviewed-by: Bin Meng Reviewed-by: Sean Anderson Signed-off-by: Tom Rini --- cmd/misc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/misc.c b/cmd/misc.c index bcd8d960ee..ec32b41ed1 100644 --- a/cmd/misc.c +++ b/cmd/misc.c @@ -44,7 +44,6 @@ static int do_misc_list(struct cmd_tbl *cmdtp, int flag, static int do_misc_op(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], enum misc_op op) { - int (*misc_op)(struct udevice *, int, void *, int); struct udevice *dev; int offset; void *buf; @@ -62,11 +61,10 @@ static int do_misc_op(struct cmd_tbl *cmdtp, int flag, size = hextoul(argv[3], NULL); if (op == MISC_OP_READ) - misc_op = misc_read; + ret = misc_read(dev, offset, buf, size); else - misc_op = misc_write; + ret = misc_write(dev, offset, buf, size); - ret = misc_op(dev, offset, buf, size); if (ret < 0) { if (ret == -ENOSYS) { printf("The device does not support %s\n", From 4276c9b2aabc7c6ff2faceedd839479a562c6738 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:34 -0500 Subject: [PATCH 07/22] ARM: hpe: gxp: add core support The GXP is the HPE BMC SoC that is used in the majority of current generation HPE servers. Traditionally the asic will last multiple generations of server before being replaced. Info about SoC: HPE GXP is the name of the HPE Soc. This SoC is used to implement many BMC features at HPE. It supports ARMv7 architecture based on the Cortex A9 core. It is capable of using an AXI bus to whicha memory controller is attached. It has multiple SPI interfaces to connect boot flash and BIOS flash. It uses a 10/100/1000 MAC for network connectivity. It has multiple i2c engines to drive connectivity with a host infrastructure. There currently are no public specifications but this process is being worked. Signed-off-by: Nick Hawkins --- arch/arm/Kconfig | 8 ++++++++ arch/arm/Makefile | 1 + arch/arm/mach-hpe/Makefile | 1 + arch/arm/mach-hpe/gxp/Kconfig | 9 +++++++++ arch/arm/mach-hpe/gxp/Makefile | 1 + arch/arm/mach-hpe/gxp/reset.c | 25 +++++++++++++++++++++++++ 6 files changed, 45 insertions(+) create mode 100644 arch/arm/mach-hpe/Makefile create mode 100644 arch/arm/mach-hpe/gxp/Kconfig create mode 100644 arch/arm/mach-hpe/gxp/Makefile create mode 100644 arch/arm/mach-hpe/gxp/reset.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 95f92538d7..dab785efad 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2095,6 +2095,12 @@ config TARGET_XENGUEST_ARM64 select SSCANF imply OF_HAS_PRIOR_STAGE +config ARCH_GXP + bool "Support HPE GXP SoCs" + select DM + select OF_CONTROL + imply CMD_DM + endchoice config SUPPORT_PASSING_ATAGS @@ -2205,6 +2211,8 @@ source "arch/arm/mach-davinci/Kconfig" source "arch/arm/mach-exynos/Kconfig" +source "arch/arm/mach-hpe/gxp/Kconfig" + source "arch/arm/mach-highbank/Kconfig" source "arch/arm/mach-integrator/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a342d72daa..64c58f4c4a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -63,6 +63,7 @@ machine-$(CONFIG_ARCH_BCMBCA) += bcmbca machine-$(CONFIG_ARCH_BCMSTB) += bcmstb machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_EXYNOS) += exynos +machine-$(CONFIG_ARCH_GXP) += hpe machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_IPQ40XX) += ipq40xx machine-$(CONFIG_ARCH_K3) += k3 diff --git a/arch/arm/mach-hpe/Makefile b/arch/arm/mach-hpe/Makefile new file mode 100644 index 0000000000..afe5f7a29e --- /dev/null +++ b/arch/arm/mach-hpe/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SOC_GXP) += gxp/ diff --git a/arch/arm/mach-hpe/gxp/Kconfig b/arch/arm/mach-hpe/gxp/Kconfig new file mode 100644 index 0000000000..2d43133ab0 --- /dev/null +++ b/arch/arm/mach-hpe/gxp/Kconfig @@ -0,0 +1,9 @@ +if ARCH_GXP + +config SOC_GXP + bool + select CPU_V7A + +source "board/hpe/gxp/Kconfig" + +endif diff --git a/arch/arm/mach-hpe/gxp/Makefile b/arch/arm/mach-hpe/gxp/Makefile new file mode 100644 index 0000000000..f3cc6684b8 --- /dev/null +++ b/arch/arm/mach-hpe/gxp/Makefile @@ -0,0 +1 @@ +obj-y += reset.o diff --git a/arch/arm/mach-hpe/gxp/reset.c b/arch/arm/mach-hpe/gxp/reset.c new file mode 100644 index 0000000000..ce018a35d9 --- /dev/null +++ b/arch/arm/mach-hpe/gxp/reset.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GXP driver + * + * (C) Copyright 2022 Hewlett Packard Enterprise Development LP. + * Author: Nick Hawkins + * Author: Jean-Marie Verdun + */ + +#include + +#define GXP_CCR 0xc0000000 + +/* empty to satisfy current lowlevel_init, can be removed any time */ +void lowlevel_init(void) +{ +} + +void reset_cpu(ulong ignored) +{ + writel(1, GXP_CCR); + + while (1) + ; /* loop forever till reset */ +} From b25913b40ee138c35d4c92e55898a365348d5769 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:35 -0500 Subject: [PATCH 08/22] timer: gxp: Add HPE GXP timer support Add support for the HPE GXP SOC timer. The GXP supports several different kinds of timers but for the purpose of this driver there is only support for the General Timer. The timer has a 1us resolution and is 56 bits. Signed-off-by: Nick Hawkins --- drivers/timer/Kconfig | 7 +++++ drivers/timer/Makefile | 1 + drivers/timer/gxp-timer.c | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 drivers/timer/gxp-timer.c diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 7b8ab56ed3..d592dba285 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -139,6 +139,13 @@ config DESIGNWARE_APB_TIMER Enables support for the Designware APB Timer driver. This timer is present on Altera SoCFPGA SoCs. +config GXP_TIMER + bool "HPE GXP Timer" + depends on TIMER + help + Enables support for the GXP Timer driver. This timer is + present on HPE GXP SoCs. + config MPC83XX_TIMER bool "MPC83xx timer support" depends on TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index b2f002d597..cc2b8516b5 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_$(SPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o +obj-$(CONFIG_GXP_TIMER) += gxp-timer.o obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o obj-$(CONFIG_NPCM_TIMER) += npcm-timer.o diff --git a/drivers/timer/gxp-timer.c b/drivers/timer/gxp-timer.c new file mode 100644 index 0000000000..6f316bc8c5 --- /dev/null +++ b/drivers/timer/gxp-timer.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GXP timer driver + * + * (C) Copyright 2022 Hewlett Packard Enterprise Development LP. + * Author: Nick Hawkins + * Author: Jean-Marie Verdun + */ + +#include +#include +#include +#include + +#define USTIMELO 0x18 +#define USTIMEHI 0x1C + +struct gxp_timer_priv { + void __iomem *base; +}; + +static u64 gxp_timer_get_count(struct udevice *dev) +{ + struct gxp_timer_priv *priv = dev_get_priv(dev); + u64 val; + + val = readl(priv->base + USTIMEHI); + val = (val << 32) | readl(priv->base + USTIMELO); + + return val; +} + +static int gxp_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct gxp_timer_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + uc_priv->clock_rate = 1000000; + + return 0; +} + +static const struct timer_ops gxp_timer_ops = { + .get_count = gxp_timer_get_count, +}; + +static const struct udevice_id gxp_timer_ids[] = { + { .compatible = "hpe,gxp-timer" }, + {} +}; + +U_BOOT_DRIVER(gxp_timer) = { + .name = "gxp-timer", + .id = UCLASS_TIMER, + .of_match = gxp_timer_ids, + .priv_auto = sizeof(struct gxp_timer_priv), + .probe = gxp_timer_probe, + .ops = &gxp_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +}; From 4f689b3d86be92625ec0593779590ab5ccfd8171 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:36 -0500 Subject: [PATCH 09/22] spi: gxp_spi: Add GXP SPI controller driver The GXP supports 3 separate SPI interfaces to accommodate the system flash, core flash, and other functions. The SPI engine supports variable clock frequency, selectable 3-byte or 4-byte addressing and a configurable x1, x2, and x4 command/address/data modes. The memory buffer for reading and writing ranges between 256 bytes and 8KB. This driver supports access to the core flash. Signed-off-by: Nick Hawkins --- drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/gxp_spi.c | 304 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/spi/gxp_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a1e515cb2b..e48d72d744 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -186,6 +186,12 @@ config FSL_QSPI_AHB_FULL_MAP Enable the Freescale QSPI driver to use full AHB memory map space for flash access. +config GXP_SPI + bool "SPI driver for GXP" + imply SPI_FLASH_BAR + help + Enable support for SPI on GXP. + config ICH_SPI bool "Intel ICH SPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 06e81b465b..8755408e62 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o obj-$(CONFIG_FSL_ESPI) += fsl_espi.o obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o +obj-$(CONFIG_GXP_SPI) += gxp_spi.o obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o diff --git a/drivers/spi/gxp_spi.c b/drivers/spi/gxp_spi.c new file mode 100644 index 0000000000..70d76ac66a --- /dev/null +++ b/drivers/spi/gxp_spi.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GXP SPI driver + * + * (C) Copyright 2022 Hewlett Packard Enterprise Development LP. + * Author: Nick Hawkins + * Author: Jean-Marie Verdun + */ + +#include +#include +#include + +#define GXP_SPI0_MAX_CHIPSELECT 2 + +#define MANUAL_MODE 0 +#define AUTO_MODE 1 +#define OFFSET_SPIMCFG 0x00 +#define OFFSET_SPIMCTRL 0x04 +#define OFFSET_SPICMD 0x05 +#define OFFSET_SPIDCNT 0x06 +#define OFFSET_SPIADDR 0x08 +#define OFFSET_SPILDAT 0x40 +#define GXP_SPILDAT_SIZE 64 + +#define SPIMCTRL_START 0x01 +#define SPIMCTRL_BUSY 0x02 + +#define CMD_READ_ARRAY_FAST 0x0b + +struct gxp_spi_priv { + struct spi_slave slave; + void __iomem *base; + unsigned int mode; + +}; + +static void spi_set_mode(struct gxp_spi_priv *priv, int mode) +{ + unsigned char value; + + value = readb(priv->base + OFFSET_SPIMCTRL); + if (mode == MANUAL_MODE) { + writeb(0x55, priv->base + OFFSET_SPICMD); + writeb(0xaa, priv->base + OFFSET_SPICMD); + /* clear bit5 and bit4, auto_start and start_mask */ + value &= ~(0x03 << 4); + } else { + value |= (0x03 << 4); + } + writeb(value, priv->base + OFFSET_SPIMCTRL); +} + +static int gxp_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, + unsigned long flags) +{ + struct gxp_spi_priv *priv = dev_get_priv(dev->parent); + struct spi_slave *slave = dev_get_parent_priv(dev); + struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); + + unsigned int len = bitlen / 8; + unsigned int value; + unsigned int addr = 0; + unsigned char uchar_out[len]; + unsigned char *uchar_in = (unsigned char *)din; + int read_len; + int read_ptr; + + if (dout && din) { + /* + * error: gxp spi engin cannot send data to dout and read data from din at the same + * time + */ + return -1; + } + + memset(uchar_out, 0, sizeof(uchar_out)); + if (dout) + memcpy(uchar_out, dout, len); + + if (flags & SPI_XFER_BEGIN) { + /* the dout is cmd + addr, cmd=dout[0], add1~3=dout[1~3]. */ + /* cmd reg */ + writeb(uchar_out[0], priv->base + OFFSET_SPICMD); + + /* config reg */ + value = readl(priv->base + OFFSET_SPIMCFG); + value &= ~(1 << 24); + /* set chipselect */ + value |= (slave_plat->cs << 24); + + /* addr reg and addr size */ + if (len >= 4) { + addr = uchar_out[1] << 16 | uchar_out[2] << 8 | uchar_out[3]; + writel(addr, priv->base + OFFSET_SPIADDR); + value &= ~(0x07 << 16); + /* set the address size to 3 byte */ + value |= (3 << 16); + } else { + writel(0, priv->base + OFFSET_SPIADDR); + /* set the address size to 0 byte */ + value &= ~(0x07 << 16); + } + + /* dummy */ + /* clear dummy_cnt to */ + value &= ~(0x1f << 19); + if (uchar_out[0] == CMD_READ_ARRAY_FAST) { + /* fast read needs 8 dummy clocks */ + value |= (8 << 19); + } + + writel(value, priv->base + OFFSET_SPIMCFG); + + if (flags & SPI_XFER_END) { + /* no data cmd just start it */ + /* set the data direction bit to 1 */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value |= (1 << 3); + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* set the data byte count */ + writeb(0, priv->base + OFFSET_SPIDCNT); + + /* set the start bit */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value |= SPIMCTRL_START; + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* wait busy bit is cleared */ + do { + value = readb(priv->base + OFFSET_SPIMCTRL); + } while (value & SPIMCTRL_BUSY); + return 0; + } + } + + if (!(flags & SPI_XFER_END) && (flags & SPI_XFER_BEGIN)) { + /* first of spi_xfer calls */ + return 0; + } + + /* if dout != null, write data to buf and start transaction */ + if (dout) { + if (len > slave->max_write_size) { + printf("SF: write length is too big(>%d)\n", slave->max_write_size); + return -1; + } + + /* load the data bytes */ + memcpy((u8 *)priv->base + OFFSET_SPILDAT, dout, len); + + /* write: set the data direction bit to 1 */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value |= (1 << 3); + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* set the data byte count */ + writeb(len, priv->base + OFFSET_SPIDCNT); + + /* set the start bit */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value |= SPIMCTRL_START; + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* wait busy bit is cleared */ + do { + value = readb(priv->base + OFFSET_SPIMCTRL); + } while (value & SPIMCTRL_BUSY); + + return 0; + } + + /* if din !=null, start and read data */ + if (uchar_in) { + read_ptr = 0; + + while (read_ptr < len) { + read_len = len - read_ptr; + if (read_len > GXP_SPILDAT_SIZE) + read_len = GXP_SPILDAT_SIZE; + + /* read: set the data direction bit to 0 */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value &= ~(1 << 3); + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* set the data byte count */ + writeb(read_len, priv->base + OFFSET_SPIDCNT); + + /* set the start bit */ + value = readb(priv->base + OFFSET_SPIMCTRL); + value |= SPIMCTRL_START; + writeb(value, priv->base + OFFSET_SPIMCTRL); + + /* wait busy bit is cleared */ + do { + value = readb(priv->base + OFFSET_SPIMCTRL); + } while (value & SPIMCTRL_BUSY); + + /* store the data bytes */ + memcpy(uchar_in + read_ptr, (u8 *)priv->base + OFFSET_SPILDAT, read_len); + /* update read_ptr and addr reg */ + read_ptr += read_len; + + addr = readl(priv->base + OFFSET_SPIADDR); + addr += read_len; + writel(addr, priv->base + OFFSET_SPIADDR); + } + + return 0; + } + return -2; +} + +static int gxp_spi_set_speed(struct udevice *dev, unsigned int speed) +{ + /* Accept any speed */ + return 0; +} + +static int gxp_spi_set_mode(struct udevice *dev, unsigned int mode) +{ + struct gxp_spi_priv *priv = dev_get_priv(dev->parent); + + priv->mode = mode; + + return 0; +} + +static int gxp_spi_claim_bus(struct udevice *dev) +{ + struct gxp_spi_priv *priv = dev_get_priv(dev->parent); + unsigned char cmd; + + spi_set_mode(priv, MANUAL_MODE); + + /* exit 4 bytes addr mode, uboot spi_flash only supports 3 byets address mode */ + cmd = 0xe9; + gxp_spi_xfer(dev, 1 * 8, &cmd, NULL, SPI_XFER_BEGIN | SPI_XFER_END); + return 0; +} + +static int gxp_spi_release_bus(struct udevice *dev) +{ + struct gxp_spi_priv *priv = dev_get_priv(dev->parent); + + spi_set_mode(priv, AUTO_MODE); + + return 0; +} + +int gxp_spi_cs_info(struct udevice *bus, unsigned int cs, struct spi_cs_info *info) +{ + if (cs < GXP_SPI0_MAX_CHIPSELECT) + return 0; + else + return -ENODEV; +} + +static int gxp_spi_probe(struct udevice *bus) +{ + struct gxp_spi_priv *priv = dev_get_priv(bus); + + priv->base = dev_read_addr_ptr(bus); + if (!priv->base) + return -ENOENT; + + return 0; +} + +static int gxp_spi_child_pre_probe(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + + slave->max_write_size = GXP_SPILDAT_SIZE; + + return 0; +} + +static const struct dm_spi_ops gxp_spi_ops = { + .claim_bus = gxp_spi_claim_bus, + .release_bus = gxp_spi_release_bus, + .xfer = gxp_spi_xfer, + .set_speed = gxp_spi_set_speed, + .set_mode = gxp_spi_set_mode, + .cs_info = gxp_spi_cs_info, +}; + +static const struct udevice_id gxp_spi_ids[] = { + { .compatible = "hpe,gxp-spi" }, + { } +}; + +U_BOOT_DRIVER(gxp_spi) = { + .name = "gxp_spi", + .id = UCLASS_SPI, + .of_match = gxp_spi_ids, + .ops = &gxp_spi_ops, + .priv_auto = sizeof(struct gxp_spi_priv), + .probe = gxp_spi_probe, + .child_pre_probe = gxp_spi_child_pre_probe, +}; + From e7ea0a2ba3ec6bc9392270aa97e4d3f8a196d91a Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:37 -0500 Subject: [PATCH 10/22] board: hpe: gxp: add HPE GXP soc support Add basic support for the HPE GXP SoC. Reset the EHCI controller at boot. Signed-off-by: Nick Hawkins --- board/hpe/gxp/Kconfig | 46 ++++++++++++++++++++++++ board/hpe/gxp/Makefile | 1 + board/hpe/gxp/gxp_board.c | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 board/hpe/gxp/Kconfig create mode 100644 board/hpe/gxp/Makefile create mode 100644 board/hpe/gxp/gxp_board.c diff --git a/board/hpe/gxp/Kconfig b/board/hpe/gxp/Kconfig new file mode 100644 index 0000000000..5b154a3f6e --- /dev/null +++ b/board/hpe/gxp/Kconfig @@ -0,0 +1,46 @@ +choice + prompt "SoC select" + +config TARGET_GXP + bool "GXP" + select DM + select SOC_GXP + imply CMD_DM + +config TARGET_GXP2 + bool "GXP2" + select DM + select SOC_GXP + select GXP_ECC + imply CMD_DM + +endchoice + +choice + prompt "GXP VROM size" + default GXP_VROM_64MB + optional + +config GXP_VROM_64MB + bool "64MB" + +config GXP_VROM_32MB + bool "32MB" +endchoice + +config GXP_ECC + bool "Enable memory ECC protected" + help + Use half of memory to enable ECC protected + +config SYS_BOARD + default "gxp" + +config SYS_VENDOR + default "hpe" + +config SYS_CONFIG_NAME + default "gxp" + +config SYS_TEXT_BASE + default 0x50000000 diff --git a/board/hpe/gxp/Makefile b/board/hpe/gxp/Makefile new file mode 100644 index 0000000000..775d6bf849 --- /dev/null +++ b/board/hpe/gxp/Makefile @@ -0,0 +1 @@ +obj-y += gxp_board.o diff --git a/board/hpe/gxp/gxp_board.c b/board/hpe/gxp/gxp_board.c new file mode 100644 index 0000000000..d94d9b8a19 --- /dev/null +++ b/board/hpe/gxp/gxp_board.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GXP timer driver + * + * (C) Copyright 2022 Hewlett Packard Enterprise Development LP. + * Author: Nick Hawkins + * Author: Jean-Marie Verdun + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define ECHI_CMD 0xcefe0010 + +int board_init(void) +{ + writel(0x00080002, ECHI_CMD); + + return 0; +} + +int dram_init(void) +{ + if (IS_ENABLED(CONFIG_TARGET_GXP)) { + if (IS_ENABLED(CONFIG_GXP_ECC)) { + /* 0x0f800000 */ + gd->ram_size = SZ_128M + SZ_64M + SZ_32M + SZ_16M + SZ_8M; + } else { + /* 0x1f000000 */ + gd->ram_size = SZ_256M + SZ_128M + SZ_64M + SZ_32M + SZ_16M; + } + + if (IS_ENABLED(CONFIG_GXP_VROM_64MB)) { + if (IS_ENABLED(CONFIG_GXP_ECC)) { + /* 0x0c000000 */ + gd->ram_size = SZ_128M + SZ_64M; + } else { + /* 0x18000000 */ + gd->ram_size = SZ_256M + SZ_128M; + } + } + + if (IS_ENABLED(CONFIG_GXP_VROM_32MB)) { + if (IS_ENABLED(CONFIG_GXP_ECC)) { + /* 0x0e000000 */ + gd->ram_size = SZ_128M + SZ_64M + SZ_32M; + } else { + /* 0x1c000000 */ + gd->ram_size = SZ_256M + SZ_128M + SZ_64M; + } + } + } + + if (IS_ENABLED(CONFIG_TARGET_GXP2)) { + /* 0x1b200000 */ + gd->ram_size = SZ_256M + SZ_128M + SZ_32M + SZ_16M + SZ_2M; + if (IS_ENABLED(CONFIG_GXP_VROM_64MB)) { + /* 0x14000000 */ + gd->ram_size = SZ_256M + SZ_64M; + } + + if (IS_ENABLED(CONFIG_GXP_VROM_32MB)) { + /* 0x18000000 */ + gd->ram_size = SZ_256M + SZ_128M; + } + } + + return 0; +} + From 63ff9d91348a95fb21bc97b3d757fd68462b9910 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:38 -0500 Subject: [PATCH 11/22] dt-bindings: spi: Add hpe gxp spi Add support for the HPE GXP SPI Controller. Signed-off-by: Nick Hawkins --- doc/device-tree-bindings/spi/hpe,gxp-spi.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 doc/device-tree-bindings/spi/hpe,gxp-spi.yaml diff --git a/doc/device-tree-bindings/spi/hpe,gxp-spi.yaml b/doc/device-tree-bindings/spi/hpe,gxp-spi.yaml new file mode 100644 index 0000000000..5e23de1847 --- /dev/null +++ b/doc/device-tree-bindings/spi/hpe,gxp-spi.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/spi/hpe,gxp-spi.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: HPE GXP SPI Controller + +maintainers: + - Nick Hawkins + - Jean-Marie Verdun + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + const: mikrotik,rb4xx-spi + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi@c00000200{ + compatible = "hpe,gxp-spi"; + reg = <0xc0000200 0x80>; + #address-cells = <1>; + #size-cells = <0>; + }; + From 2b7a89bc941707baccf9f3acdc8ca48d489b524c Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:39 -0500 Subject: [PATCH 12/22] ARM: dts: Add device tree files for hpe gxp soc The HPE SoC is new to linux. A basic device tree layout with minimum required for linux to boot including a timer and watchdog support has been created. The dts file is empty at this point but will be updated in subsequent updates as board specific features are enabled. Signed-off-by: Nick Hawkins --- arch/arm/dts/Makefile | 2 + arch/arm/dts/hpe-bmc-dl360gen10.dts | 26 ++++++ arch/arm/dts/hpe-gxp-u-boot.dtsi | 25 ++++++ arch/arm/dts/hpe-gxp.dtsi | 127 ++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 arch/arm/dts/hpe-bmc-dl360gen10.dts create mode 100644 arch/arm/dts/hpe-gxp-u-boot.dtsi create mode 100644 arch/arm/dts/hpe-gxp.dtsi diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 2873d048cd..4b940f8516 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1247,6 +1247,8 @@ dtb-$(CONFIG_TARGET_POMELO) += phytium-pomelo.dtb dtb-$(CONFIG_TARGET_PRESIDIO_ASIC) += ca-presidio-engboard.dtb +dtb-$(CONFIG_TARGET_GXP) += hpe-bmc-dl360gen10.dts + dtb-$(CONFIG_TARGET_IMX8MM_CL_IOT_GATE) += imx8mm-cl-iot-gate.dtb \ imx8mm-cl-iot-gate-ied.dtbo \ imx8mm-cl-iot-gate-ied-adc0.dtbo \ diff --git a/arch/arm/dts/hpe-bmc-dl360gen10.dts b/arch/arm/dts/hpe-bmc-dl360gen10.dts new file mode 100644 index 0000000000..b8030d9d9f --- /dev/null +++ b/arch/arm/dts/hpe-bmc-dl360gen10.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for HPE DL360Gen10 + */ + +/include/ "hpe-gxp-u-boot.dtsi" + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "hpe,gxp-dl360gen10", "hpe,gxp"; + model = "Hewlett Packard Enterprise ProLiant dl360 Gen10"; + + aliases { + serial0 = &uartc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x40000000 0x20000000>; + }; +}; diff --git a/arch/arm/dts/hpe-gxp-u-boot.dtsi b/arch/arm/dts/hpe-gxp-u-boot.dtsi new file mode 100644 index 0000000000..7a2b488521 --- /dev/null +++ b/arch/arm/dts/hpe-gxp-u-boot.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for HPE GXP + */ + +/include/ "hpe-gxp.dtsi" + +/ { + + axi { + u-boot,dm-pre-reloc; + + ahb@c0000000 { + u-boot,dm-pre-reloc; + + spi0: spi@200 { + compatible = "hpe,gxp-spi"; + reg = <0x200 0x80>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/dts/hpe-gxp.dtsi b/arch/arm/dts/hpe-gxp.dtsi new file mode 100644 index 0000000000..cf735b3c4f --- /dev/null +++ b/arch/arm/dts/hpe-gxp.dtsi @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for HPE GXP + */ + +/dts-v1/; +/ { + model = "Hewlett Packard Enterprise GXP BMC"; + compatible = "hpe,gxp"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + device_type = "cpu"; + next-level-cache = <&L2>; + }; + }; + + clocks { + pll: clock-0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1600000000>; + }; + + iopclk: clock-1 { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clock-div = <4>; + clock-mult = <1>; + clocks = <&pll>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + dma-ranges; + + L2: cache-controller@b0040000 { + compatible = "arm,pl310-cache"; + reg = <0xb0040000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + ahb@c0000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xc0000000 0x30000000>; + dma-ranges; + + vic0: interrupt-controller@eff0000 { + compatible = "arm,pl192-vic"; + reg = <0xeff0000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + vic1: interrupt-controller@80f00000 { + compatible = "arm,pl192-vic"; + reg = <0x80f00000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + uarta: serial@e0 { + compatible = "ns16550a"; + reg = <0xe0 0x8>; + interrupts = <17>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + uartb: serial@e8 { + compatible = "ns16550a"; + reg = <0xe8 0x8>; + interrupts = <18>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + uartc: serial@f0 { + compatible = "ns16550a"; + reg = <0xf0 0x8>; + interrupts = <19>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + usb0: usb@efe0000 { + compatible = "hpe,gxp-ehci", "generic-ehci"; + reg = <0xefe0000 0x100>; + interrupts = <7>; + interrupt-parent = <&vic0>; + }; + + st: timer@80 { + compatible = "hpe,gxp-timer"; + reg = <0x80 0x16>; + interrupts = <0>; + interrupt-parent = <&vic0>; + clocks = <&iopclk>; + clock-names = "iop"; + }; + + usb1: usb@efe0100 { + compatible = "hpe,gxp-ohci", "generic-ohci"; + reg = <0xefe0100 0x110>; + interrupts = <6>; + interrupt-parent = <&vic0>; + }; + }; + }; +}; From 79c6c381020324e059f877eb4539fc31226d7fb7 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:40 -0500 Subject: [PATCH 13/22] configs: gxp: add core support Add the include file for the gxp soc. Signed-off-by: Nick Hawkins --- include/configs/gxp.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 include/configs/gxp.h diff --git a/include/configs/gxp.h b/include/configs/gxp.h new file mode 100644 index 0000000000..ae46126399 --- /dev/null +++ b/include/configs/gxp.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * GXP board + * + * (C) Copyright 2022 Hewlett Packard Enterprise Development LP. + * Author: Nick Hawkins + * Author: Jean-Marie Verdun + */ + +#ifndef _GXP_H_ +#define _GXP_H_ + +#define CONFIG_SYS_SDRAM_BASE 0x40000000 + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "recover_file=openbmc-hpe-recovery-image.mtd\0" \ + "recover_cmd=usb start; " \ + "mw.b 0xD100000D 0x40; " \ + "if fatload usb 0 0x50000000 $recover_file 0x4C0000 0x80000; then " \ + "setenv bootargs console=ttyS0,115200 recovery; " \ + "setenv force_recovery; " \ + "saveenv; " \ + "bootm 0x50000000; " \ + "else " \ + "while itest 0 < 1; do " \ + "mw.b 0xd1000005 0xc0; " \ + "sleep .1; " \ + "mw.b 0xd1000005 0x00; " \ + "sleep .1; " \ + "done; " \ + "fi; " \ + "reset;\0" \ + "spiboot=if itest.b *0xD10000B2 == 6; then " \ + "run recover_cmd;" \ + "fi;" \ + "if printenv force_recovery; then " \ + "run recover_cmd; " \ + "else " \ + "bootm 0xfc080000; " \ + "run recover_cmd; " \ + "fi;\0" + +#endif From 3736faee5b776a9f273d4107ea58fab4bbd48cef Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:41 -0500 Subject: [PATCH 14/22] configs: gxp: add gxp_defconfig This is the initial very basic config that enables the U-Boot console on the hpe gxp soc. Signed-off-by: Nick Hawkins --- configs/gxp_defconfig | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 configs/gxp_defconfig diff --git a/configs/gxp_defconfig b/configs/gxp_defconfig new file mode 100644 index 0000000000..4408c6ce37 --- /dev/null +++ b/configs/gxp_defconfig @@ -0,0 +1,60 @@ +CONFIG_ARM=y +CONFIG_SKIP_LOWLEVEL_INIT=y +CONFIG_SYS_THUMB_BUILD=y +CONFIG_ARCH_GXP=y +CONFIG_SYS_MALLOC_LEN=0x4000000 +CONFIG_GXP_VROM_64MB=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x60000 +CONFIG_ENV_SECT_SIZE=0x10000 +CONFIG_DEFAULT_DEVICE_TREE="hpe-bmc-dl360gen10" +CONFIG_ENV_OFFSET_REDUND=0x70000 +CONFIG_SYS_LOAD_ADDR=0x40100000 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x2000000 +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_VERBOSE=y +CONFIG_BOOTDELAY=5 +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Press SPACE to abort autoboot in %d seconds\n" +CONFIG_AUTOBOOT_STOP_STR=" " +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="earlyprintk console=ttyS2,115200 user_debug=31" +CONFIG_USE_BOOTCOMMAND=y +CONFIG_BOOTCOMMAND="run spiboot" +# CONFIG_DISPLAY_CPUINFO is not set +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="gxp# " +# CONFIG_BOOTM_NETBSD is not set +# CONFIG_BOOTM_PLAN9 is not set +# CONFIG_BOOTM_RTEMS is not set +# CONFIG_BOOTM_VXWORKS is not set +CONFIG_CMD_GPT=y +# CONFIG_RANDOM_UUID is not set +CONFIG_CMD_MISC=y +CONFIG_CMD_FAT=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_SYS_REDUNDAND_ENVIRONMENT=y +CONFIG_NETCONSOLE=y +CONFIG_MISC=y +# CONFIG_MMC is not set +CONFIG_DM_SPI_FLASH=y +CONFIG_SF_DEFAULT_MODE=3 +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_POWER is not set +CONFIG_RAM=y +CONFIG_DM_SERIAL=y +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_GXP_SPI=y +CONFIG_TIMER=y +CONFIG_GXP_TIMER=y +CONFIG_SHA512=y From 478c00718df842271fe0636031603bfcef420837 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 8 Jun 2022 16:21:42 -0500 Subject: [PATCH 15/22] MAINTAINERS: Introduce HPE GXP Architecture Create a section in MAINTAINERS for the GXP HPE architecture Signed-off-by: Nick Hawkins --- MAINTAINERS | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ebec1f7b4..ba9fdb5a66 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -279,6 +279,19 @@ F: arch/arm/cpu/armv8/hisilicon F: arch/arm/include/asm/arch-hi6220/ F: arch/arm/include/asm/arch-hi3660/ +ARM HPE GXP ARCHITECTURE +M: Jean-Marie Verdun +M: Nick Hawkins +S: Maintained +F: arch/arm/dts/hpe-bmc* +F: arch/arm/dts/hpe-gxp* +F: arch/arm/mach-hpe/ +F: board/hpe/ +F: configs/gxp_defconfig +F: doc/device-tree-bindings/spi/hpe,gxp-spi.yaml +F: drivers/timer/gxp-timer.c +F: drivers/spi/gxp_spi.c + ARM IPQ40XX M: Robert Marko M: Luka Kovacic From 442a69c143759648f571e3784c7b3bc5be7ed595 Mon Sep 17 00:00:00 2001 From: Chia-Wei Wang Date: Wed, 1 Jun 2022 16:21:15 +0800 Subject: [PATCH 16/22] configs: ast2600: Move SPL bss section to DRAM space The commit b583348ca8c8 ("image: fit: Align hash output buffers") places the hash output buffer at the .bss section. However, AST2600 by default executes SPL in the NOR flash XIP way. This results in the hash output cannot be written to the buffer as it is located at the R/X only region. We need to move the .bss section out of the SPL body to the DRAM space, where hash output can be written to. This patch includes: - Define the .bss section base and size - A new SPL linker script is added with a separate .bss region specified - Enable CONFIG_SPL_SEPARATE_BSS kconfig option Signed-off-by: Chia-Wei Wang Reviewed-by: Neal Liu --- arch/arm/mach-aspeed/ast2600/u-boot-spl.lds | 94 +++++++++++++++++++++ configs/evb-ast2600_defconfig | 6 +- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-aspeed/ast2600/u-boot-spl.lds diff --git a/arch/arm/mach-aspeed/ast2600/u-boot-spl.lds b/arch/arm/mach-aspeed/ast2600/u-boot-spl.lds new file mode 100644 index 0000000000..22b4e16d35 --- /dev/null +++ b/arch/arm/mach-aspeed/ast2600/u-boot-spl.lds @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * (C) Copyright 2022 + * Chia-Wei Wang + */ + +MEMORY { .nor : ORIGIN = CONFIG_SPL_TEXT_BASE, + LENGTH = CONFIG_SPL_SIZE_LIMIT } +MEMORY { .bss : ORIGIN = CONFIG_SPL_BSS_START_ADDR, + LENGTH = CONFIG_SPL_BSS_MAX_SIZE } + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + __image_copy_start = .; + *(.vectors) + CPUDIR/start.o (.text*) + *(.text*) + *(.glue*) + } > .nor + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } > .nor + + . = ALIGN(4); + .data : { + *(.data*) + } > .nor + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } > .nor + + . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + } > .nor + + . = ALIGN(4); + + __image_copy_end = .; + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } > .nor + + .end : + { + *(.__end) + } > .nor + + _image_binary_end = .; + + .bss : { + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } > .bss + + __bss_size = __bss_end - __bss_start; +} + +#if defined(IMAGE_MAX_SIZE) +ASSERT(__image_copy_end - __image_copy_start <= (IMAGE_MAX_SIZE), \ + "SPL image too big"); +#endif + +#if defined(CONFIG_SPL_BSS_MAX_SIZE) +ASSERT(__bss_end - __bss_start <= (CONFIG_SPL_BSS_MAX_SIZE), \ + "SPL image BSS too big"); +#endif + +#if defined(CONFIG_SPL_MAX_FOOTPRINT) +ASSERT(__bss_end - _start <= (CONFIG_SPL_MAX_FOOTPRINT), \ + "SPL image plus BSS too big"); +#endif diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig index bfd0a5f2b1..a91a53da4f 100644 --- a/configs/evb-ast2600_defconfig +++ b/configs/evb-ast2600_defconfig @@ -1,6 +1,7 @@ CONFIG_ARM=y CONFIG_SYS_DCACHE_OFF=y CONFIG_SPL_SYS_THUMB_BUILD=y +CONFIG_SPL_LDSCRIPT="arch/arm/mach-aspeed/ast2600/u-boot-spl.lds" CONFIG_ARCH_ASPEED=y CONFIG_SYS_TEXT_BASE=0x80000000 CONFIG_SYS_MALLOC_LEN=0x2000000 @@ -32,10 +33,13 @@ CONFIG_BOOTCOMMAND="run bootspi" # CONFIG_DISPLAY_CPUINFO is not set CONFIG_SPL_SIZE_LIMIT_SUBTRACT_GD=y CONFIG_SPL_SIZE_LIMIT_SUBTRACT_MALLOC=y -CONFIG_SPL_NO_BSS_LIMIT=y +CONFIG_SPL_HAS_BSS_LINKER_SECTION=y +CONFIG_SPL_BSS_START_ADDR=0x83000000 +CONFIG_SPL_BSS_MAX_SIZE=0x1000000 CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000000 +CONFIG_SPL_SEPARATE_BSS=y CONFIG_SPL_FIT_IMAGE_TINY=y CONFIG_SPL_DM_RESET=y CONFIG_SPL_RAM_SUPPORT=y From 12770d0df0e841cfa1bdbde7636aad3d531bf66b Mon Sep 17 00:00:00 2001 From: Chia-Wei Wang Date: Wed, 1 Jun 2022 16:43:52 +0800 Subject: [PATCH 17/22] ast2600: spl: Add boot mode detection AST2600 supports boot from SPI(mmap), eMMC, and UART. This patch adds the boot mode detection and return the corresponding boot device type. Signed-off-by: Chia-Wei Wang --- .../arm/include/asm/arch-aspeed/scu_ast2600.h | 3 ++ arch/arm/mach-aspeed/ast2600/spl.c | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/arm/include/asm/arch-aspeed/scu_ast2600.h b/arch/arm/include/asm/arch-aspeed/scu_ast2600.h index 7c5aab98b6..251bfa269b 100644 --- a/arch/arm/include/asm/arch-aspeed/scu_ast2600.h +++ b/arch/arm/include/asm/arch-aspeed/scu_ast2600.h @@ -87,6 +87,9 @@ #define SCU_HWSTRAP1_CPU_FREQ_SHIFT 8 #define SCU_HWSTRAP1_MAC2_INTF BIT(7) #define SCU_HWSTRAP1_MAC1_INTF BIT(6) +#define SCU_HWSTRAP1_BOOT_EMMC BIT(2) + +#define SCU_HWSTRAP2_BOOT_UART BIT(8) #define SCU_EFUSE_DIS_DP BIT(17) #define SCU_EFUSE_DIS_VGA BIT(14) diff --git a/arch/arm/mach-aspeed/ast2600/spl.c b/arch/arm/mach-aspeed/ast2600/spl.c index 6c49d6aede..53c8a15bf9 100644 --- a/arch/arm/mach-aspeed/ast2600/spl.c +++ b/arch/arm/mach-aspeed/ast2600/spl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,8 +22,37 @@ void board_init_f(ulong dummy) dram_init(); } +/* + * Try to detect the boot mode. Fallback to the default, + * memory mapped SPI XIP booting if detection failed. + */ u32 spl_boot_device(void) { + int rc; + struct udevice *scu_dev; + struct ast2600_scu *scu; + + rc = uclass_get_device_by_driver(UCLASS_CLK, + DM_DRIVER_GET(aspeed_ast2600_scu), &scu_dev); + if (rc) { + debug("%s: failed to get SCU driver\n", __func__); + goto out; + } + + scu = devfdt_get_addr_ptr(scu_dev); + if (IS_ERR_OR_NULL(scu)) { + debug("%s: failed to get SCU base\n", __func__); + goto out; + } + + /* boot from UART has higher priority */ + if (scu->hwstrap2 & SCU_HWSTRAP2_BOOT_UART) + return BOOT_DEVICE_UART; + + if (scu->hwstrap1 & SCU_HWSTRAP1_BOOT_EMMC) + return BOOT_DEVICE_MMC1; + +out: return BOOT_DEVICE_RAM; } From 9e03b48dfa6f0ad4a0a4f4411c8cc1da2cd70800 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 7 Jun 2022 16:32:08 +0800 Subject: [PATCH 18/22] crypto: nuvoton: Add NPCM7xx AES driver add nuvoton BMC npcm750 AES driver Signed-off-by: Jim Liu --- arch/arm/include/asm/arch-npcm7xx/aes.h | 53 +++++ drivers/crypto/Kconfig | 2 + drivers/crypto/Makefile | 1 + drivers/crypto/nuvoton/Kconfig | 8 + drivers/crypto/nuvoton/Makefile | 1 + drivers/crypto/nuvoton/npcm_aes.c | 301 ++++++++++++++++++++++++ 6 files changed, 366 insertions(+) create mode 100644 arch/arm/include/asm/arch-npcm7xx/aes.h create mode 100644 drivers/crypto/nuvoton/Kconfig create mode 100644 drivers/crypto/nuvoton/Makefile create mode 100644 drivers/crypto/nuvoton/npcm_aes.c diff --git a/arch/arm/include/asm/arch-npcm7xx/aes.h b/arch/arm/include/asm/arch-npcm7xx/aes.h new file mode 100644 index 0000000000..255efcb5ce --- /dev/null +++ b/arch/arm/include/asm/arch-npcm7xx/aes.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _NPCM_AES_H_ +#define _NPCM_AES_H_ + +#define AES_OP_ENCRYPT 0 +#define AES_OP_DECRYPT 1 +#define SIZE_AES_BLOCK (AES128_KEY_LENGTH) + +struct npcm_aes_regs { + unsigned char reserved_0[0x400]; // 0x000 + unsigned int aes_key_0; // 0x400 + unsigned int aes_key_1; // 0x404 + unsigned int aes_key_2; // 0x408 + unsigned int aes_key_3; // 0x40c + unsigned char reserved_1[0x30]; // 0x410 + unsigned int aes_iv_0; // 0x440 + unsigned char reserved_2[0x1c]; // 0x444 + unsigned int aes_ctr_0; // 0x460 + unsigned char reserved_3[0x0c]; // 0x464 + unsigned int aes_busy; // 0x470 + unsigned char reserved_4[0x04]; // 0x474 + unsigned int aes_sk; // 0x478 + unsigned char reserved_5[0x14]; // 0x47c + unsigned int aes_prev_iv_0; // 0x490 + unsigned char reserved_6[0x0c]; // 0x494 + unsigned int aes_din_dout; // 0x4a0 + unsigned char reserved_7[0x1c]; // 0x4a4 + unsigned int aes_control; // 0x4c0 + unsigned int aes_version; // 0x4c4 + unsigned int aes_hw_flags; // 0x4c8 + unsigned char reserved_8[0x28]; // 0x4cc + unsigned int aes_sw_reset; // 0x4f4 + unsigned char reserved_9[0x08]; // 0x4f8 + unsigned int aes_fifo_data; // 0x500 + unsigned char reserved_10[0xfc]; // 0x504 + unsigned int aes_fifo_status; // 0x600 +}; + +#define AES_BUSY_BIT BIT(0) +#define SW_RESET_BIT BIT(0) +#define AES_SK_BIT BIT(0) + +#define DIN_FIFO_FULL BIT(0) +#define DIN_FIFO_EMPTY BIT(1) +#define DOUT_FIFO_FULL BIT(2) +#define DOUT_FIFO_EMPTY BIT(3) +#define DIN_FIFO_OVERFLOW BIT(4) +#define DOUT_FIFO_UNDERFLOW BIT(5) + +int npcm_aes_select_key(u8 fkeyind); + +#endif diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 675081ecd3..12ef84ca05 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -6,4 +6,6 @@ source drivers/crypto/fsl/Kconfig source drivers/crypto/aspeed/Kconfig +source drivers/crypto/nuvoton/Kconfig + endmenu diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 6b762565a1..b910518609 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -8,3 +8,4 @@ obj-y += rsa_mod_exp/ obj-y += fsl/ obj-y += hash/ obj-y += aspeed/ +obj-y += nuvoton/ diff --git a/drivers/crypto/nuvoton/Kconfig b/drivers/crypto/nuvoton/Kconfig new file mode 100644 index 0000000000..c4ab0674e5 --- /dev/null +++ b/drivers/crypto/nuvoton/Kconfig @@ -0,0 +1,8 @@ +config NPCM_AES + bool "Support the NPCM AES algorithm" + select NPCM_OTP + help + This provides a means to encrypt and decrypt data using the NPCM + AES (Advanced Encryption Standard). This algorithm uses a symmetric + key and is widely used as a streaming cipher. This command only + supports AES256-CBC. diff --git a/drivers/crypto/nuvoton/Makefile b/drivers/crypto/nuvoton/Makefile new file mode 100644 index 0000000000..5b2fb90314 --- /dev/null +++ b/drivers/crypto/nuvoton/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NPCM_AES) += npcm_aes.o diff --git a/drivers/crypto/nuvoton/npcm_aes.c b/drivers/crypto/nuvoton/npcm_aes.c new file mode 100644 index 0000000000..6493ea108e --- /dev/null +++ b/drivers/crypto/nuvoton/npcm_aes.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ONE_SECOND 0xC00000 + +struct npcm_aes_priv { + struct npcm_aes_regs *regs; +}; + +static struct npcm_aes_priv *aes_priv; +static u8 fkeyind_to_set = 0xff; + +static int second_timeout(u32 *addr, u32 bitmask, u32 bitpol) +{ + ulong time, i = 0; + + time = get_timer(0); + + /* default 1 second timeout */ + while (((readl(addr) & bitmask) == bitpol) && i < ONE_SECOND) + i++; + + if (i == ONE_SECOND) { + printf("%xms timeout: addr = %x, mask = %x\n", (u32)get_timer(time), + *addr, bitmask); + return -1; + } + + return 0; +} + +int npcm_aes_select_key(u8 fkeyind) +{ + if (npcm_otp_is_fuse_array_disabled(NPCM_KEY_SA)) { + printf("AES key access denied\n"); + return -EACCES; + } + + if (fkeyind < 4) + fkeyind_to_set = fkeyind; + + return 0; +} + +static int npcm_aes_init(u8 dec_enc) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 ctrl, orgctrlval, wrtimeout; + + /* reset hw */ + writel(readl(®s->aes_sw_reset) | SW_RESET_BIT, ®s->aes_sw_reset); + writel(readl(®s->aes_fifo_status) | DIN_FIFO_OVERFLOW, ®s->aes_fifo_status); + writel(readl(®s->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, ®s->aes_fifo_status); + + /* Workaround to over come Errata #648 */ + orgctrlval = readl(®s->aes_control); + ctrl = (0x00002004 | dec_enc); /* AES256(CBC) */ + + if (ctrl != orgctrlval) { + writel(ctrl, ®s->aes_control); + + if (ctrl != readl(®s->aes_control)) { + u32 read_ctrl; + int intwr; + + for (wrtimeout = 0; wrtimeout < 1000; wrtimeout++) { + for (intwr = 0 ; intwr < 10; intwr++) { + writel(ctrl, ®s->aes_control); + writew(ctrl, (u16 *)®s->aes_control + 1); + /* Write configurable info in a single write operation */ + mb(); + } + + read_ctrl = readl(®s->aes_control); + if (ctrl == read_ctrl) + break; + } + + if (wrtimeout == 1000) { + printf("\nTIMEOUT expected data=0x%x Actual AES_CONTROL data 0x%x\n\n", + ctrl, read_ctrl); + return -EAGAIN; + } + + printf("Workaround success, wrtimeout = %d\n", wrtimeout); + } + } + + if (second_timeout(®s->aes_busy, AES_BUSY_BIT, AES_BUSY_BIT)) + return -EAGAIN; + + return 0; +} + +static inline void npcm_aes_load_iv(u8 *iv) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 *p = (u32 *)iv; + u32 i; + + /* Initialization Vector is loaded in 32-bit chunks */ + for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++) + writel(p[i], ®s->aes_iv_0 + i); +} + +static inline void npcm_aes_load_key(u8 *key) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 *p = (u32 *)key; + u32 i; + + /* The key can be loaded either via the configuration or by using sideband + * key port (aes_select_key). + * If aes_select_key has been called ('fkeyind_to_set' was set to desired + * key index) and no key is specified (key is NULL), we should use the + * key index. Otherwise, we write the given key to the registers. + */ + if (!key && fkeyind_to_set < 4) { + npcm_otp_select_key(fkeyind_to_set); + + /* Sample the new key */ + writel(readl(®s->aes_sk) | AES_SK_BIT, ®s->aes_sk); + + } else { + /* Initialization Vector is loaded in 32-bit chunks */ + for (i = 0; i < (2 * SIZE_AES_BLOCK / sizeof(u32)); i++) + writel(p[i], ®s->aes_key_0 + i); + + fkeyind_to_set = 0xff; + } +} + +static inline void npcm_aes_write(u32 *in) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 i; + + /* 16 Byte AES Block is written in 32-bit chunks */ + for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++) + writel(in[i], ®s->aes_fifo_data); +} + +static inline void npcm_aes_read(u32 *out) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 i; + + /* Data is read in 32-bit chunks */ + for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++) + out[i] = readl(®s->aes_fifo_data); +} + +static void npcm_aes_feed(u32 num_aes_blocks, u32 *datain, u32 *dataout) +{ + struct npcm_aes_regs *regs = aes_priv->regs; + u32 aes_datablk; + u32 total_blocks = num_aes_blocks; + u32 blocks_left = num_aes_blocks; + + /* data mode */ + writel(readl(®s->aes_busy) | AES_BUSY_BIT, ®s->aes_busy); + + /* Clear overflow and underflow */ + writel(readl(®s->aes_fifo_status) | DIN_FIFO_OVERFLOW, ®s->aes_fifo_status); + writel(readl(®s->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, ®s->aes_fifo_status); + + /* datain/dataout is advanced in 32-bit chunks */ + aes_datablk = (SIZE_AES_BLOCK / sizeof(u32)); + + /* Quit if there is no complete blocks */ + if (total_blocks == 0) + return; + + /* Write the first block */ + if (total_blocks > 1) { + npcm_aes_write(datain); + datain += aes_datablk; + blocks_left--; + } + + /* Write the second block */ + if (total_blocks > 2) { + second_timeout(®s->aes_fifo_status, DIN_FIFO_EMPTY, 0); + npcm_aes_write(datain); + datain += aes_datablk; + blocks_left--; + } + + /* Write & read available blocks */ + while (blocks_left > 0) { + second_timeout(®s->aes_fifo_status, DIN_FIFO_FULL, DIN_FIFO_FULL); + + /* Write next block */ + npcm_aes_write(datain); + datain += aes_datablk; + + /* Wait till DOUT FIFO is empty */ + second_timeout(®s->aes_fifo_status, DOUT_FIFO_EMPTY, DOUT_FIFO_EMPTY); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + + blocks_left--; + } + + if (total_blocks > 2) { + second_timeout(®s->aes_fifo_status, DOUT_FIFO_FULL, 0); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + + second_timeout(®s->aes_fifo_status, DOUT_FIFO_FULL, 0); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + } else if (total_blocks > 1) { + second_timeout(®s->aes_fifo_status, DOUT_FIFO_FULL, 0); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + } +} + +void aes_expand_key(u8 *key, u32 key_size, u8 *expkey) +{ + /* npcm hw expands the key automatically, just copy it */ + memcpy(expkey, key, SIZE_AES_BLOCK * 2); +} + +void aes_cbc_encrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + if (npcm_aes_init(AES_OP_ENCRYPT)) + return; + + npcm_aes_load_iv(iv); + + npcm_aes_load_key(key_exp); + + npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst); +} + +void aes_cbc_decrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + if (npcm_aes_init(AES_OP_DECRYPT)) + return; + + npcm_aes_load_iv(iv); + + npcm_aes_load_key(key_exp); + + npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst); +} + +static int npcm_aes_bind(struct udevice *dev) +{ + aes_priv = calloc(1, sizeof(struct npcm_aes_priv)); + if (!aes_priv) { + printf("%s: %d\n", __func__, __LINE__); + return -ENOMEM; + } + + aes_priv->regs = dev_read_addr_ptr(dev); + if (!aes_priv->regs) { + printf("Cannot find aes reg address, binding failed\n"); + return -EINVAL; + } + + printf("AES: NPCM AES module bind OK\n"); + + return 0; +} + +static const struct udevice_id npcm_aes_ids[] = { + { .compatible = "nuvoton,npcm845-aes" }, + { .compatible = "nuvoton,npcm750-aes" }, + { } +}; + +U_BOOT_DRIVER(npcm_aes) = { + .name = "npcm_aes", + .id = UCLASS_MISC, + .of_match = npcm_aes_ids, + .priv_auto = sizeof(struct npcm_aes_priv), + .bind = npcm_aes_bind, +}; From 2eeb4ee97ef8ebf92f4097ddba0dfc9654370196 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 7 Jun 2022 16:32:09 +0800 Subject: [PATCH 19/22] crypto: nuvoton: Add NPCM7xx SHA driver add nuvoton BMC npcm750 SHA driver Signed-off-by: Jim Liu --- drivers/crypto/nuvoton/Kconfig | 6 + drivers/crypto/nuvoton/Makefile | 1 + drivers/crypto/nuvoton/npcm_sha.c | 897 ++++++++++++++++++++++++++++++ 3 files changed, 904 insertions(+) create mode 100644 drivers/crypto/nuvoton/npcm_sha.c diff --git a/drivers/crypto/nuvoton/Kconfig b/drivers/crypto/nuvoton/Kconfig index c4ab0674e5..034fcadfcc 100644 --- a/drivers/crypto/nuvoton/Kconfig +++ b/drivers/crypto/nuvoton/Kconfig @@ -6,3 +6,9 @@ config NPCM_AES AES (Advanced Encryption Standard). This algorithm uses a symmetric key and is widely used as a streaming cipher. This command only supports AES256-CBC. + +config NPCM_SHA + bool "Enable NPCM cryptographic HW SHA accelerator" + help + This option enables support of NPCM cryptographic HW SHA accelerator. + It supports SHA1 and SHA256 hashing algorithms. diff --git a/drivers/crypto/nuvoton/Makefile b/drivers/crypto/nuvoton/Makefile index 5b2fb90314..5a1173dfe7 100644 --- a/drivers/crypto/nuvoton/Makefile +++ b/drivers/crypto/nuvoton/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_NPCM_AES) += npcm_aes.o +obj-$(CONFIG_NPCM_SHA) += npcm_sha.o diff --git a/drivers/crypto/nuvoton/npcm_sha.c b/drivers/crypto/nuvoton/npcm_sha.c new file mode 100644 index 0000000000..7ebdfa16f4 --- /dev/null +++ b/drivers/crypto/nuvoton/npcm_sha.c @@ -0,0 +1,897 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include + +#define HASH_DIG_H_NUM 8 + +#define HASH_CTR_STS_SHA_EN BIT(0) +#define HASH_CTR_STS_SHA_BUSY BIT(1) +#define HASH_CTR_STS_SHA_RST BIT(2) +#define HASH_CFG_SHA1_SHA2 BIT(0) + +/* SHA type */ +enum npcm_sha_type { + npcm_sha_type_sha2 = 0, + npcm_sha_type_sha1, + npcm_sha_type_num +}; + +struct npcm_sha_regs { + unsigned int hash_data_in; + unsigned char hash_ctr_sts; + unsigned char reserved_0[0x03]; + unsigned char hash_cfg; + unsigned char reserved_1[0x03]; + unsigned char hash_ver; + unsigned char reserved_2[0x13]; + unsigned int hash_dig[HASH_DIG_H_NUM]; +}; + +struct npcm_sha_priv { + struct npcm_sha_regs *regs; +}; + +static struct npcm_sha_priv *sha_priv; + +#ifdef SHA_DEBUG_MODULE +#define sha_print(fmt, args...) printf(fmt, ##args) +#else +#define sha_print(fmt, args...) (void)0 +#endif + +#define SHA_BLOCK_LENGTH (512 / 8) +#define SHA_2_HASH_LENGTH (256 / 8) +#define SHA_1_HASH_LENGTH (160 / 8) +#define SHA_HASH_LENGTH(type) ((type == npcm_sha_type_sha2) ? \ + (SHA_2_HASH_LENGTH) : (SHA_1_HASH_LENGTH)) + +#define SHA_SECRUN_BUFF_SIZE 64 +#define SHA_TIMEOUT 100 +#define SHA_DATA_LAST_BYTE 0x80 + +#define SHA2_NUM_OF_SELF_TESTS 3 +#define SHA1_NUM_OF_SELF_TESTS 4 + +#define NUVOTON_ALIGNMENT 4 + +/*-----------------------------------------------------------------------------*/ +/* SHA instance struct handler */ +/*-----------------------------------------------------------------------------*/ +struct SHA_HANDLE_T { + u32 hv[SHA_2_HASH_LENGTH / sizeof(u32)]; + u32 length0; + u32 length1; + u32 block[SHA_BLOCK_LENGTH / sizeof(u32)]; + u8 type; + bool active; +}; + +// The # of bytes currently in the sha block buffer +#define SHA_BUFF_POS(length) ((length) & (SHA_BLOCK_LENGTH - 1)) + +// The # of free bytes in the sha block buffer +#define SHA_BUFF_FREE(length) (SHA_BLOCK_LENGTH - SHA_BUFF_POS(length)) + +static void SHA_FlushLocalBuffer_l(const u32 *buff); +static int SHA_BusyWait_l(void); +static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type); +static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type); +static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block); +static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block); +static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block); + +static int SHA_Init(struct SHA_HANDLE_T *handleptr); +static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type); +static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len); +static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest); +static int SHA_Reset(void); +static int SHA_Power(bool on); +#ifdef SHA_PRINT +static void SHA_PrintRegs(void); +static void SHA_PrintVersion(void); +#endif + +static struct SHA_HANDLE_T sha_handle; + +/*----------------------------------------------------------------------------*/ +/* Checks if give function returns int error, and returns the error */ +/* immediately after SHA disabling */ +/*----------------------------------------------------------------------------*/ +int npcm_sha_check(int status) +{ + if (status != 0) { + SHA_Power(false); + return status; + } + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_sha_calc */ +/* */ +/* Parameters: type - SHA module type */ +/* inBuff - Pointer to a buffer containing the data to */ +/* be hashed */ +/* len - Length of the data to hash */ +/* hashDigest - Pointer to a buffer where the reseulting */ +/* digest will be copied to */ +/* */ +/* Returns: 0 on success or other int error code on error */ +/* Side effects: */ +/* Description: */ +/* This routine performs complete SHA calculation in one */ +/* step */ +/*----------------------------------------------------------------------------*/ +int npcm_sha_calc(u8 type, const u8 *inbuff, u32 len, u8 *hashdigest) +{ + int status; + struct SHA_HANDLE_T handle; + + SHA_Init(&handle); + SHA_Power(true); + SHA_Reset(); + SHA_Start(&handle, type); + status = SHA_Update(&handle, inbuff, len); + npcm_sha_check(status); + status = SHA_Finish(&handle, hashdigest); + npcm_sha_check(status); + SHA_Power(false); + + return 0; +} + +/* + * Computes hash value of input pbuf using h/w acceleration + * + * @param in_addr A pointer to the input buffer + * @param bufleni Byte length of input buffer + * @param out_addr A pointer to the output buffer. When complete + * 32 bytes are copied to pout[0]...pout[31]. Thus, a user + * should allocate at least 32 bytes at pOut in advance. + * @param chunk_size chunk size for sha256 + */ +void hw_sha256(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size) +{ + puts("\nhw_sha256 using BMC HW accelerator\t"); + npcm_sha_calc(npcm_sha_type_sha2, (u8 *)in_addr, buflen, (u8 *)out_addr); +} + +/* + * Computes hash value of input pbuf using h/w acceleration + * + * @param in_addr A pointer to the input buffer + * @param bufleni Byte length of input buffer + * @param out_addr A pointer to the output buffer. When complete + * 32 bytes are copied to pout[0]...pout[31]. Thus, a user + * should allocate at least 32 bytes at pOut in advance. + * @param chunk_size chunk_size for sha1 + */ +void hw_sha1(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size) +{ + puts("\nhw_sha1 using BMC HW accelerator\t"); + npcm_sha_calc(npcm_sha_type_sha1, (u8 *)in_addr, buflen, (u8 *)out_addr); +} + +/* + * Create the context for sha progressive hashing using h/w acceleration + * + * @algo: Pointer to the hash_algo struct + * @ctxp: Pointer to the pointer of the context for hashing + * @return 0 if ok, -ve on error + */ +int hw_sha_init(struct hash_algo *algo, void **ctxp) +{ + const char *algo_name1 = "sha1"; + const char *algo_name2 = "sha256"; + + SHA_Init(&sha_handle); + SHA_Power(true); + SHA_Reset(); + if (!strcmp(algo_name1, algo->name)) + return SHA_Start(&sha_handle, npcm_sha_type_sha1); + else if (!strcmp(algo_name2, algo->name)) + return SHA_Start(&sha_handle, npcm_sha_type_sha2); + else + return -EPROTO; +} + +/* + * Update buffer for sha progressive hashing using h/w acceleration + * + * The context is freed by this function if an error occurs. + * + * @algo: Pointer to the hash_algo struct + * @ctx: Pointer to the context for hashing + * @buf: Pointer to the buffer being hashed + * @size: Size of the buffer being hashed + * @is_last: 1 if this is the last update; 0 otherwise + * @return 0 if ok, -ve on error + */ +int hw_sha_update(struct hash_algo *algo, void *ctx, const void *buf, + unsigned int size, int is_last) +{ + return SHA_Update(&sha_handle, buf, size); +} + +/* + * Copy sha hash result at destination location + * + * The context is freed after completion of hash operation or after an error. + * + * @algo: Pointer to the hash_algo struct + * @ctx: Pointer to the context for hashing + * @dest_buf: Pointer to the destination buffer where hash is to be copied + * @size: Size of the buffer being hashed + * @return 0 if ok, -ve on error + */ +int hw_sha_finish(struct hash_algo *algo, void *ctx, void *dest_buf, int size) +{ + int status; + + status = SHA_Finish(&sha_handle, dest_buf); + npcm_sha_check(status); + return SHA_Power(false); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Init */ +/* */ +/* Parameters: handlePtr - SHA processing handle pointer */ +/* Returns: 0 on success or other int error code on error. */ +/* Side effects: */ +/* Description: */ +/* This routine initialize the SHA module */ +/*----------------------------------------------------------------------------*/ +static int SHA_Init(struct SHA_HANDLE_T *handleptr) +{ + handleptr->active = false; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Start */ +/* */ +/* Parameters: handlePtr - SHA processing handle pointer */ +/* type - SHA module type */ +/* */ +/* Returns: 0 on success or other int error code on error. */ +/* Side effects: */ +/* Description: */ +/* This routine start a single SHA process */ +/*----------------------------------------------------------------------------*/ +static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + + // Initialize handle + handleptr->length0 = 0; + handleptr->length1 = 0; + handleptr->type = type; + handleptr->active = true; + + // Set SHA type + writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg); + + // Reset SHA hardware + SHA_Reset(); + + /* The handlePtr->hv is initialized with the correct IV as the SHA engine + * automatically fill the HASH_DIG_Hn registers according to SHA spec + * (following SHA_RST assertion) + */ + SHA_GetShaDigest_l((u8 *)handleptr->hv, type); + + // Init block with zeros + memset(handleptr->block, 0, sizeof(handleptr->block)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Update */ +/* */ +/* Parameters: handlePtr - SHA processing handle pointer */ +/* buffer - Pointer to the data that will be added to */ +/* the hash calculation */ +/* len - Length of data to add to SHA calculation */ +/* */ +/* */ +/* Returns: 0 on success or other int error code on error */ +/* Side effects: */ +/* Description: */ +/* This routine adds data to previously started SHA */ +/* calculation */ +/*----------------------------------------------------------------------------*/ +static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)]; + u32 bufferlen = len; + u16 pos = 0; + u8 *blockptr; + int status; + + // Error check + if (!handleptr->active) + return -EPROTO; + + // Wait till SHA is not busy + status = SHA_BusyWait_l(); + npcm_sha_check(status); + + // Set SHA type + writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg); + + // Write SHA latest digest into SHA module + SHA_SetShaDigest_l(handleptr->hv, handleptr->type); + + // Set number of unhashed bytes which remained from last update + pos = SHA_BUFF_POS(handleptr->length0); + + // Copy unhashed bytes which remained from last update to secrun buffer + SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer); + + while (len) { + // Wait for the hardware to be available (in case we are hashing) + status = SHA_BusyWait_l(); + npcm_sha_check(status); + + // Move as much bytes as we can into the secrun buffer + bufferlen = min(len, SHA_BUFF_FREE(handleptr->length0)); + + // Copy current given buffer to the secrun buffer + SHA_SetBlock_l((u8 *)buffer, bufferlen, pos, localbuffer); + + // Update size of hashed bytes + handleptr->length0 += bufferlen; + + if (handleptr->length0 < bufferlen) + handleptr->length1++; + + // Update length of data left to digest + len -= bufferlen; + + // Update given buffer pointer + buffer += bufferlen; + + // If secrun buffer is full + if (SHA_BUFF_POS(handleptr->length0) == 0) { + /* We just filled up the buffer perfectly, so let it hash (we'll + * unload the hash only when we are done with all hashing) + */ + SHA_FlushLocalBuffer_l(localbuffer); + + pos = 0; + bufferlen = 0; + } + } + + // Wait till SHA is not busy + status = SHA_BusyWait_l(); + npcm_sha_check(status); + + /* Copy unhashed bytes from given buffer to handle block for next update/finish */ + blockptr = (u8 *)handleptr->block; + while (bufferlen) + blockptr[--bufferlen + pos] = *(--buffer); + + // Save SHA current digest + SHA_GetShaDigest_l((u8 *)handleptr->hv, handleptr->type); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Finish */ +/* */ +/* Parameters: handlePtr - SHA processing handle pointer */ +/* hashDigest - Pointer to a buffer where the final digest */ +/* will be copied to */ +/* */ +/* Returns: 0 on success or other int error code on error */ +/* Side effects: */ +/* Description: */ +/* This routine finish SHA calculation and get */ +/* the resulting SHA digest */ +/*----------------------------------------------------------------------------*/ +static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)]; + const u8 lastbyte = SHA_DATA_LAST_BYTE; + u16 pos; + int status; + + // Error check + if (!handleptr->active) + return -EPROTO; + + // Set SHA type + writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg); + + // Wait till SHA is not busy + status = SHA_BusyWait_l(); + npcm_sha_check(status); + + // Finish off the current buffer with the SHA spec'ed padding + pos = SHA_BUFF_POS(handleptr->length0); + + // Init SHA digest + SHA_SetShaDigest_l(handleptr->hv, handleptr->type); + + // Load data into secrun buffer + SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer); + + // Set data last byte as in SHA algorithm spec + SHA_SetBlock_l(&lastbyte, 1, pos++, localbuffer); + + // If the remainder of data is longer then one block + if (pos > (SHA_BLOCK_LENGTH - 8)) { + /* The length will be in the next block Pad the rest of the last block with 0's */ + SHA_ClearBlock_l((SHA_BLOCK_LENGTH - pos), pos, localbuffer); + + // Hash the current block + SHA_FlushLocalBuffer_l(localbuffer); + + pos = 0; + + // Wait till SHA is not busy + status = SHA_BusyWait_l(); + npcm_sha_check(status); + } + + // Pad the rest of the last block with 0's except for the last 8-3 bytes + SHA_ClearBlock_l((SHA_BLOCK_LENGTH - (8 - 3)) - pos, pos, localbuffer); + + /* The last 8-3 bytes are set to the bit-length of the message in big-endian form */ + SHA_SetLength32_l(handleptr, localbuffer); + + // Hash all that, and save the hash for the caller + SHA_FlushLocalBuffer_l(localbuffer); + + // Wait till SHA is not busy + status = SHA_BusyWait_l(); + npcm_sha_check(status); + + // Save SHA final digest into given buffer + SHA_GetShaDigest_l(hashdigest, handleptr->type); + + // Free handle + handleptr->active = false; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Reset */ +/* */ +/* Parameters: none */ +/* Returns: none */ +/* Side effects: */ +/* Description: */ +/* This routine reset SHA module */ +/*----------------------------------------------------------------------------*/ +static int SHA_Reset(void) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + + writel(readl(®s->hash_ctr_sts) | HASH_CTR_STS_SHA_RST, ®s->hash_ctr_sts); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_Power */ +/* */ +/* Parameters: on - true enable the module, false disable the module */ +/* Returns: none */ +/* Side effects: */ +/* Description: */ +/* This routine set SHA module power on/off */ +/*----------------------------------------------------------------------------*/ +static int SHA_Power(bool on) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u8 hash_sts; + + hash_sts = readb(®s->hash_ctr_sts) & ~HASH_CTR_STS_SHA_EN; + writeb(hash_sts | (on & HASH_CTR_STS_SHA_EN), ®s->hash_ctr_sts); + + return 0; +} + +#ifdef SHA_PRINT +/*----------------------------------------------------------------------------*/ +/* Function: SHA_PrintRegs */ +/* */ +/* Parameters: none */ +/* Returns: none */ +/* Side effects: */ +/* Description: */ +/* This routine prints the module registers */ +/*----------------------------------------------------------------------------*/ +static void SHA_PrintRegs(void) +{ +#ifdef SHA_DEBUG_MODULE + struct npcm_sha_regs *regs = sha_priv->regs; +#endif + unsigned int i; + + sha_print("/*--------------*/\n"); + sha_print("/* SHA */\n"); + sha_print("/*--------------*/\n\n"); + + sha_print("HASH_CTR_STS = 0x%02X\n", readb(®s->hash_ctr_sts)); + sha_print("HASH_CFG = 0x%02X\n", readb(®s->hash_cfg)); + + for (i = 0; i < HASH_DIG_H_NUM; i++) + sha_print("HASH_DIG_H%d = 0x%08X\n", i, readl(®s->hash_dig[i])); + + sha_print("HASH_VER = 0x%08X\n", readb(®s->hash_ver)); + + sha_print("\n"); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_PrintVersion */ +/* */ +/* Parameters: none */ +/* Returns: none */ +/* Side effects: */ +/* Description: */ +/* This routine prints the module version */ +/*----------------------------------------------------------------------------*/ +static void SHA_PrintVersion(void) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + + printf("SHA MODULE VER = %d\n", readb(®s->hash_ver)); +} +#endif + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_sha_selftest */ +/* */ +/* Parameters: type - SHA module type */ +/* Returns: 0 on success or other int error code on error */ +/* Side effects: */ +/* Description: */ +/* This routine performs various tests on the SHA HW and SW */ +/*----------------------------------------------------------------------------*/ +int npcm_sha_selftest(u8 type) +{ + int status; + struct SHA_HANDLE_T handle; + u8 hashdigest[max(SHA_1_HASH_LENGTH, SHA_2_HASH_LENGTH)]; + u16 i, j; + + /*------------------------------------------------------------------------*/ + /* SHA1 tests info */ + /*------------------------------------------------------------------------*/ + + static const u8 sha1selftestbuff[SHA1_NUM_OF_SELF_TESTS][94] = { + {"abc"}, + {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + {"0123456789012345678901234567890123456789012345678901234567890123"}, + {0x30, 0x5c, 0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b, + 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a, + 0x01, 0x0c, 0x04, 0x14, 0xe1, 0xb6, 0x93, 0xfe, 0x33, 0x43, 0xc1, 0x20, + 0x5d, 0x4b, 0xaa, 0xb8, 0x63, 0xfb, 0xcf, 0x6c, 0x46, 0x1e, 0x88, 0x04, + 0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a, 0x01, 0x0c, + 0x04, 0x14, 0x13, 0xc1, 0x0c, 0xfc, 0xc8, 0x92, 0xd7, 0xde, 0x07, 0x1c, + 0x40, 0xde, 0x4f, 0xcd, 0x07, 0x5b, 0x68, 0x20, 0x5a, 0x6c} + }; + + static const u8 sha1selftestbufflen[SHA1_NUM_OF_SELF_TESTS] = { + 3, 56, 64, 94 + }; + + static const u8 sha1selftestexpres[SHA1_NUM_OF_SELF_TESTS][SHA_1_HASH_LENGTH] = { + {0xA9, 0x99, 0x3E, 0x36, + 0x47, 0x06, 0x81, 0x6A, + 0xBA, 0x3E, 0x25, 0x71, + 0x78, 0x50, 0xC2, 0x6C, + 0x9C, 0xD0, 0xD8, 0x9D}, + {0x84, 0x98, 0x3E, 0x44, + 0x1C, 0x3B, 0xD2, 0x6E, + 0xBA, 0xAE, 0x4A, 0xA1, + 0xF9, 0x51, 0x29, 0xE5, + 0xE5, 0x46, 0x70, 0xF1}, + {0xCF, 0x08, 0x00, 0xF7, + 0x64, 0x4A, 0xCE, 0x3C, + 0xB4, 0xC3, 0xFA, 0x33, + 0x38, 0x8D, 0x3B, 0xA0, + 0xEA, 0x3C, 0x8B, 0x6E}, + {0xc9, 0x84, 0x45, 0xc8, + 0x64, 0x04, 0xb1, 0xe3, + 0x3c, 0x6b, 0x0a, 0x8c, + 0x8b, 0x80, 0x94, 0xfc, + 0xf3, 0xc9, 0x98, 0xab} + }; + + /*------------------------------------------------------------------------*/ + /* SHA2 tests info */ + /*------------------------------------------------------------------------*/ + + static const u8 sha2selftestbuff[SHA2_NUM_OF_SELF_TESTS][100] = { + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + {'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'} + }; + + static const u8 sha2selftestbufflen[SHA2_NUM_OF_SELF_TESTS] = { + 3, 56, 100 + }; + + static const u8 sha2selftestexpres[SHA2_NUM_OF_SELF_TESTS][SHA_2_HASH_LENGTH] = { + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }, + }; + + if (type == npcm_sha_type_sha1) { + /*--------------------------------------------------------------------*/ + /* SHA 1 TESTS */ + /*--------------------------------------------------------------------*/ + for (i = 0; i < SHA1_NUM_OF_SELF_TESTS; i++) { + if (i != 3) { + status = npcm_sha_calc(npcm_sha_type_sha1, sha1selftestbuff[i], sha1selftestbufflen[i], hashdigest); + npcm_sha_check(status); + } else { + SHA_Power(true); + SHA_Reset(); + status = SHA_Start(&handle, npcm_sha_type_sha1); + npcm_sha_check(status); + status = SHA_Update(&handle, sha1selftestbuff[i], 73); + npcm_sha_check(status); + status = SHA_Update(&handle, &sha1selftestbuff[i][73], sha1selftestbufflen[i] - 73); + npcm_sha_check(status); + status = SHA_Finish(&handle, hashdigest); + npcm_sha_check(status); + SHA_Power(false); + } + + if (memcmp(hashdigest, sha1selftestexpres[i], SHA_1_HASH_LENGTH)) + return -1; + } + + } else { + /*--------------------------------------------------------------------*/ + /* SHA 2 TESTS */ + /*--------------------------------------------------------------------*/ + for (i = 0; i < SHA2_NUM_OF_SELF_TESTS; i++) { + SHA_Power(true); + SHA_Reset(); + status = SHA_Start(&handle, npcm_sha_type_sha2); + npcm_sha_check(status); + if (i == 2) { + for (j = 0; j < 10000; j++) { //not working + status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]); + npcm_sha_check(status); + } + } else { + status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]); + npcm_sha_check(status); + } + + status = SHA_Finish(&handle, hashdigest); + npcm_sha_check(status); + SHA_Power(false); + if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH)) + return -1; + + npcm_sha_calc(npcm_sha_type_sha2, sha2selftestbuff[i], sha2selftestbufflen[i], hashdigest); + if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH)) + return -1; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_FlushLocalBuffer_l */ +/* */ +/* Parameters: */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine flush secrun buffer to SHA module */ +/*----------------------------------------------------------------------------*/ +static void SHA_FlushLocalBuffer_l(const u32 *buff) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u32 i; + + for (i = 0; i < (SHA_BLOCK_LENGTH / sizeof(u32)); i++) + writel(buff[i], ®s->hash_data_in); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_BusyWait_l */ +/* */ +/* Parameters: */ +/* Returns: 0 if no error was found or DEFS_STATUS_ERROR otherwise */ +/* Side effects: */ +/* Description: This routine wait for SHA unit to no longer be busy */ +/*----------------------------------------------------------------------------*/ +static int SHA_BusyWait_l(void) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u32 timeout = SHA_TIMEOUT; + + do { + if (timeout-- == 0) + return -ETIMEDOUT; + } while ((readb(®s->hash_ctr_sts) & HASH_CTR_STS_SHA_BUSY) + == HASH_CTR_STS_SHA_BUSY); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_GetShaDigest_l */ +/* */ +/* Parameters: hashDigest - buffer for the hash output. */ +/* type - SHA module type */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine copy the hash digest from the hardware */ +/* and into given buffer (in ram) */ +/*----------------------------------------------------------------------------*/ +static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u16 j; + u8 len = SHA_HASH_LENGTH(type) / sizeof(u32); + + // Copy Bytes from SHA module to given buffer + for (j = 0; j < len; j++) + ((u32 *)hashdigest)[j] = readl(®s->hash_dig[j]); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_SetShaDigest_l */ +/* */ +/* Parameters: hashDigest - input buffer to set as hash digest */ +/* type - SHA module type */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine set the hash digest in the hardware from */ +/* a given buffer (in ram) */ +/*----------------------------------------------------------------------------*/ +static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type) +{ + struct npcm_sha_regs *regs = sha_priv->regs; + u16 j; + u8 len = SHA_HASH_LENGTH(type) / sizeof(u32); + + // Copy Bytes from given buffer to SHA module + for (j = 0; j < len; j++) + writel(hashdigest[j], ®s->hash_dig[j]); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_SetBlock_l */ +/* */ +/* Parameters: data - data to copy */ +/* len - size of data */ +/* position - byte offset into the block at which data */ +/* should be placed */ +/* block - block buffer */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine load bytes into block buffer */ +/*----------------------------------------------------------------------------*/ +static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block) +{ + u8 *dest = (u8 *)block; + + memcpy(dest + position, data, len); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_SetBlock_l */ +/* */ +/* Parameters: */ +/* len - size of data */ +/* position - byte offset into the block at which data */ +/* should be placed */ +/* block - block buffer */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine load zero's into the block buffer */ +/*----------------------------------------------------------------------------*/ +static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block) +{ + u8 *dest = (u8 *)block; + + memset(dest + position, 0, len); +} + +/*----------------------------------------------------------------------------*/ +/* Function: SHA_SetLength32_l */ +/* */ +/* Parameters: */ +/* handlePtr - SHA processing handle pointer */ +/* block - block buffer */ +/* Returns: none */ +/* Side effects: */ +/* Description: This routine set the length of the hash's data */ +/* len is the 32-bit byte length of the message */ +/*lint -efunc(734,SHA_SetLength32_l) Supperess loss of percision lint warning */ +/*----------------------------------------------------------------------------*/ +static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block) +{ + u16 *secrunbufferswappedptr = (u16 *)(void *)(block); + + secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 1] = (u16) + ((handleptr->length0 << 3) << 8) | ((u16)(handleptr->length0 << 3) >> 8); + secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 2] = (u16) + ((handleptr->length0 >> (16 - 3)) >> 8) | ((u16)(handleptr->length0 >> (16 - 3)) << 8); + secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 3] = (u16) + ((handleptr->length1 << 3) << 8) | ((u16)(handleptr->length1 << 3) >> 8); + secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 4] = (u16) + ((handleptr->length1 >> (16 - 3)) >> 8) | ((u16)(handleptr->length1 >> (16 - 3)) << 8); +} + +static int npcm_sha_bind(struct udevice *dev) +{ + sha_priv = calloc(1, sizeof(struct npcm_sha_priv)); + if (!sha_priv) + return -ENOMEM; + + sha_priv->regs = dev_remap_addr_index(dev, 0); + if (!sha_priv->regs) { + printf("Cannot find sha reg address, binding failed\n"); + return -EINVAL; + } + + printf("SHA: NPCM SHA module bind OK\n"); + + return 0; +} + +static const struct udevice_id npcm_sha_ids[] = { + { .compatible = "nuvoton,npcm845-sha" }, + { .compatible = "nuvoton,npcm750-sha" }, + { } +}; + +U_BOOT_DRIVER(npcm_sha) = { + .name = "npcm_sha", + .id = UCLASS_MISC, + .of_match = npcm_sha_ids, + .priv_auto = sizeof(struct npcm_sha_priv), + .bind = npcm_sha_bind, +}; From 0ae1c77199a6ae0b5bf759f894736898d62d46b0 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 7 Jun 2022 16:33:54 +0800 Subject: [PATCH 20/22] misc: nuvoton: Add NPCM7xx otp controller driver Add Nuvoton BMC npcm750 otp driver Signed-off-by: Jim Liu --- arch/arm/include/asm/arch-npcm7xx/otp.h | 90 +++++ drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 + drivers/misc/npcm_otp.c | 512 ++++++++++++++++++++++++ 4 files changed, 612 insertions(+) create mode 100644 arch/arm/include/asm/arch-npcm7xx/otp.h create mode 100644 drivers/misc/npcm_otp.c diff --git a/arch/arm/include/asm/arch-npcm7xx/otp.h b/arch/arm/include/asm/arch-npcm7xx/otp.h new file mode 100644 index 0000000000..11d1e8550c --- /dev/null +++ b/arch/arm/include/asm/arch-npcm7xx/otp.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _NPCM_OTP_H_ +#define _NPCM_OTP_H_ + +#ifdef CONFIG_ARCH_NPCM8XX +enum { + NPCM_KEY_SA = 0, + NPCM_FUSE_SA = 0, + NPCM_NUM_OF_SA = 1 +}; +#else +enum { + NPCM_KEY_SA = 0, + NPCM_FUSE_SA = 1, + NPCM_NUM_OF_SA = 2 +}; +#endif + +struct npcm_otp_regs { + unsigned int fst; + unsigned int faddr; + unsigned int fdata; + unsigned int fcfg; + unsigned int fustrap_fkeyind; + unsigned int fctl; +}; + +#define FST_RDY BIT(0) +#define FST_RDST BIT(1) +#define FST_RIEN BIT(2) + +#ifdef CONFIG_ARCH_NPCM8XX +#define FADDR_BYTEADDR(addr) ((addr) << 3) +#define FADDR_BITPOS(pos) ((pos) << 0) +#define FADDR_VAL(addr, pos) (FADDR_BITPOS(pos) | FADDR_BYTEADDR(addr)) +#define FADDR_IN_PROG BIT(16) +#else +#define FADDR_BYTEADDR(addr) ((addr) << 0) +#define FADDR_BITPOS(pos) ((pos) << 10) +#define FADDR_VAL(addr, pos) (FADDR_BYTEADDR(addr) | FADDR_BITPOS(pos)) +#define FADDR_IN_PROG BIT(16) +#endif + +#define FDATA_MASK (0xff) + +#define FUSTRAP_O_SECBOOT BIT(23) + +#define FCFG_FDIS BIT(31) + +#define FKEYIND_KVAL BIT(0) +#define FKEYIND_KSIZE_MASK (0x00000070) +#define FKEYIND_KSIZE_128 (0x40) +#define FKEYIND_KSIZE_192 (0x50) +#define FKEYIND_KSIZE_256 (0x60) +#define FKEYIND_KIND_MASK (0x000c0000) +#define FKEYIND_KIND_KEY(indx) ((indx) << 18) + +// Program cycle initiation values (sequence of two adjacent writes) +#define PROGRAM_ARM 0x1 +#define PROGRAM_INIT 0xBF79E5D0 + +#define OTP2_BASE 0xF018A000 +#define FUSTRAP (OTP2_BASE + 0x10) + +// Read cycle initiation value +#define READ_INIT 0x02 + +// Value to clean FDATA contents +#define FDATA_CLEAN_VALUE 0x01 + +#ifdef CONFIG_ARCH_NPCM8XX +#define NPCM_OTP_ARR_BYTE_SIZE 8192 +#else +#define NPCM_OTP_ARR_BYTE_SIZE 1024 +#endif + +#define MIN_PROGRAM_PULSES 4 +#define MAX_PROGRAM_PULSES 20 +#define NPCM_OTP_ARR_BYTE_SIZE 1024 + +int fuse_prog_image(u32 bank, uintptr_t address); +int fuse_program_data(u32 bank, u32 word, u8 *data, u32 size); +int npcm_otp_select_key(u8 key_index); +bool npcm_otp_is_fuse_array_disabled(u32 arr); +void npcm_otp_nibble_parity_ecc_encode(u8 *datain, u8 *dataout, u32 size); +void npcm_otp_majority_rule_ecc_encode(u8 *datain, u8 *dataout, u32 size); +void npcm_arch_preboot_os(void); + +#endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7b6c371d1c..28d5da49ff 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -321,6 +321,15 @@ config SPL_MXC_OCOTP Programmable memory pages, that are stored on some Freescale i.MX processors, in SPL. +config NPCM_OTP + bool "Nnvoton NPCM BMC On-Chip OTP Memory Support" + depends on (ARM && ARCH_NPCM) + default n + help + Support NPCM BMC OTP memory (fuse). + To compile this driver as a module, choose M here: the module + will be called npcm_otp. + config NUVOTON_NCT6102D bool "Enable Nuvoton NCT6102D Super I/O driver" help diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 0a333640b9..0bf05ca05e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o obj-$(CONFIG_$(SPL_TPL_)LS2_SFP) += ls2_sfp.o obj-$(CONFIG_$(SPL_)MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o +obj-$(CONFIG_NPCM_OTP) += npcm_otp.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o diff --git a/drivers/misc/npcm_otp.c b/drivers/misc/npcm_otp.c new file mode 100644 index 0000000000..304910888b --- /dev/null +++ b/drivers/misc/npcm_otp.c @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct npcm_otp_priv { + struct npcm_otp_regs *regs[2]; +}; + +static struct npcm_otp_priv *otp_priv; + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_check_inputs */ +/* */ +/* Parameters: arr - fuse array number to check */ +/* word - fuse word (offset) to check */ +/* Returns: int */ +/* Side effects: */ +/* Description: Checks is arr and word are illegal and do not exceed */ +/* their range. Return 0 if they are legal, -1 if not */ +/*----------------------------------------------------------------------------*/ +static int npcm_otp_check_inputs(u32 arr, u32 word) +{ + if (arr >= NPCM_NUM_OF_SA) { + if (IS_ENABLED(CONFIG_ARCH_NPCM8XX)) + printf("\nError: npcm8XX otp includs only one bank: 0\n"); + if (IS_ENABLED(CONFIG_ARCH_NPCM7XX)) + printf("\nError: npcm7XX otp includs only two banks: 0 and 1\n"); + return -1; + } + + if (word >= NPCM_OTP_ARR_BYTE_SIZE) { + printf("\nError: npcm otp array comprises only %d bytes, numbered from 0 to %d\n", + NPCM_OTP_ARR_BYTE_SIZE, NPCM_OTP_ARR_BYTE_SIZE - 1); + return -1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_wait_for_otp_ready */ +/* */ +/* Parameters: array - fuse array to wait for */ +/* Returns: int */ +/* Side effects: */ +/* Description: Initialize the Fuse HW module. */ +/*----------------------------------------------------------------------------*/ +static int npcm_otp_wait_for_otp_ready(u32 arr, u32 timeout) +{ + struct npcm_otp_regs *regs = otp_priv->regs[arr]; + u32 time = timeout; + + /*------------------------------------------------------------------------*/ + /* check parameters validity */ + /*------------------------------------------------------------------------*/ + if (arr > NPCM_FUSE_SA) + return -EINVAL; + + while (--time > 1) { + if (readl(®s->fst) & FST_RDY) { + /* fuse is ready, clear the status. */ + writel(readl(®s->fst) | FST_RDST, ®s->fst); + return 0; + } + } + + /* try to clear the status in case it was set */ + writel(readl(®s->fst) | FST_RDST, ®s->fst); + + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_read_byte */ +/* */ +/* Parameters: arr - Storage Array type [input]. */ +/* addr - Byte-address to read from [input]. */ +/* data - Pointer to result [output]. */ +/* Returns: none */ +/* Side effects: */ +/* Description: Read 8-bit data from an OTP storage array. */ +/*----------------------------------------------------------------------------*/ +static void npcm_otp_read_byte(u32 arr, u32 addr, u8 *data) +{ + struct npcm_otp_regs *regs = otp_priv->regs[arr]; + + /* Wait for the Fuse Box Idle */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Configure the byte address in the fuse array for read operation */ + writel(FADDR_VAL(addr, 0), ®s->faddr); + + /* Initiate a read cycle */ + writel(READ_INIT, ®s->fctl); + + /* Wait for read operation completion */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Read the result */ + *data = readl(®s->fdata) & FDATA_MASK; + + /* Clean FDATA contents to prevent unauthorized software from reading + * sensitive information + */ + writel(FDATA_CLEAN_VALUE, ®s->fdata); +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_bit_is_programmed */ +/* */ +/* Parameters: arr - Storage Array type [input]. */ +/* byte_offset - Byte offset in array [input]. */ +/* bit_offset - Bit offset in byte [input]. */ +/* Returns: Nonzero if bit is programmed, zero otherwise. */ +/* Side effects: */ +/* Description: Check if a bit is programmed in an OTP storage array. */ +/*----------------------------------------------------------------------------*/ +static bool npcm_otp_bit_is_programmed(u32 arr, + u32 byte_offset, u8 bit_offset) +{ + u32 data = 0; + + /* Read the entire byte you wish to program */ + npcm_otp_read_byte(arr, byte_offset, (u8 *)&data); + + /* Check whether the bit is already programmed */ + if (data & (1 << bit_offset)) + return true; + + return false; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_program_bit */ +/* */ +/* Parameters: arr - Storage Array type [input]. */ +/* byte)offset - Byte offset in array [input]. */ +/* bit_offset - Bit offset in byte [input]. */ +/* Returns: int */ +/* Side effects: */ +/* Description: Program (set to 1) a bit in an OTP storage array. */ +/*----------------------------------------------------------------------------*/ +static int npcm_otp_program_bit(u32 arr, u32 byte_offset, + u8 bit_offset) +{ + struct npcm_otp_regs *regs = otp_priv->regs[arr]; + int count; + u8 read_data; + + /* Wait for the Fuse Box Idle */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Make sure the bit is not already programmed */ + if (npcm_otp_bit_is_programmed(arr, byte_offset, bit_offset)) + return 0; + + /* Configure the bit address in the fuse array for program operation */ + writel(FADDR_VAL(byte_offset, bit_offset), ®s->faddr); + writel(readl(®s->faddr) | FADDR_IN_PROG, ®s->faddr); + + // program up to MAX_PROGRAM_PULSES + for (count = 1; count <= MAX_PROGRAM_PULSES; count++) { + /* Initiate a program cycle */ + writel(PROGRAM_ARM, ®s->fctl); + writel(PROGRAM_INIT, ®s->fctl); + + /* Wait for program operation completion */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + // after MIN_PROGRAM_PULSES start verifying the result + if (count >= MIN_PROGRAM_PULSES) { + /* Initiate a read cycle */ + writel(READ_INIT, ®s->fctl); + + /* Wait for read operation completion */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Read the result */ + read_data = readl(®s->fdata) & FDATA_MASK; + + /* If the bit is set the sequence ended correctly */ + if (read_data & (1 << bit_offset)) + break; + } + } + + // check if programmking failed + if (count > MAX_PROGRAM_PULSES) { + printf("program fail\n"); + return -EINVAL; + } + + /* + * Clean FDATA contents to prevent unauthorized software from reading + * sensitive information + */ + writel(FDATA_CLEAN_VALUE, ®s->fdata); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_program_byte */ +/* */ +/* Parameters: arr - Storage Array type [input]. */ +/* byte_offset - Byte offset in array [input]. */ +/* value - Byte to program [input]. */ +/* Returns: int */ +/* Side effects: */ +/* Description: Program (set to 1) a given byte's relevant bits in an */ +/* OTP storage array. */ +/*----------------------------------------------------------------------------*/ +static int npcm_otp_program_byte(u32 arr, u32 byte_offset, + u8 value) +{ + int status = 0; + unsigned int i; + u8 data = 0; + int rc; + + rc = npcm_otp_check_inputs(arr, byte_offset); + if (rc != 0) + return rc; + + /* Wait for the Fuse Box Idle */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Read the entire byte you wish to program */ + npcm_otp_read_byte(arr, byte_offset, &data); + + /* In case all relevant bits are already programmed - nothing to do */ + if ((~data & value) == 0) + return status; + + /* Program unprogrammed bits. */ + for (i = 0; i < 8; i++) { + if (value & (1 << i)) { + /* Program (set to 1) the relevant bit */ + int last_status = npcm_otp_program_bit(arr, byte_offset, (u8)i); + + if (last_status != 0) + status = last_status; + } + } + return status; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_is_fuse_array_disabled */ +/* */ +/* Parameters: arr - Storage Array type [input]. */ +/* Returns: bool */ +/* Side effects: */ +/* Description: Return true if access to the first 2048 bits of the */ +/* specified fuse array is disabled, false if not */ +/*----------------------------------------------------------------------------*/ +bool npcm_otp_is_fuse_array_disabled(u32 arr) +{ + struct npcm_otp_regs *regs = otp_priv->regs[arr]; + + return (readl(®s->fcfg) & FCFG_FDIS) != 0; +} + +int npcm_otp_select_key(u8 key_index) +{ + struct npcm_otp_regs *regs = otp_priv->regs[NPCM_KEY_SA]; + u32 idx = 0; + u32 time = 0xDAEDBEEF; + + if (key_index >= 4) + return -1; + + /* Do not destroy ECCDIS bit */ + idx = readl(®s->fustrap_fkeyind); + + /* Configure the key size */ + idx &= ~FKEYIND_KSIZE_MASK; + idx |= FKEYIND_KSIZE_256; + + /* Configure the key index (0 to 3) */ + idx &= ~FKEYIND_KIND_MASK; + idx |= FKEYIND_KIND_KEY(key_index); + + writel(idx, ®s->fustrap_fkeyind); + + /* Wait for selection completetion */ + while (--time > 1) { + if (readl(®s->fustrap_fkeyind) & FKEYIND_KVAL) + return 0; + udelay(1); + } + + return -1; +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_nibble_parity_ecc_encode */ +/* */ +/* Parameters: datain - pointer to decoded data buffer */ +/* dataout - pointer to encoded data buffer (buffer size */ +/* should be 2 x dataout) */ +/* size - size of encoded data (decoded data x 2) */ +/* Returns: none */ +/* Side effects: */ +/* Description: Decodes the data according to nibble parity ECC scheme. */ +/* Size specifies the encoded data size. */ +/* Decodes whole bytes only */ +/*----------------------------------------------------------------------------*/ +void npcm_otp_nibble_parity_ecc_encode(u8 *datain, u8 *dataout, u32 size) +{ + u32 i, idx; + u8 E0, E1, E2, E3; + + for (i = 0; i < (size / 2); i++) { + E0 = (datain[i] >> 0) & 0x01; + E1 = (datain[i] >> 1) & 0x01; + E2 = (datain[i] >> 2) & 0x01; + E3 = (datain[i] >> 3) & 0x01; + + idx = i * 2; + dataout[idx] = datain[i] & 0x0f; + dataout[idx] |= (E0 ^ E1) << 4; + dataout[idx] |= (E2 ^ E3) << 5; + dataout[idx] |= (E0 ^ E2) << 6; + dataout[idx] |= (E1 ^ E3) << 7; + + E0 = (datain[i] >> 4) & 0x01; + E1 = (datain[i] >> 5) & 0x01; + E2 = (datain[i] >> 6) & 0x01; + E3 = (datain[i] >> 7) & 0x01; + + idx = i * 2 + 1; + dataout[idx] = (datain[i] & 0xf0) >> 4; + dataout[idx] |= (E0 ^ E1) << 4; + dataout[idx] |= (E2 ^ E3) << 5; + dataout[idx] |= (E0 ^ E2) << 6; + dataout[idx] |= (E1 ^ E3) << 7; + } +} + +/*----------------------------------------------------------------------------*/ +/* Function: npcm_otp_majority_rule_ecc_encode */ +/* */ +/* Parameters: datain - pointer to decoded data buffer */ +/* dataout - pointer to encoded data buffer (buffer size */ +/* should be 3 x dataout) */ +/* size - size of encoded data (decoded data x 3) */ +/* Returns: none */ +/* Side effects: */ +/* Description: Decodes the data according to Major Rule ECC scheme. */ +/* Size specifies the encoded data size. */ +/* Decodes whole bytes only */ +/*----------------------------------------------------------------------------*/ +void npcm_otp_majority_rule_ecc_encode(u8 *datain, u8 *dataout, u32 size) +{ + u32 byte; + u32 bit; + u8 bit_val; + u32 decoded_size = size / 3; + + for (byte = 0; byte < decoded_size; byte++) { + for (bit = 0; bit < 8; bit++) { + bit_val = (datain[byte] >> bit) & 0x01; + + if (bit_val) { + dataout[byte] |= (1 << bit); + dataout[decoded_size + byte] |= (1 << bit); + dataout[decoded_size * 2 + byte] |= (1 << bit); + } else { + dataout[byte] &= ~(1 << bit); + dataout[decoded_size + byte] &= ~(1 << bit); + dataout[decoded_size * 2 + byte] &= ~(1 << bit); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/* Function: fuse_program_data */ +/* */ +/* Parameters: bank - Storage Array type [input]. */ +/* word - Byte offset in array [input]. */ +/* data - Pointer to data buffer to program. */ +/* size - Number of bytes to program. */ +/* Returns: none */ +/* Side effects: */ +/* Description: Programs the given byte array (size bytes) to the given */ +/* OTP storage array, starting from offset word. */ +/*----------------------------------------------------------------------------*/ +int fuse_program_data(u32 bank, u32 word, u8 *data, u32 size) +{ + u32 arr = (u32)bank; + u32 byte; + int rc; + + rc = npcm_otp_check_inputs(bank, word + size - 1); + if (rc != 0) + return rc; + + for (byte = 0; byte < size; byte++) { + u8 val; + + val = data[byte]; + if (val == 0) // optimization + continue; + + rc = npcm_otp_program_byte(arr, word + byte, data[byte]); + if (rc != 0) + return rc; + + // verify programming of every '1' bit + val = 0; + npcm_otp_read_byte((u32)bank, byte, &val); + if ((data[byte] & ~val) != 0) + return -1; + } + + return 0; +} + +int fuse_prog_image(u32 bank, uintptr_t address) +{ + return fuse_program_data(bank, 0, (u8 *)address, NPCM_OTP_ARR_BYTE_SIZE); +} + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + int rc = npcm_otp_check_inputs(bank, word); + + if (rc != 0) + return rc; + + *val = 0; + npcm_otp_read_byte((u32)bank, word, (u8 *)val); + + return 0; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + /* We do not support overriding */ + return -EINVAL; +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + int rc; + + rc = npcm_otp_check_inputs(bank, word); + if (rc != 0) + return rc; + + return npcm_otp_program_byte(bank, word, (u8)val); +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + /* We do not support overriding */ + return -EINVAL; +} + +static int npcm_otp_bind(struct udevice *dev) +{ + struct npcm_otp_regs *regs; + + otp_priv = calloc(1, sizeof(struct npcm_otp_priv)); + if (!otp_priv) + return -ENOMEM; + + regs = dev_remap_addr_index(dev, 0); + if (!regs) { + printf("Cannot find reg address (arr #0), binding failed\n"); + return -EINVAL; + } + otp_priv->regs[0] = regs; + + if (IS_ENABLED(CONFIG_ARCH_NPCM7xx)) { + regs = dev_remap_addr_index(dev, 1); + if (!regs) { + printf("Cannot find reg address (arr #1), binding failed\n"); + return -EINVAL; + } + otp_priv->regs[1] = regs; + } + printf("OTP: NPCM OTP module bind OK\n"); + + return 0; +} + +static const struct udevice_id npcm_otp_ids[] = { + { .compatible = "nuvoton,npcm845-otp" }, + { .compatible = "nuvoton,npcm750-otp" }, + { } +}; + +U_BOOT_DRIVER(npcm_otp) = { + .name = "npcm_otp", + .id = UCLASS_MISC, + .of_match = npcm_otp_ids, + .priv_auto = sizeof(struct npcm_otp_priv), + .bind = npcm_otp_bind, +}; From 781a144a7a7e1c3efea94b1a8be8ea65f5e0ac13 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 22 Jun 2022 11:23:03 -0400 Subject: [PATCH 21/22] gxp: Convert to text file environment Convert this platform to using the text file environment rather than defining CONFIG_EXTRA_ENV_SETTINGS. Signed-off-by: Tom Rini --- board/hpe/gxp/gxp.env | 27 +++++++++++++++++++++++++++ include/configs/gxp.h | 28 ---------------------------- 2 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 board/hpe/gxp/gxp.env diff --git a/board/hpe/gxp/gxp.env b/board/hpe/gxp/gxp.env new file mode 100644 index 0000000000..4760bf1663 --- /dev/null +++ b/board/hpe/gxp/gxp.env @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +recover_file=openbmc-hpe-recovery-image.mtd +recover_cmd=usb start; mw.b 0xD100000D 0x40; + if fatload usb 0 0x50000000 $recover_file 0x4C0000 0x80000; then + setenv bootargs console=ttyS0,115200 recovery; + setenv force_recovery; + saveenv; + bootm 0x50000000; + else + while itest 0 < 1; do + mw.b 0xd1000005 0xc0; + sleep .1; + mw.b 0xd1000005 0x00; + sleep .1; + done; + fi; + reset; +spiboot=if itest.b *0xD10000B2 == 6; then + run recover_cmd; + fi; + if printenv force_recovery; then + run recover_cmd; + else + bootm 0xfc080000; + run recover_cmd; + fi; diff --git a/include/configs/gxp.h b/include/configs/gxp.h index ae46126399..e3c97b20d5 100644 --- a/include/configs/gxp.h +++ b/include/configs/gxp.h @@ -12,32 +12,4 @@ #define CONFIG_SYS_SDRAM_BASE 0x40000000 -#define CONFIG_EXTRA_ENV_SETTINGS \ - "recover_file=openbmc-hpe-recovery-image.mtd\0" \ - "recover_cmd=usb start; " \ - "mw.b 0xD100000D 0x40; " \ - "if fatload usb 0 0x50000000 $recover_file 0x4C0000 0x80000; then " \ - "setenv bootargs console=ttyS0,115200 recovery; " \ - "setenv force_recovery; " \ - "saveenv; " \ - "bootm 0x50000000; " \ - "else " \ - "while itest 0 < 1; do " \ - "mw.b 0xd1000005 0xc0; " \ - "sleep .1; " \ - "mw.b 0xd1000005 0x00; " \ - "sleep .1; " \ - "done; " \ - "fi; " \ - "reset;\0" \ - "spiboot=if itest.b *0xD10000B2 == 6; then " \ - "run recover_cmd;" \ - "fi;" \ - "if printenv force_recovery; then " \ - "run recover_cmd; " \ - "else " \ - "bootm 0xfc080000; " \ - "run recover_cmd; " \ - "fi;\0" - #endif From 929e581a620feba40bea659725f88b338d8b65ec Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 22 Jun 2022 11:25:52 -0400 Subject: [PATCH 22/22] corstone1000: Convert to text file environment Convert this platform to using the text file environment rather than defining CONFIG_EXTRA_ENV_SETTINGS. Signed-off-by: Tom Rini --- board/armltd/corstone1000/corstone1000.env | 13 +++++++++++++ include/configs/corstone1000.h | 14 -------------- 2 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 board/armltd/corstone1000/corstone1000.env diff --git a/board/armltd/corstone1000/corstone1000.env b/board/armltd/corstone1000/corstone1000.env new file mode 100644 index 0000000000..b24ff07fc6 --- /dev/null +++ b/board/armltd/corstone1000/corstone1000.env @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +usb_pgood_delay=250 +boot_bank_flag=0x08002000 +kernel_addr_bank_0=0x083EE000 +kernel_addr_bank_1=0x0936E000 +retrieve_kernel_load_addr= + if itest.l *${boot_bank_flag} == 0; then + setenv kernel_addr $kernel_addr_bank_0; + else + setenv kernel_addr $kernel_addr_bank_1; + fi; +kernel_addr_r=0x88200000 diff --git a/include/configs/corstone1000.h b/include/configs/corstone1000.h index eba5cba0fb..38d7fe8d0d 100644 --- a/include/configs/corstone1000.h +++ b/include/configs/corstone1000.h @@ -24,18 +24,4 @@ #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_EXTRA_ENV_SETTINGS \ - "usb_pgood_delay=250\0" \ - "boot_bank_flag=0x08002000\0" \ - "kernel_addr_bank_0=0x083EE000\0" \ - "kernel_addr_bank_1=0x0936E000\0" \ - "retrieve_kernel_load_addr=" \ - "if itest.l *${boot_bank_flag} == 0; then " \ - "setenv kernel_addr $kernel_addr_bank_0;" \ - "else " \ - "setenv kernel_addr $kernel_addr_bank_1;" \ - "fi;" \ - "\0" \ - "kernel_addr_r=0x88200000\0" - #endif