From abf2678f0f0d796295f3bfbe422436292e0795f7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Feb 2019 11:44:39 +0100 Subject: stm32mp1: add trusted boot with TF-A Add support of trusted boot, using TF-A as first stage bootloader, The boot sequence is BootRom >=> TF-A.stm32 (clock & DDR) >=> U-Boot.stm32 The TF-A monitor provides secure monitor with support of SMC - proprietary to manage secure devices (BSEC for example) - PSCI for power The same device tree is used for STMicroelectronics boards with basic boot and with trusted boot. Signed-off-by: Patrick Delaunay --- arch/arm/Kconfig | 6 ++-- arch/arm/mach-stm32mp/Kconfig | 17 +++++++++-- arch/arm/mach-stm32mp/config.mk | 15 +++++++++- arch/arm/mach-stm32mp/cpu.c | 9 ++++-- board/st/stm32mp1/MAINTAINERS | 5 ++-- board/st/stm32mp1/README | 56 ++++++++++++++++++++++++----------- configs/stm32mp15_trusted_defconfig | 58 +++++++++++++++++++++++++++++++++++++ drivers/clk/clk_stm32mp1.c | 2 ++ drivers/ram/stm32mp1/stm32mp1_ram.c | 3 +- include/configs/stm32mp1.h | 2 ++ 10 files changed, 145 insertions(+), 28 deletions(-) create mode 100644 configs/stm32mp15_trusted_defconfig diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4a23e327df..764547091c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1406,8 +1406,10 @@ config ARCH_STM32MP help Support for STM32MP SoC family developed by STMicroelectronics, MPUs based on ARM cortex A core - U-BOOT is running in DDR and SPL support is the unsecure First Stage - BootLoader (FSBL) + U-BOOT is running in DDR, loaded by the First Stage BootLoader (FSBL). + FSBL can be TF-A: Trusted Firmware for Cortex A, for trusted boot + chain. + SPL is the unsecure FSBL for the basic boot chain. config ARCH_ROCKCHIP bool "Support Rockchip SoCs" diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 8a929fa913..3101d80f18 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -25,19 +25,30 @@ config SYS_SOC config TARGET_STM32MP1 bool "Support stm32mp1xx" - select ARCH_SUPPORT_PSCI + select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED select CPU_V7A - select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_NONSEC if !STM32MP1_TRUSTED select CPU_V7_HAS_VIRT select PINCTRL_STM32 select STM32_RCC select STM32_RESET select SYS_ARCH_TIMER - select SYSRESET_SYSCON + imply SYSRESET_PSCI if STM32MP1_TRUSTED + imply SYSRESET_SYSCON if !STM32MP1_TRUSTED help target STMicroelectronics SOC STM32MP1 family STMicroelectronics MPU with core ARMv7 +config STM32MP1_TRUSTED + bool "Support trusted boot with TF-A" + default y if !SPL + select ARM_SMCCC + help + Say Y here to enable boot with TF-A + Trusted boot chain is : + BootRom => TF-A.stm32 (clock & DDR) => U-Boot.stm32 + TF-A monitor provides proprietary smc to manage secure devices + config SYS_TEXT_BASE prompt "U-Boot base address" default 0xC0100000 diff --git a/arch/arm/mach-stm32mp/config.mk b/arch/arm/mach-stm32mp/config.mk index f371aac75b..403af2a225 100644 --- a/arch/arm/mach-stm32mp/config.mk +++ b/arch/arm/mach-stm32mp/config.mk @@ -3,7 +3,20 @@ # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # -ALL-$(CONFIG_SPL_BUILD) += u-boot-spl.stm32 +ifndef CONFIG_SPL +ALL-y += u-boot.stm32 +else +ifdef CONFIG_SPL_BUILD +ALL-y += u-boot-spl.stm32 +endif +endif + +MKIMAGEFLAGS_u-boot.stm32 = -T stm32image -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) + +u-boot.stm32: MKIMAGEOUTPUT = u-boot.stm32.log + +u-boot.stm32: u-boot.bin FORCE + $(call if_changed,mkimage) MKIMAGEFLAGS_u-boot-spl.stm32 = -T stm32image -a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index b8933587ad..b96720fe5a 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -59,6 +59,7 @@ #define BSEC_OTP_MAC 57 #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) +#ifndef CONFIG_STM32MP1_TRUSTED static void security_init(void) { /* Disable the backup domain write protection */ @@ -114,6 +115,7 @@ static void security_init(void) */ writel(0x0, TAMP_CR1); } +#endif /* CONFIG_STM32MP1_TRUSTED */ /* * Debug init @@ -130,7 +132,8 @@ static void dbgmcu_init(void) static u32 get_bootmode(void) { u32 boot_mode; -#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_STM32MP1_TRUSTED) && \ + (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) u32 bootrom_itf = readl(BOOTROM_PARAM_ADDR); u32 bootrom_device, bootrom_instance; @@ -167,8 +170,9 @@ int arch_cpu_init(void) #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) dbgmcu_init(); - +#ifndef CONFIG_STM32MP1_TRUSTED security_init(); +#endif #endif /* get bootmode from BootRom context: saved in TAMP register */ @@ -177,6 +181,7 @@ int arch_cpu_init(void) if ((boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART) gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE; #if defined(CONFIG_DEBUG_UART) && \ + !defined(CONFIG_STM32MP1_TRUSTED) && \ (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) else debug_uart_init(); diff --git a/board/st/stm32mp1/MAINTAINERS b/board/st/stm32mp1/MAINTAINERS index 48d8fd2c3f..0a2eddbe03 100644 --- a/board/st/stm32mp1/MAINTAINERS +++ b/board/st/stm32mp1/MAINTAINERS @@ -2,7 +2,8 @@ STM32MP1 BOARD M: Patrick Delaunay L: uboot-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers) S: Maintained +F: arch/arm/dts/stm32mp157* F: board/st/stm32mp1 -F: include/configs/stm32mp1.h F: configs/stm32mp15_basic_defconfig -F: arch/arm/dts/stm32mp157* +F: configs/stm32mp15_trusted_defconfig +F: include/configs/stm32mp1.h diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 174e6db148..1c3e865e20 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -28,7 +28,6 @@ Everything is supported in Linux but U-Boot is limited to: And the necessary drivers 1. I2C -2. STPMU1 2. STPMU1 (PMIC and regulator) 3. Clock, Reset, Sysreset 4. Fuse @@ -45,15 +44,22 @@ BootRom => FSBL in SYSRAM => SSBL in DDR => OS (Linux Kernel) with FSBL = First Stage Bootloader SSBL = Second Stage Bootloader -One boot configuration is supported: +2 boot configurations are supported: - The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig) +1) The "Trusted" boot chain (defconfig_file : stm32mp15_trusted_defconfig) + BootRom => FSBL = Trusted Firmware-A (TF-A) => SSBL = U-Boot + TF-A performs a full initialization of Secure peripherals and installs a + secure monitor. + U-Boot is running in normal world and uses TF-A monitor + to access to secure resources + +2) The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig) BootRom => FSBL = U-Boot SPL => SSBL = U-Boot SPL has limited security initialisation U-Boot is running in secure mode and provide a secure monitor to the kernel with only PSCI support (Power State Coordination Interface defined by ARM) -All the STM32MP1 board supported by U-Boot use the same generic board +All the STM32MP1 boards supported by U-Boot use the same generic board stm32mp1 which support all the bootable devices. Each board is configurated only with the associated device tree. @@ -90,12 +96,14 @@ the supported device trees for stm32mp157 are: # export KBUILD_OUTPUT=/path/to/output for example: use one output directory for each configuration + # export KBUILD_OUTPUT=stm32mp15_trusted # export KBUILD_OUTPUT=stm32mp15_basic -4. Configure the U-Boot: +4. Configure U-Boot: # make + - For trusted boot mode : "stm32mp15_trusted_defconfig" - For basic boot mode: "stm32mp15_basic_defconfig" 5. Configure the device-tree and build the U-Boot image: @@ -104,12 +112,17 @@ the supported device trees for stm32mp157 are: example: - basic boot on ev1 + a) trusted boot on ev1 + # export KBUILD_OUTPUT=stm32mp15_trusted + # make stm32mp15_trusted_defconfig + # make DEVICE_TREE=stm32mp157c-ev1 all + + b) basic boot on ev1 # export KBUILD_OUTPUT=stm32mp15_basic # make stm32mp15_basic_defconfig # make DEVICE_TREE=stm32mp157c-ev1 all - basic boot on ed1 + c) basic boot on ed1 # export KBUILD_OUTPUT=stm32mp15_basic # make stm32mp15_basic_defconfig # make DEVICE_TREE=stm32mp157c-ed1 all @@ -122,6 +135,11 @@ the supported device trees for stm32mp157 are: So in the output directory (selected by KBUILD_OUTPUT), you can found the needed files: + a) For Trusted boot + + FSBL = tf-a.stm32 (provided by TF-A compilation) + + SSBL = u-boot.stm32 + + b) For Basic boot + FSBL = spl/u-boot-spl.stm32 + SSBL = u-boot.img @@ -135,7 +153,6 @@ You can select the boot mode, on the board ed1 with the switch SW1 ----------------------------------- Reserved 0 0 0 NOR 0 0 1 - SD-Card 1 1 1 SD-Card 1 0 1 eMMC 0 1 0 NAND 0 1 1 @@ -158,14 +175,14 @@ The minimal requirements for STMP32MP1 boot up to U-Boot are: - one ssbl partition for U-Boot Then the minimal GPT partition is: - ----- ------- --------- ------------- - | Num | Name | Size | Content | - ----- ------- -------- -------------- + ----- ------- --------- -------------- + | Num | Name | Size | Content | + ----- ------- -------- --------------- | 1 | fsbl1 | 256 KiB | TF-A or SPL | | 2 | fsbl2 | 256 KiB | TF-A or SPL | - | 3 | ssbl | enought | U-Boot | - | * | - | - | Boot/Rootfs| - ----- ------- --------- ------------- + | 3 | ssbl | enought | U-Boot | + | * | - | - | Boot/Rootfs | + ----- ------- --------- -------------- (*) add bootable partition for extlinux.conf following Generic Distribution @@ -189,7 +206,7 @@ for example: with gpt table with 128 entries you can add other partitions for kernel one partition rootfs for example: - -n 3:5154: -c 4:rootfs + -n 4:5154: -c 4:rootfs \ c) copy the FSBL (2 times) and SSBL file on the correct partition. in this example in partition 1 to 3 @@ -199,6 +216,11 @@ for example: with gpt table with 128 entries # dd if=u-boot-spl.stm32 of=/dev/mmcblk0p2 # dd if=u-boot.img of=/dev/mmcblk0p3 + for trusted boot mode : + # dd if=tf-a.stm32 of=/dev/mmcblk0p1 + # dd if=tf-a.stm32 of=/dev/mmcblk0p2 + # dd if=u-boot.stm32 of=/dev/mmcblk0p3 + To boot from SDCard, select BootPinMode = 1 1 1 and reset. 8. Prepare eMMC @@ -208,7 +230,7 @@ You can use U-Boot to copy binary in eMMC. In the next example, you need to boot from SDCARD and the images (u-boot-spl.stm32, u-boot.img) are presents on SDCARD (mmc 0) in ext4 partition 4 (bootfs). -To boot from SDCard, select BootPinMode = 1 1 1 and reset. +To boot from SDCard, select BootPinMode = 1 0 1 and reset. Then you update the eMMC with the next U-Boot command : @@ -227,7 +249,7 @@ b) copy SPL on eMMC on firts boot partition # mmc write ${fileaddr} 0 200 # mmc partconf 1 1 1 0 -b) copy U-Boot in first GPT partition of eMMC +c) copy U-Boot in first GPT partition of eMMC # ext4load mmc 0:4 0xC0000000 u-boot.img # mmc dev 1 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig new file mode 100644 index 0000000000..62ab010e91 --- /dev/null +++ b/configs/stm32mp15_trusted_defconfig @@ -0,0 +1,58 @@ +CONFIG_ARM=y +CONFIG_ARCH_STM32MP=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_TARGET_STM32MP1=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_PROMPT="STM32MP> " +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_EXPORTENV is not set +# CONFIG_CMD_IMPORTENV is not set +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_ADC=y +CONFIG_CMD_CLK=y +CONFIG_CMD_FUSE=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_STM32_ADC=y +CONFIG_DM_HWSPINLOCK=y +CONFIG_HWSPINLOCK_STM32=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_STM32F7=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_DM_MMC=y +CONFIG_STM32_SDMMC2=y +CONFIG_PHY=y +CONFIG_PHY_STM32_USBPHYC=y +# CONFIG_PINCTRL_FULL is not set +CONFIG_DM_PMIC=y +CONFIG_PMIC_STPMU1=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_DM_REGULATOR_STM32_VREFBUF=y +CONFIG_DM_REGULATOR_STPMU1=y +CONFIG_SERIAL_RX_BUFFER=y +CONFIG_STM32_SERIAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_DWC2=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" +CONFIG_USB_GADGET_VENDOR_NUM=0x0483 +CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index aebc6f0a34..24859fd054 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -15,10 +15,12 @@ #include #include +#ifndef CONFIG_STM32MP1_TRUSTED #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) /* activate clock tree initialization in the driver */ #define STM32MP1_CLOCK_TREE_INIT #endif +#endif #define MAX_HSI_HZ 64000000 diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index bd497a3021..e45a3b2658 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -157,7 +157,8 @@ static int stm32mp1_ddr_probe(struct udevice *dev) priv->info.base = STM32_DDR_BASE; -#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_STM32MP1_TRUSTED) && \ + (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) priv->info.size = 0; return stm32mp1_ddr_setup(dev); #else diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 701298cab8..4722672ff1 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -17,10 +17,12 @@ */ #define CONFIG_SYS_HZ 1000 +#ifndef CONFIG_STM32MP1_TRUSTED /* PSCI support */ #define CONFIG_ARMV7_PSCI_1_0 #define CONFIG_ARMV7_SECURE_BASE STM32_SYSRAM_BASE #define CONFIG_ARMV7_SECURE_MAX_SIZE STM32_SYSRAM_SIZE +#endif /* * malloc() pool size -- cgit From d859c611397b90ea4a96d18dcdbfe4f6ce7c231c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Feb 2019 11:44:40 +0100 Subject: stm32mp1: bsec: access with SMC for trusted boot As BSEC is secure aware, all register access need to be done by TF-A for TRUSTED boot chain, when U-Boot is executed in normal world. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/bsec.c | 28 ++++++++++ arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h | 64 +++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index d087a31389..920a6c9191 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -8,9 +8,12 @@ #include #include #include +#include +#include #define BSEC_OTP_MAX_VALUE 95 +#ifndef CONFIG_STM32MP1_TRUSTED #define BSEC_TIMEOUT_US 10000 /* BSEC REGISTER OFFSET (base relative) */ @@ -270,6 +273,7 @@ static int bsec_program_otp(long base, u32 val, u32 otp) return ret; } +#endif /* CONFIG_STM32MP1_TRUSTED */ /* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_platdata { @@ -278,6 +282,11 @@ struct stm32mp_bsec_platdata { static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp) { +#ifdef CONFIG_STM32MP1_TRUSTED + return stm32_smc(STM32_SMC_BSEC, + STM32_SMC_READ_OTP, + otp, 0, val); +#else struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); u32 tmp_data = 0; int ret; @@ -299,27 +308,46 @@ static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp) /* restore shadow value */ ret = bsec_write_shadow(plat->base, tmp_data, otp); return ret; +#endif } static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) { +#ifdef CONFIG_STM32MP1_TRUSTED + return stm32_smc(STM32_SMC_BSEC, + STM32_SMC_READ_SHADOW, + otp, 0, val); +#else struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); return bsec_read_shadow(plat->base, val, otp); +#endif } static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp) { +#ifdef CONFIG_STM32MP1_TRUSTED + return stm32_smc_exec(STM32_SMC_BSEC, + STM32_SMC_PROG_OTP, + otp, val); +#else struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); return bsec_program_otp(plat->base, val, otp); +#endif } static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp) { +#ifdef CONFIG_STM32MP1_TRUSTED + return stm32_smc_exec(STM32_SMC_BSEC, + STM32_SMC_WRITE_SHADOW, + otp, val); +#else struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); return bsec_write_shadow(plat->base, val, otp); +#endif } static int stm32mp_bsec_read(struct udevice *dev, int offset, diff --git a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h new file mode 100644 index 0000000000..8130546b27 --- /dev/null +++ b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ + +#ifndef __STM32MP1_SMC_H__ +#define __STM32MP1_SMC_H__ + +#include + +/* + * SMC function IDs for STM32 Service queries + * STM32 SMC services use the space between 0x82000000 and 0x8200FFFF + * like this is defined in SMC calling Convention by ARM + * for SiP (silicon Partner) + * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + */ +#define STM32_SMC_VERSION 0x82000000 + +/* Secure Service access from Non-secure */ +#define STM32_SMC_BSEC 0x82001003 + +/* Service for BSEC */ +#define STM32_SMC_READ_SHADOW 0x01 +#define STM32_SMC_PROG_OTP 0x02 +#define STM32_SMC_WRITE_SHADOW 0x03 +#define STM32_SMC_READ_OTP 0x04 +#define STM32_SMC_READ_ALL 0x05 +#define STM32_SMC_WRITE_ALL 0x06 + +/* SMC error codes */ +#define STM32_SMC_OK 0x0 +#define STM32_SMC_NOT_SUPPORTED -1 +#define STM32_SMC_FAILED -2 +#define STM32_SMC_INVALID_PARAMS -3 + +#define stm32_smc_exec(svc, op, data1, data2) \ + stm32_smc(svc, op, data1, data2, NULL) + +#ifdef CONFIG_ARM_SMCCC +static inline u32 stm32_smc(u32 svc, u8 op, u32 data1, u32 data2, u32 *result) +{ + struct arm_smccc_res res; + + arm_smccc_smc(svc, op, data1, data2, 0, 0, 0, 0, &res); + + if (res.a0) { + pr_err("%s: Failed to exec in secure mode (err = %ld)\n", + __func__, res.a0); + return -EINVAL; + } + if (result) + *result = (u32)res.a1; + + return 0; +} +#else +static inline u32 stm32_smc(u32 svc, u8 op, u32 data1, u32 data2, u32 *result) +{ + return 0; +} +#endif + +#endif /* __STM32MP1_SMC_H__ */ -- cgit From d461f1003627043e4385a2f15093f92d3008e86b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Feb 2019 11:44:41 +0100 Subject: stm32mp1: display board information Implement checkboard() function to display - the boot chain used: basic or trusted - the board compatible in device tree - the board identifier and revision, saved in OTP59 for ST boards Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/include/mach/stm32.h | 4 +++ board/st/stm32mp1/stm32mp1.c | 44 ++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 5d0bdca178..85d783cccb 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -98,7 +98,11 @@ enum boot_device { /* offset used for BSEC driver: misc_read and misc_write */ #define STM32_BSEC_SHADOW_OFFSET 0x0 +#define STM32_BSEC_SHADOW(id) (STM32_BSEC_SHADOW_OFFSET + (id) * 4) #define STM32_BSEC_OTP_OFFSET 0x80000000 +#define STM32_BSEC_OTP(id) (STM32_BSEC_OTP_OFFSET + (id) * 4) + +#define BSEC_OTP_BOARD 59 #endif /* __ASSEMBLY__*/ #endif /* _MACH_STM32_H_ */ diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 54feca0ecf..07d1addb2a 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -3,11 +3,12 @@ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ #include -#include -#include #include +#include #include #include +#include +#include #include #include #include @@ -26,6 +27,45 @@ DECLARE_GLOBAL_DATA_PTR; #define STM32MP_GGPIO 0x38 #define STM32MP_GGPIO_VBUS_SENSING BIT(21) +int checkboard(void) +{ + int ret; + char *mode; + u32 otp; + struct udevice *dev; + const char *fdt_compat; + int fdt_compat_len; + + if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED)) + mode = "trusted"; + else + mode = "basic"; + + printf("Board: stm32mp1 in %s mode", mode); + fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible", + &fdt_compat_len); + if (fdt_compat && fdt_compat_len) + printf(" (%s)", fdt_compat); + puts("\n"); + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + + if (!ret) + ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD), + &otp, sizeof(otp)); + if (!ret && otp) { + printf("Board: MB%04x Var%d Rev.%c-%02d\n", + otp >> 16, + (otp >> 12) & 0xF, + ((otp >> 8) & 0xF) - 1 + 'A', + otp & 0xF); + } + + return 0; +} + static struct dwc2_plat_otg_data stm32mp_otg_data = { .usb_gusbcfg = STM32MP_GUSBCFG, }; -- cgit From b4ae34b66b2d5447e0422e03bf88dd0fde31dea0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:11 +0100 Subject: stm32mp1: add runtime information in environment Set board name with the first dts compatible found in DT code under CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG The result with DEVICE_TREE=stm32mp157c-ev1 is: STM32MP> env print board=stm32mp1 board_name=stm32mp157c-ev1 Signed-off-by: Patrick Delaunay --- arch/arm/Kconfig | 1 + board/st/stm32mp1/stm32mp1.c | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 764547091c..33628b86d4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1403,6 +1403,7 @@ config ARCH_STM32MP select SYSRESET select SYS_THUMB_BUILD imply CMD_DM + imply ENV_VARS_UBOOT_RUNTIME_CONFIG help Support for STM32MP SoC family developed by STMicroelectronics, MPUs based on ARM cortex A core diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 07d1addb2a..48da4599ab 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -220,11 +220,6 @@ int board_usb_cleanup(int index, enum usb_init_type init) return 0; } -int board_late_init(void) -{ - return 0; -} - /* board dependent setup after realloc */ int board_init(void) { @@ -236,3 +231,22 @@ int board_init(void) return 0; } + +int board_late_init(void) +{ +#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG + const void *fdt_compat; + int fdt_compat_len; + + fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible", + &fdt_compat_len); + if (fdt_compat && fdt_compat_len) { + if (strncmp(fdt_compat, "st,", 3) != 0) + env_set("board_name", fdt_compat); + else + env_set("board_name", fdt_compat + 3); + } +#endif + + return 0; +} -- cgit From 7f63c1e687ce833d0ef12778ff46868c5458d08d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:12 +0100 Subject: stm32mp1: update boot mode management - export the function get_bootmode() and reused it in spl code - manage uart instance by alias (prepare v4.19 binding) - solve issue on nand instance - restore console for uart boot Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 57 +++++++++++++++++++++----- arch/arm/mach-stm32mp/include/mach/stm32.h | 3 -- arch/arm/mach-stm32mp/include/mach/sys_proto.h | 2 + arch/arm/mach-stm32mp/spl.c | 18 +++++++- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index b96720fe5a..753ff3e4db 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -129,14 +129,19 @@ static void dbgmcu_init(void) } #endif /* !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) */ -static u32 get_bootmode(void) -{ - u32 boot_mode; #if !defined(CONFIG_STM32MP1_TRUSTED) && \ (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) +/* get bootmode from ROM code boot context: saved in TAMP register */ +static void update_bootmode(void) +{ + u32 boot_mode; u32 bootrom_itf = readl(BOOTROM_PARAM_ADDR); u32 bootrom_device, bootrom_instance; + /* enable TAMP clock = RTCAPBEN */ + writel(BIT(8), RCC_MP_APB5ENSETR); + + /* read bootrom context */ bootrom_device = (bootrom_itf & BOOTROM_MODE_MASK) >> BOOTROM_MODE_SHIFT; bootrom_instance = @@ -150,12 +155,14 @@ static u32 get_bootmode(void) clrsetbits_le32(TAMP_BOOT_CONTEXT, TAMP_BOOT_MODE_MASK, boot_mode << TAMP_BOOT_MODE_SHIFT); -#else - /* read TAMP backup register */ - boot_mode = (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >> - TAMP_BOOT_MODE_SHIFT; +} #endif - return boot_mode; + +u32 get_bootmode(void) +{ + /* read bootmode from TAMP backup register */ + return (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >> + TAMP_BOOT_MODE_SHIFT; } /* @@ -172,10 +179,10 @@ int arch_cpu_init(void) dbgmcu_init(); #ifndef CONFIG_STM32MP1_TRUSTED security_init(); + update_bootmode(); #endif #endif - /* get bootmode from BootRom context: saved in TAMP register */ boot_mode = get_bootmode(); if ((boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART) @@ -247,20 +254,48 @@ int print_cpuinfo(void) static void setup_boot_mode(void) { + const u32 serial_addr[] = { + STM32_USART1_BASE, + STM32_USART2_BASE, + STM32_USART3_BASE, + STM32_UART4_BASE, + STM32_UART5_BASE, + STM32_USART6_BASE, + STM32_UART7_BASE, + STM32_UART8_BASE + }; char cmd[60]; u32 boot_ctx = readl(TAMP_BOOT_CONTEXT); u32 boot_mode = (boot_ctx & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT; int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1; + struct udevice *dev; + int alias; pr_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d\n", __func__, boot_ctx, boot_mode, instance); switch (boot_mode & TAMP_BOOT_DEVICE_MASK) { case BOOT_SERIAL_UART: - sprintf(cmd, "%d", instance); - env_set("boot_device", "uart"); + if (instance > ARRAY_SIZE(serial_addr)) + break; + /* serial : search associated alias in devicetree */ + sprintf(cmd, "serial@%x", serial_addr[instance]); + if (uclass_get_device_by_name(UCLASS_SERIAL, cmd, &dev)) + break; + if (fdtdec_get_alias_seq(gd->fdt_blob, "serial", + dev_of_offset(dev), &alias)) + break; + sprintf(cmd, "%d", alias); + env_set("boot_device", "serial"); env_set("boot_instance", cmd); + + /* restore console on uart when not used */ + if (gd->cur_serial_dev != dev) { + gd->flags &= ~(GD_FLG_SILENT | + GD_FLG_DISABLE_CONSOLE); + printf("serial boot with console enabled!\n"); + } break; case BOOT_SERIAL_USB: env_set("boot_device", "usb"); diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 85d783cccb..f2ab026a5a 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -18,8 +18,6 @@ #define STM32_ETZPC_BASE 0x5C007000 #define STM32_TAMP_BASE 0x5C00A000 -#ifdef CONFIG_DEBUG_UART_BASE -/* hardcoded value can be only used for DEBUG UART */ #define STM32_USART1_BASE 0x5C000000 #define STM32_USART2_BASE 0x4000E000 #define STM32_USART3_BASE 0x4000F000 @@ -28,7 +26,6 @@ #define STM32_USART6_BASE 0x44003000 #define STM32_UART7_BASE 0x40018000 #define STM32_UART8_BASE 0x40019000 -#endif #define STM32_SYSRAM_BASE 0x2FFC0000 #define STM32_SYSRAM_SIZE SZ_256K diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 41d4b40bcb..8b426c08f6 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -13,3 +13,5 @@ u32 get_cpu_type(void); /* return CPU_REV constants */ u32 get_cpu_rev(void); +/* return boot mode */ +u32 get_bootmode(void); diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 790973e8b6..c6ae73d600 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -12,8 +12,7 @@ u32 spl_boot_device(void) { u32 boot_mode; - boot_mode = (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >> - TAMP_BOOT_MODE_SHIFT; + boot_mode = get_bootmode(); switch (boot_mode) { case BOOT_FLASH_SD_1: @@ -22,6 +21,21 @@ u32 spl_boot_device(void) case BOOT_FLASH_SD_2: case BOOT_FLASH_EMMC_2: return BOOT_DEVICE_MMC2; + case BOOT_SERIAL_UART_1: + case BOOT_SERIAL_UART_2: + case BOOT_SERIAL_UART_3: + case BOOT_SERIAL_UART_4: + case BOOT_SERIAL_UART_5: + case BOOT_SERIAL_UART_6: + case BOOT_SERIAL_UART_7: + case BOOT_SERIAL_UART_8: + return BOOT_DEVICE_UART; + case BOOT_SERIAL_USB_OTG: + return BOOT_DEVICE_USB; + case BOOT_FLASH_NAND_FMC: + return BOOT_DEVICE_NAND; + case BOOT_FLASH_NOR_QSPI: + return BOOT_DEVICE_SPI; } return BOOT_DEVICE_MMC1; -- cgit From 35d568f090ec853efa1b0b5409cc89c0f0dfa7e7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:13 +0100 Subject: stm32mp1: update print_cpuinfo() Display CPU part number and package information. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 102 +++++++++++++++++++++++-- arch/arm/mach-stm32mp/include/mach/sys_proto.h | 10 ++- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 753ff3e4db..206b82e9e9 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -55,9 +55,30 @@ #define BOOTROM_INSTANCE_SHIFT 16 /* BSEC OTP index */ +#define BSEC_OTP_RPN 1 #define BSEC_OTP_SERIAL 13 +#define BSEC_OTP_PKG 16 #define BSEC_OTP_MAC 57 +/* Device Part Number (RPN) = OTP_DATA1 lower 8 bits */ +#define RPN_SHIFT 0 +#define RPN_MASK GENMASK(7, 0) + +/* Package = bit 27:29 of OTP16 + * - 100: LBGA448 (FFI) => AA = LFBGA 18x18mm 448 balls p. 0.8mm + * - 011: LBGA354 (LCI) => AB = LFBGA 16x16mm 359 balls p. 0.8mm + * - 010: TFBGA361 (FFC) => AC = TFBGA 12x12mm 361 balls p. 0.5mm + * - 001: TFBGA257 (LCC) => AD = TFBGA 10x10mm 257 balls p. 0.5mm + * - others: Reserved + */ +#define PKG_SHIFT 27 +#define PKG_MASK GENMASK(2, 0) + +#define PKG_AA_LBGA448 4 +#define PKG_AB_LBGA354 3 +#define PKG_AC_TFBGA361 2 +#define PKG_AD_TFBGA257 1 + #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) #ifndef CONFIG_STM32MP1_TRUSTED static void security_init(void) @@ -215,25 +236,94 @@ u32 get_cpu_rev(void) return (read_idc() & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT; } +static u32 get_otp(int index, int shift, int mask) +{ + int ret; + struct udevice *dev; + u32 otp = 0; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + + if (!ret) + ret = misc_read(dev, STM32_BSEC_SHADOW(index), + &otp, sizeof(otp)); + + return (otp >> shift) & mask; +} + +/* Get Device Part Number (RPN) from OTP */ +static u32 get_cpu_rpn(void) +{ + return get_otp(BSEC_OTP_RPN, RPN_SHIFT, RPN_MASK); +} + u32 get_cpu_type(void) { - return (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT; + u32 id; + + id = (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT; + + return (id << 16) | get_cpu_rpn(); +} + +/* Get Package options from OTP */ +static u32 get_cpu_package(void) +{ + return get_otp(BSEC_OTP_PKG, PKG_SHIFT, PKG_MASK); } #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) { - char *cpu_s, *cpu_r; + char *cpu_s, *cpu_r, *pkg; + /* MPUs Part Numbers */ switch (get_cpu_type()) { - case CPU_STMP32MP15x: - cpu_s = "15x"; + case CPU_STM32MP157Cxx: + cpu_s = "157C"; + break; + case CPU_STM32MP157Axx: + cpu_s = "157A"; + break; + case CPU_STM32MP153Cxx: + cpu_s = "153C"; + break; + case CPU_STM32MP153Axx: + cpu_s = "153A"; + break; + case CPU_STM32MP151Cxx: + cpu_s = "151C"; + break; + case CPU_STM32MP151Axx: + cpu_s = "151A"; + break; + default: + cpu_s = "????"; + break; + } + + /* Package */ + switch (get_cpu_package()) { + case PKG_AA_LBGA448: + pkg = "AA"; + break; + case PKG_AB_LBGA354: + pkg = "AB"; + break; + case PKG_AC_TFBGA361: + pkg = "AC"; + break; + case PKG_AD_TFBGA257: + pkg = "AD"; break; default: - cpu_s = "?"; + pkg = "??"; break; } + /* REVISION */ switch (get_cpu_rev()) { case CPU_REVA: cpu_r = "A"; @@ -246,7 +336,7 @@ int print_cpuinfo(void) break; } - printf("CPU: STM32MP%s.%s\n", cpu_s, cpu_r); + printf("CPU: STM32MP%s%s Rev.%s\n", cpu_s, pkg, cpu_r); return 0; } diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 8b426c08f6..71a3ba794d 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -3,9 +3,15 @@ * Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved */ -#define CPU_STMP32MP15x 0x500 +/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit15:0)*/ +#define CPU_STM32MP157Cxx 0x05000000 +#define CPU_STM32MP157Axx 0x05000001 +#define CPU_STM32MP153Cxx 0x05000024 +#define CPU_STM32MP153Axx 0x05000025 +#define CPU_STM32MP151Cxx 0x0500002E +#define CPU_STM32MP151Axx 0x0500002F -/* return CPU_STMP32MPxx constants */ +/* return CPU_STMP32MP...Xxx constants */ u32 get_cpu_type(void); #define CPU_REVA 0x1000 -- cgit From 006ea18910679f150a8bc0aa5bf92d67f4f8870b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:14 +0100 Subject: stm32mp1: spl: add spl_display_print SPL displays the board model from device tree. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/Kconfig | 1 + arch/arm/mach-stm32mp/spl.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 3101d80f18..d70658a143 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -18,6 +18,7 @@ config SPL select SPL_SERIAL_SUPPORT select SPL_SYSCON select SPL_DRIVERS_MISC_SUPPORT + imply SPL_DISPLAY_PRINT imply SPL_LIBDISK_SUPPORT config SYS_SOC diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index c6ae73d600..501e077fb3 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include u32 spl_boot_device(void) { @@ -58,6 +60,21 @@ int spl_boot_partition(const u32 boot_device) } } +#ifdef CONFIG_SPL_DISPLAY_PRINT +void spl_display_print(void) +{ + DECLARE_GLOBAL_DATA_PTR; + const char *model; + + /* same code than show_board_info() but not compiled for SPL + * see CONFIG_DISPLAY_BOARDINFO & common/board_info.c + */ + model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); + if (model) + printf("Model: %s\n", model); +} +#endif + void board_init_f(ulong dummy) { struct udevice *dev; -- cgit From 45ccdb6fc7142795af40389ea0612e9bd52fd257 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:15 +0100 Subject: stm32mp1: cosmetic cleanup Kconfig Cosmetic cleanup in mach-stm32mp Kconfig - remove duplicated SPL_DRIVERS_MISC_SUPPORT - update help for TARGET_STM32MP1 - set value for NR_DRAM_BANKS - remove one comment as DEBUG_UART is deactivated by default - include board Kconfig at the end of the file Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/Kconfig | 11 +++++++---- configs/stm32mp15_basic_defconfig | 1 - configs/stm32mp15_trusted_defconfig | 1 - 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index d70658a143..73aa382712 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -17,7 +17,6 @@ config SPL select SPL_DM_RESET select SPL_SERIAL_SUPPORT select SPL_SYSCON - select SPL_DRIVERS_MISC_SUPPORT imply SPL_DISPLAY_PRINT imply SPL_LIBDISK_SUPPORT @@ -38,7 +37,9 @@ config TARGET_STM32MP1 imply SYSRESET_SYSCON if !STM32MP1_TRUSTED help target STMicroelectronics SOC STM32MP1 family + STM32MP157, STM32MP153 or STM32MP151 STMicroelectronics MPU with core ARMv7 + dual core A7 for STM32MP157/3, monocore for STM32MP151 config STM32MP1_TRUSTED bool "Support trusted boot with TF-A" @@ -58,6 +59,9 @@ config SYS_TEXT_BASE when DDR driver is used: DDR + 1MB (0xC0100000) +config NR_DRAM_BANKS + default 1 + config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2 hex "Partition on MMC2 to use to load U-Boot from" depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION @@ -66,9 +70,6 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2 Partition on the second MMC to load U-Boot from when the MMC is being used in raw mode -source "board/st/stm32mp1/Kconfig" - -# currently activated for debug / should be deactivated for real product if DEBUG_UART config DEBUG_UART_BOARD_INIT @@ -83,4 +84,6 @@ config DEBUG_UART_CLOCK default 64000000 endif +source "board/st/stm32mp1/Kconfig" + endif diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index d20b2ab350..b1d09fb648 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -5,7 +5,6 @@ CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL=y CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y -CONFIG_NR_DRAM_BANKS=1 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 CONFIG_SPL_I2C_SUPPORT=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 62ab010e91..9be731955a 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -3,7 +3,6 @@ CONFIG_ARCH_STM32MP=y CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y -CONFIG_NR_DRAM_BANKS=1 CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set # CONFIG_CMD_ELF is not set -- cgit From b496eec65d3c138c97f16e905b12b6f36a578d04 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:16 +0100 Subject: stm32mp1: cosmetic: add comment on psci_migrate_info_type return value Add explaination for the return value of psci_migrate_info_type: 2 = Trusted OS. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/psci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 6ed2482080..c2dff38c36 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -103,7 +103,13 @@ int __secure psci_affinity_info(u32 function_id, u32 target_affinity, int __secure psci_migrate_info_type(u32 function_id) { - /* Trusted OS is either not present or does not require migration */ + /* + * in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf + * return 2 = Trusted OS is either not present or does not require + * migration, system of this type does not require the caller + * to use the MIGRATE function. + * MIGRATE function calls return NOT_SUPPORTED. + */ return 2; } -- cgit From 105a5ad614f3cb8491df1825553993a0d45fa857 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:17 +0100 Subject: stm32mp1: spl: hang with trace when DDR init failed When DDR initialization failed, print error message and stop the SPL execution. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/spl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 501e077fb3..a3b0d6f382 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -111,7 +111,7 @@ void board_init_f(ulong dummy) ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { - debug("DRAM init failed: %d\n", ret); - return; + printf("DRAM init failed: %d\n", ret); + hang(); } } -- cgit From 842ebb5f40810c1ccdd45ba80aff7ae5f05512fa Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:18 +0100 Subject: stm32mp1: update bootcmd Clearly separate bootcmd for stm32mp1 board (bootcmd_stm32mp) and preboot management. That solve issue for fastboot continue command. Signed-off-by: Patrick Delaunay --- board/st/stm32mp1/stm32mp1.c | 1 + configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + include/configs/stm32mp1.h | 37 +++++++++++++++++++++++++++---------- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 48da4599ab..0d963c2af4 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index b1d09fb648..4ab29ee195 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -5,6 +5,7 @@ CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL=y CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 CONFIG_SPL_I2C_SUPPORT=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 9be731955a..1bb3d0d7ff 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -3,6 +3,7 @@ CONFIG_ARCH_STM32MP=y CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set # CONFIG_CMD_ELF is not set diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 4722672ff1..48da1e374a 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -10,8 +10,6 @@ #include #include -#define CONFIG_PREBOOT - /* * Number of clock ticks in 1 sec */ @@ -75,20 +73,38 @@ #define CONFIG_SYS_MMC_MAX_DEVICE 3 #define CONFIG_SUPPORT_EMMC_BOOT -#if !defined(CONFIG_SPL) || !defined(CONFIG_SPL_BUILD) +/*****************************************************************************/ +#ifdef CONFIG_DISTRO_DEFAULTS +/*****************************************************************************/ + +#if !defined(CONFIG_SPL_BUILD) #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ func(MMC, mmc, 2) +/* + * bootcmd for stm32mp1: + * for serial/usb: execute the stm32prog command + * for mmc boot (eMMC, SD card), boot only on the same device + * for nand boot, boot with on ubifs partition on nand + * for nor boot, use the default order + */ +#define CONFIG_PREBOOT -#include +#define STM32MP_BOOTCMD "bootcmd_stm32mp=" \ + "echo \"Boot over ${boot_device}${boot_instance}!\";" \ + "if test ${boot_device} = serial || test ${boot_device} = usb;" \ + "then stm32prog ${boot_device} ${boot_instance}; " \ + "else " \ + "if test ${boot_device} = mmc;" \ + "then env set boot_targets \"mmc${boot_instance}\"; fi;" \ + "if test ${boot_device} = nand;" \ + "then env set boot_targets ubifs0; fi;" \ + "run distro_bootcmd;" \ + "fi;\0" -#define STM32MP_PREBOOT \ - "echo \"Boot over ${boot_device}${boot_instance}!\"; " \ - "if test \"${boot_device}\" = \"mmc\"; then " \ - "env set boot_targets \"mmc${boot_instance}\"; "\ - "fi;" +#include #define CONFIG_EXTRA_ENV_SETTINGS \ "scriptaddr=0xC0000000\0" \ @@ -98,9 +114,10 @@ "ramdisk_addr_r=0xC4100000\0" \ "fdt_high=0xffffffff\0" \ "initrd_high=0xffffffff\0" \ - "preboot=" STM32MP_PREBOOT "\0" \ + STM32MP_BOOTCMD \ BOOTENV #endif /* ifndef CONFIG_SPL_BUILD */ +#endif /* ifdef CONFIG_DISTRO_DEFAULTS*/ #endif /* __CONFIG_H */ -- cgit From 4633fd51c5d7f355be792d795467a9222be96c48 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:19 +0100 Subject: stm32mp1: activate FASTBOOT on eMMC activate Fastboot for eMMC on EV1 board (mmc1) $> sudo apt-get install android-tools-adb android-tools-fastboot $> fastboot -i 0x0483 getvar bootloader-version Signed-off-by: Patrick Delaunay --- configs/stm32mp15_basic_defconfig | 7 ++++++- configs/stm32mp15_trusted_defconfig | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 4ab29ee195..2d6a16444e 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -33,6 +33,12 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_STM32_ADC=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 +CONFIG_FASTBOOT_BUF_SIZE=0x02000000 +CONFIG_FASTBOOT_USB_DEV=1 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=1 CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y CONFIG_DM_I2C=y @@ -64,4 +70,3 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 CONFIG_USB_GADGET_DWC2_OTG=y -CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 1bb3d0d7ff..7945e9fb90 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -26,6 +26,12 @@ CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_STM32_ADC=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 +CONFIG_FASTBOOT_BUF_SIZE=0x02000000 +CONFIG_FASTBOOT_USB_DEV=1 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=1 CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y CONFIG_DM_I2C=y @@ -55,4 +61,3 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 CONFIG_USB_GADGET_DWC2_OTG=y -CONFIG_USB_GADGET_DOWNLOAD=y -- cgit From 9a2ba2838bda7baef73b0a4852918415a5d1d442 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:20 +0100 Subject: stm32mp1: support forced boot mode The boot mode can be forced by key press or by TAMP register, requested in kernel by syscon-reboot-mode tamp: tamp@5c00a000 { compatible = "simple-bus", "syscon", "simple-mfd"; reg = <0x5c00a000 0x400>; reboot-mode { compatible = "syscon-reboot-mode"; offset = <0x150>; /* reg20 */ mask = <0xff>; mode-normal = <0>; mode-fastboot = <0x1>; mode-recovery = <0x2>; mode-stm32cubeprogrammer = <0x3>; mode-ums_mmc0 = <0x10>; mode-ums_mmc1 = <0x11>; mode-ums_mmc2 = <0x12>; }; }; Signed-off-by: Patrick Delaunay --- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 5 +++ arch/arm/mach-stm32mp/cpu.c | 36 +++++++++++++++++++-- arch/arm/mach-stm32mp/include/mach/stm32.h | 11 +++++++ board/st/stm32mp1/stm32mp1.c | 51 ++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 70bbf66704..d22401c26e 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -14,6 +14,11 @@ i2c3 = &i2c4; }; + config { + st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; + }; + led { compatible = "gpio-leds"; diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 206b82e9e9..305ea6dd64 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -359,12 +359,12 @@ static void setup_boot_mode(void) u32 boot_mode = (boot_ctx & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT; int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1; + u32 forced_mode = (boot_ctx & TAMP_BOOT_FORCED_MASK); struct udevice *dev; int alias; - pr_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d\n", - __func__, boot_ctx, boot_mode, instance); - + pr_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d forced=%x\n", + __func__, boot_ctx, boot_mode, instance, forced_mode); switch (boot_mode & TAMP_BOOT_DEVICE_MASK) { case BOOT_SERIAL_UART: if (instance > ARRAY_SIZE(serial_addr)) @@ -409,6 +409,36 @@ static void setup_boot_mode(void) pr_debug("unexpected boot mode = %x\n", boot_mode); break; } + + switch (forced_mode) { + case BOOT_FASTBOOT: + printf("Enter fastboot!\n"); + env_set("preboot", "env set preboot; fastboot 0"); + break; + case BOOT_STM32PROG: + env_set("boot_device", "usb"); + env_set("boot_instance", "0"); + break; + case BOOT_UMS_MMC0: + case BOOT_UMS_MMC1: + case BOOT_UMS_MMC2: + printf("Enter UMS!\n"); + instance = forced_mode - BOOT_UMS_MMC0; + sprintf(cmd, "env set preboot; ums 0 mmc %d", instance); + env_set("preboot", cmd); + break; + case BOOT_RECOVERY: + env_set("preboot", "env set preboot; run altbootcmd"); + break; + case BOOT_NORMAL: + break; + default: + pr_debug("unexpected forced boot mode = %x\n", forced_mode); + break; + } + + /* clear TAMP for next reboot */ + clrsetbits_le32(TAMP_BOOT_CONTEXT, TAMP_BOOT_FORCED_MASK, BOOT_NORMAL); } /* diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index f2ab026a5a..da23af0a64 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -92,6 +92,17 @@ enum boot_device { #define TAMP_BOOT_MODE_SHIFT 8 #define TAMP_BOOT_DEVICE_MASK GENMASK(7, 4) #define TAMP_BOOT_INSTANCE_MASK GENMASK(3, 0) +#define TAMP_BOOT_FORCED_MASK GENMASK(7, 0) + +enum forced_boot_mode { + BOOT_NORMAL = 0x00, + BOOT_FASTBOOT = 0x01, + BOOT_RECOVERY = 0x02, + BOOT_STM32PROG = 0x03, + BOOT_UMS_MMC0 = 0x10, + BOOT_UMS_MMC1 = 0x11, + BOOT_UMS_MMC2 = 0x12, +}; /* offset used for BSEC driver: misc_read and misc_write */ #define STM32_BSEC_SHADOW_OFFSET 0x0 diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 0d963c2af4..d13793ed6a 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -67,6 +67,55 @@ int checkboard(void) return 0; } +static void board_key_check(void) +{ +#if defined(CONFIG_FASTBOOT) || defined(CONFIG_CMD_STM32PROG) + ofnode node; + struct gpio_desc gpio; + enum forced_boot_mode boot_mode = BOOT_NORMAL; + + node = ofnode_path("/config"); + if (!ofnode_valid(node)) { + debug("%s: no /config node?\n", __func__); + return; + } +#ifdef CONFIG_FASTBOOT + if (gpio_request_by_name_nodev(node, "st,fastboot-gpios", 0, + &gpio, GPIOD_IS_IN)) { + debug("%s: could not find a /config/st,fastboot-gpios\n", + __func__); + } else { + if (dm_gpio_get_value(&gpio)) { + puts("Fastboot key pressed, "); + boot_mode = BOOT_FASTBOOT; + } + + dm_gpio_free(NULL, &gpio); + } +#endif +#ifdef CONFIG_CMD_STM32PROG + if (gpio_request_by_name_nodev(node, "st,stm32prog-gpios", 0, + &gpio, GPIOD_IS_IN)) { + debug("%s: could not find a /config/st,stm32prog-gpios\n", + __func__); + } else { + if (dm_gpio_get_value(&gpio)) { + puts("STM32Programmer key pressed, "); + boot_mode = BOOT_STM32PROG; + } + dm_gpio_free(NULL, &gpio); + } +#endif + + if (boot_mode != BOOT_NORMAL) { + puts("entering download mode...\n"); + clrsetbits_le32(TAMP_BOOT_CONTEXT, + TAMP_BOOT_FORCED_MASK, + boot_mode); + } +#endif +} + static struct dwc2_plat_otg_data stm32mp_otg_data = { .usb_gusbcfg = STM32MP_GUSBCFG, }; @@ -227,6 +276,8 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100; + board_key_check(); + if (IS_ENABLED(CONFIG_LED)) led_default_state(); -- cgit From 2cf2b5139430b031946a8947ae1aa0309a471a6b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:21 +0100 Subject: stm32mp1: update memory layout Update the memory layout to be aligned with other platform and avoid overlap with 32MB Linux kernel (multiv7 image). + Kernel => 32MiB offset = 0xC2000000 and increase the bootm size to 32MiB + FDT => 64MiB offset = 0xc4000000 + SCRIPT => 65Mib offset = 0xc4100000 + PXESCRIPT => 66Mib offset = 0xc4200000 + SPLASHIMAGE => 67Mib offset = 0xc4300000 + RAMDISK => 68Mib offset = 0xc4400000 (not limited size) In sources/boot/u-boot/doc/README.distro + kernel_addr_r: A size of 16MB for the kernel is likely adequate. + pxefile_addr_r: A size of 1MB for extlinux.conf is more than adequate. + fdt_addr_r: A size of 1MB for the FDT/DTB seems reasonable. + ramdisk_addr_r: It is recommended that this location be highest in RAM out of fdt_addr_, kernel_addr_r, and ramdisk_addr_r, so that the RAM disk can vary in size and use any available RAM. + pxefile_addr_r: A size of 1MB for extlinux.conf is more than adequate. + scriptaddr: A size of 1MB for extlinux.conf is more than adequate. For suggestions on memory locations for ARM systems, you must follow the guidelines specified in Documentation/arm/Booting in the Linux kernel tree. And in sources/linux-stm32mp/Documentation/arm/Booting The zImage may also be placed in system RAM and called there. The kernel should be placed in the first 128MiB of RAM. It is recommended that it is loaded above 32MiB in order to avoid the need to relocate prior to decompression, which will make the boot process slightly faster. Signed-off-by: Patrick Delaunay --- include/configs/stm32mp1.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 48da1e374a..f2508f736a 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -53,6 +53,9 @@ #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_INITRD_TAG +/* Extend size of kernel image for uncompression */ +#define CONFIG_SYS_BOOTM_LEN SZ_32M + /* SPL support */ #ifdef CONFIG_SPL /* BOOTROM load address */ @@ -106,12 +109,18 @@ #include +/* + * memory layout for 32M uncompressed/compressed kernel, + * 1M fdt, 1M script, 1M pxe and 1M for splashimage + * and the ramdisk at the end. + */ #define CONFIG_EXTRA_ENV_SETTINGS \ - "scriptaddr=0xC0000000\0" \ - "pxefile_addr_r=0xC0000000\0" \ - "kernel_addr_r=0xC1000000\0" \ - "fdt_addr_r=0xC4000000\0" \ - "ramdisk_addr_r=0xC4100000\0" \ + "kernel_addr_r=0xc2000000\0" \ + "fdt_addr_r=0xc4000000\0" \ + "scriptaddr=0xc4100000\0" \ + "pxefile_addr_r=0xc4200000\0" \ + "splashimage=0xc4300000\0" \ + "ramdisk_addr_r=0xc4400000\0" \ "fdt_high=0xffffffff\0" \ "initrd_high=0xffffffff\0" \ STM32MP_BOOTCMD \ -- cgit From a53d9f8f905a0f272e04ef30934bf7d0c95462d6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:22 +0100 Subject: stm32mp1: activated some configuration Add configuration useful for test - FIT support - MEMTEST - DFU - CACHE - TIME - TIMER Signed-off-by: Patrick Delaunay --- configs/stm32mp15_basic_defconfig | 6 ++++++ configs/stm32mp15_trusted_defconfig | 6 ++++++ include/configs/stm32mp1.h | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 2d6a16444e..fa27cad8ba 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -5,6 +5,7 @@ CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL=y CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 @@ -18,8 +19,10 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEMTEST=y CONFIG_CMD_ADC=y CONFIG_CMD_CLK=y +CONFIG_CMD_DFU=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y @@ -27,6 +30,9 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 7945e9fb90..447c1d96c3 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -3,6 +3,7 @@ CONFIG_ARCH_STM32MP=y CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set @@ -12,8 +13,10 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEMTEST=y CONFIG_CMD_ADC=y CONFIG_CMD_CLK=y +CONFIG_CMD_DFU=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y @@ -21,6 +24,9 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index f2508f736a..737dfd6a5c 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -72,6 +72,10 @@ STM32_SYSRAM_SIZE) #endif /* #ifdef CONFIG_SPL */ +#define CONFIG_SYS_MEMTEST_START STM32_DDR_BASE +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + SZ_64M) +#define CONFIG_SYS_MEMTEST_SCRATCH (CONFIG_SYS_MEMTEST_END + 4) + /*MMC SD*/ #define CONFIG_SYS_MMC_MAX_DEVICE 3 #define CONFIG_SUPPORT_EMMC_BOOT -- cgit From 6c09eb9e7ef2c39d6f0fc2575ac10957bb922b36 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:23 +0100 Subject: stm32mp1: add some syscon drivers for syscfg and etpzc Add SYSCON driver for syscfg and etpzc and reorder in alphabetics order Signed-off-by: Patrick Delaunay --- arch/arm/dts/stm32mp157c.dtsi | 2 +- arch/arm/mach-stm32mp/include/mach/stm32.h | 4 +++- arch/arm/mach-stm32mp/syscon.c | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 37cadfa30c..d1d0f90b2a 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -754,7 +754,7 @@ }; syscfg: system-config@50020000 { - compatible = "st,stm32-syscfg", "syscon"; + compatible = "st,stm32mp157-syscfg", "syscon"; reg = <0x50020000 0x400>; }; diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index da23af0a64..d153ac8203 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -37,8 +37,10 @@ /* enumerated used to identify the SYSCON driver instance */ enum { STM32MP_SYSCON_UNKNOWN, - STM32MP_SYSCON_STGEN, + STM32MP_SYSCON_ETZPC, STM32MP_SYSCON_PWR, + STM32MP_SYSCON_STGEN, + STM32MP_SYSCON_SYSCFG, }; /* diff --git a/arch/arm/mach-stm32mp/syscon.c b/arch/arm/mach-stm32mp/syscon.c index eb7f435f10..242f8340ab 100644 --- a/arch/arm/mach-stm32mp/syscon.c +++ b/arch/arm/mach-stm32mp/syscon.c @@ -9,10 +9,11 @@ #include static const struct udevice_id stm32mp_syscon_ids[] = { - { .compatible = "st,stm32-stgen", - .data = STM32MP_SYSCON_STGEN }, - { .compatible = "st,stm32mp1-pwr", - .data = STM32MP_SYSCON_PWR }, + { .compatible = "st,stm32mp1-etzpc", .data = STM32MP_SYSCON_ETZPC }, + { .compatible = "st,stm32mp1-pwr", .data = STM32MP_SYSCON_PWR }, + { .compatible = "st,stm32-stgen", .data = STM32MP_SYSCON_STGEN }, + { .compatible = "st,stm32mp157-syscfg", + .data = STM32MP_SYSCON_SYSCFG }, { } }; -- cgit From 45459747ca0efee6f0198c65bac319f9d89e1988 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:24 +0100 Subject: stm32mp1: add syscfg initialization Initialize the system configuration for basic boot - update interconnect setting - disable pull-down for boot pin - enable High Speed Low Voltage Pad mode for SPI, SDMMC, ETH, QSPI - activate I/O compensation Done by SSBL = TF-A for trusted boot Signed-off-by: Patrick Delaunay --- board/st/stm32mp1/stm32mp1.c | 130 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index d13793ed6a..282918089b 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -11,13 +11,47 @@ #include #include #include +#include #include -#include #include #include +#include #include #include +/* SYSCFG registers */ +#define SYSCFG_BOOTR 0x00 +#define SYSCFG_PMCSETR 0x04 +#define SYSCFG_IOCTRLSETR 0x18 +#define SYSCFG_ICNR 0x1C +#define SYSCFG_CMPCR 0x20 +#define SYSCFG_CMPENSETR 0x24 +#define SYSCFG_PMCCLRR 0x44 + +#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0) +#define SYSCFG_BOOTR_BOOTPD_SHIFT 4 + +#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0) +#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1) +#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2) +#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3) +#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4) + +#define SYSCFG_CMPCR_SW_CTRL BIT(1) +#define SYSCFG_CMPCR_READY BIT(8) + +#define SYSCFG_CMPENSETR_MPU_EN BIT(0) + +#define SYSCFG_PMCSETR_ETH_CLK_SEL BIT(16) +#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL BIT(17) + +#define SYSCFG_PMCSETR_ETH_SELMII BIT(20) + +#define SYSCFG_PMCSETR_ETH_SEL_MASK GENMASK(23, 21) +#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII (0 << 21) +#define SYSCFG_PMCSETR_ETH_SEL_RGMII (1 << 21) +#define SYSCFG_PMCSETR_ETH_SEL_RMII (4 << 21) + /* * Get a global data pointer */ @@ -270,6 +304,98 @@ int board_usb_cleanup(int index, enum usb_init_type init) return 0; } +static void sysconf_init(void) +{ +#ifndef CONFIG_STM32MP1_TRUSTED + u8 *syscfg; +#ifdef CONFIG_DM_REGULATOR + struct udevice *pwr_dev; + struct udevice *pwr_reg; + struct udevice *dev; + int ret; + u32 otp = 0; +#endif + u32 bootr; + + syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG); + + /* interconnect update : select master using the port 1 */ + /* LTDC = AXI_M9 */ + /* GPU = AXI_M8 */ + /* today information is hardcoded in U-Boot */ + writel(BIT(9), syscfg + SYSCFG_ICNR); + + /* disable Pull-Down for boot pin connected to VDD */ + bootr = readl(syscfg + SYSCFG_BOOTR); + bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT); + bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT; + writel(bootr, syscfg + SYSCFG_BOOTR); + +#ifdef CONFIG_DM_REGULATOR + /* High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI + * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. + * The customer will have to disable this for low frequencies + * or if AFMUX is selected but the function not used, typically for + * TRACE. Otherwise, impact on power consumption. + * + * WARNING: + * enabling High Speed mode while VDD>2.7V + * with the OTP product_below_2v5 (OTP 18, BIT 13) + * erroneously set to 1 can damage the IC! + * => U-Boot set the register only if VDD < 2.7V (in DT) + * but this value need to be consistent with board design + */ + ret = syscon_get_by_driver_data(STM32MP_SYSCON_PWR, &pwr_dev); + if (!ret) { + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) { + pr_err("Can't find stm32mp_bsec driver\n"); + return; + } + + ret = misc_read(dev, STM32_BSEC_SHADOW(18), &otp, 4); + if (!ret) + otp = otp & BIT(13); + + /* get VDD = pwr-supply */ + ret = device_get_supply_regulator(pwr_dev, "pwr-supply", + &pwr_reg); + + /* check if VDD is Low Voltage */ + if (!ret) { + if (regulator_get_value(pwr_reg) < 2700000) { + writel(SYSCFG_IOCTRLSETR_HSLVEN_TRACE | + SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | + SYSCFG_IOCTRLSETR_HSLVEN_ETH | + SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | + SYSCFG_IOCTRLSETR_HSLVEN_SPI, + syscfg + SYSCFG_IOCTRLSETR); + + if (!otp) + pr_err("product_below_2v5=0: HSLVEN protected by HW\n"); + } else { + if (otp) + pr_err("product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n"); + } + } else { + debug("VDD unknown"); + } + } +#endif + + /* activate automatic I/O compensation + * warning: need to ensure CSI enabled and ready in clock driver + */ + writel(SYSCFG_CMPENSETR_MPU_EN, syscfg + SYSCFG_CMPENSETR); + + while (!(readl(syscfg + SYSCFG_CMPCR) & SYSCFG_CMPCR_READY)) + ; + clrbits_le32(syscfg + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); +#endif +} + /* board dependent setup after realloc */ int board_init(void) { @@ -278,6 +404,8 @@ int board_init(void) board_key_check(); + sysconf_init(); + if (IS_ENABLED(CONFIG_LED)) led_default_state(); -- cgit From 8983ba2751ec008e13583960d711ec010e109fe6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:25 +0100 Subject: stm32mp1: align serial number on bootrom Always use upper case for serial number. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 305ea6dd64..5d79bde733 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -507,7 +507,7 @@ static int setup_serial_number(void) if (ret < 0) return ret; - sprintf(serial_string, "%08x%08x%08x", otp[0], otp[1], otp[2]); + sprintf(serial_string, "%08X%08X%08X", otp[0], otp[1], otp[2]); env_set("serial#", serial_string); return 0; -- cgit From 59a54e37a6adb86c920d8cadbac663e8fb2eeb2c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:26 +0100 Subject: stm32mp1: basic boot: SPL enable access to GPIOZ bank SPL need to set GPIOZ_SECCFGR = 0 to enable access to GPIOZ bank (open security). Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 5d79bde733..f39941edfc 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -18,6 +18,7 @@ #define RCC_DBGCFGR (STM32_RCC_BASE + 0x080C) #define RCC_BDCR (STM32_RCC_BASE + 0x0140) #define RCC_MP_APB5ENSETR (STM32_RCC_BASE + 0x0208) +#define RCC_MP_AHB5ENSETR (STM32_RCC_BASE + 0x0210) #define RCC_BDCR_VSWRST BIT(31) #define RCC_BDCR_RTCSRC GENMASK(17, 16) #define RCC_DBGCFGR_DBGCKEN BIT(8) @@ -44,6 +45,9 @@ #define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16) #define DBGMCU_IDC_REV_ID_SHIFT 16 +/* GPIOZ registers */ +#define GPIOZ_SECCFGR 0x54004030 + /* boot interface from Bootrom * - boot instance = bit 31:16 * - boot device = bit 15:0 @@ -135,6 +139,10 @@ static void security_init(void) * Bit 16 ITAMP1E: RTC power domain supply monitoring */ writel(0x0, TAMP_CR1); + + /* GPIOZ: deactivate the security */ + writel(BIT(0), RCC_MP_AHB5ENSETR); + writel(0x0, GPIOZ_SECCFGR); } #endif /* CONFIG_STM32MP1_TRUSTED */ -- cgit From bfe1f08f88beacc61755bbeeb509b840c66df740 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:27 +0100 Subject: stm32mp1: bsec: use device tree new compatible Update bsec driver to use the device tree provided by Kernel. Signed-off-by: Patrick Delaunay --- arch/arm/dts/stm32mp157-u-boot.dtsi | 4 ++++ arch/arm/dts/stm32mp157c.dtsi | 7 +++++++ arch/arm/mach-stm32mp/bsec.c | 12 +----------- arch/arm/mach-stm32mp/include/mach/stm32.h | 1 - 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 90d13f35c4..2594702c92 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -39,6 +39,10 @@ }; }; +&bsec { + u-boot,dm-pre-reloc; +}; + &clk_hsi { u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index d1d0f90b2a..50978efc7c 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -996,6 +996,13 @@ status = "disabled"; }; + bsec: nvmem@5c005000 { + compatible = "st,stm32mp15-bsec"; + reg = <0x5c005000 0x400>; + #address-cells = <1>; + #size-cells = <1>; + }; + i2c6: i2c@5c009000 { compatible = "st,stm32f7-i2c"; reg = <0x5c009000 0x400>; diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 920a6c9191..8c5a299104 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -434,7 +434,7 @@ static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) } static const struct udevice_id stm32mp_bsec_ids[] = { - { .compatible = "st,stm32mp-bsec" }, + { .compatible = "st,stm32mp15-bsec" }, {} }; @@ -446,13 +446,3 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), .ops = &stm32mp_bsec_ops, }; - -/* bsec IP is not present in device tee, manage IP address by platdata */ -static struct stm32mp_bsec_platdata stm32_bsec_platdata = { - .base = STM32_BSEC_BASE, -}; - -U_BOOT_DEVICE(stm32mp_bsec) = { - .name = "stm32mp_bsec", - .platdata = &stm32_bsec_platdata, -}; diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index d153ac8203..c526c88e3e 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -13,7 +13,6 @@ #define STM32_RCC_BASE 0x50000000 #define STM32_PWR_BASE 0x50001000 #define STM32_DBGMCU_BASE 0x50081000 -#define STM32_BSEC_BASE 0x5C005000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_TAMP_BASE 0x5C00A000 -- cgit From 815bc8bc94b0c5bbd1bcb921f67c31a42cfad8d4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:28 +0100 Subject: stm32mp1: bsec: shadow all the upper OTP (no secure) during boot Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/bsec.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 8c5a299104..9ed8d8c56c 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -171,7 +171,7 @@ static int bsec_shadow_register(u32 base, u32 otp) ret = bsec_power_safmem(base, true); if (ret) return ret; - power_up = 1; + power_up = true; } /* set BSEC_OTP_CTRL_OFF with the otp value*/ writel(otp | BSEC_READ, base + BSEC_OTP_CTRL_OFF); @@ -433,6 +433,21 @@ static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) return 0; } +#ifndef CONFIG_STM32MP1_TRUSTED +static int stm32mp_bsec_probe(struct udevice *dev) +{ + int otp; + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + /* update unlocked shadow for OTP cleared by the rom code */ + for (otp = 57; otp <= BSEC_OTP_MAX_VALUE; otp++) + if (!bsec_read_SR_lock(plat->base, otp)) + bsec_shadow_register(plat->base, otp); + + return 0; +} +#endif + static const struct udevice_id stm32mp_bsec_ids[] = { { .compatible = "st,stm32mp15-bsec" }, {} @@ -445,4 +460,7 @@ U_BOOT_DRIVER(stm32mp_bsec) = { .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), .ops = &stm32mp_bsec_ops, +#ifndef CONFIG_STM32MP1_TRUSTED + .probe = stm32mp_bsec_probe, +#endif }; -- cgit From 17f1f9b17672bf6d3c9ce37f7cb370cd8b6132d1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Feb 2019 17:01:29 +0100 Subject: stm32mp1: Replace OTP read by SHADOW read Replace STM32_BSEC_OTP() by STM32_BSEC_SHADOW() to increase read performance. Signed-off-by: Patrice Chotard Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index f39941edfc..7b4431c9c7 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -472,7 +472,7 @@ static int setup_mac_address(void) if (ret) return ret; - ret = misc_read(dev, BSEC_OTP_MAC * 4 + STM32_BSEC_OTP_OFFSET, + ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_MAC), otp, sizeof(otp)); if (ret < 0) return ret; @@ -510,7 +510,7 @@ static int setup_serial_number(void) if (ret) return ret; - ret = misc_read(dev, BSEC_OTP_SERIAL * 4 + STM32_BSEC_OTP_OFFSET, + ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_SERIAL), otp, sizeof(otp)); if (ret < 0) return ret; -- cgit From 9772125130546115206d25b2dcd221f22355bad3 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:15 +0100 Subject: regulator: stpmu1: update buck1 range SW impact for Rev 1.2 of STPMIC1 in U-Boot: Buck converters output voltage change for Buck1 => Vdd min 0,725 to max 1,5V instead of 0.6V to 1.35V (see STPMIC1 datasheet / chapter 5.3 Buck converters) Signed-off-by: Patrick Delaunay --- drivers/power/regulator/stpmu1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/power/regulator/stpmu1.c b/drivers/power/regulator/stpmu1.c index 6eb2420b6b..2e64051ac0 100644 --- a/drivers/power/regulator/stpmu1.c +++ b/drivers/power/regulator/stpmu1.c @@ -83,8 +83,9 @@ static int stpmu1_output_find_sel(int uv, */ static const struct stpmu1_range buck1_ranges[] = { - STPMU1_RANGE(600000, 0, 30, 25000), - STPMU1_RANGE(1350000, 31, 63, 0), + STPMU1_RANGE(725000, 0, 4, 0), + STPMU1_RANGE(725000, 5, 36, 25000), + STPMU1_RANGE(1500000, 37, 63, 0), }; static const struct stpmu1_range buck2_ranges[] = { -- cgit From d46c22b3fdb58623f1bf372d028313a5d3e7b79b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:16 +0100 Subject: power: stpmu1: rename files to stpmic1 Prepare file modification for kernel alignment and rename driver to stpmic1. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- arch/arm/dts/stm32mp157c-ed1.dts | 2 +- board/st/stm32mp1/board.c | 2 +- board/st/stm32mp1/spl.c | 2 +- drivers/power/pmic/Makefile | 2 +- drivers/power/pmic/stpmic1.c | 95 +++++ drivers/power/pmic/stpmu1.c | 95 ----- drivers/power/regulator/Makefile | 2 +- drivers/power/regulator/stpmic1.c | 672 +++++++++++++++++++++++++++++++++++ drivers/power/regulator/stpmu1.c | 672 ----------------------------------- include/dt-bindings/mfd/st,stpmic1.h | 60 ++++ include/dt-bindings/mfd/st,stpmu1.h | 60 ---- include/power/stpmic1.h | 85 +++++ include/power/stpmu1.h | 85 ----- 13 files changed, 917 insertions(+), 917 deletions(-) create mode 100644 drivers/power/pmic/stpmic1.c delete mode 100644 drivers/power/pmic/stpmu1.c create mode 100644 drivers/power/regulator/stpmic1.c delete mode 100644 drivers/power/regulator/stpmu1.c create mode 100644 include/dt-bindings/mfd/st,stpmic1.h delete mode 100644 include/dt-bindings/mfd/st,stpmu1.h create mode 100644 include/power/stpmic1.h delete mode 100644 include/power/stpmu1.h diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 7a9b742d36..ddee286ab1 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -8,7 +8,7 @@ #include "stm32mp157c.dtsi" #include "stm32mp157-pinctrl.dtsi" #include -#include +#include / { model = "STMicroelectronics STM32MP157C eval daughter"; diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 5f31ea99f5..1bb97792c9 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #ifdef CONFIG_DEBUG_UART_BOARD_INIT void board_debug_uart_init(void) diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index f3db0d6385..1202297d2e 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include void spl_board_init(void) diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 637352ab2b..147ac76366 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o -obj-$(CONFIG_PMIC_STPMU1) += stpmu1.o +obj-$(CONFIG_PMIC_STPMU1) += stpmic1.o obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c new file mode 100644 index 0000000000..157ce8bfb6 --- /dev/null +++ b/drivers/power/pmic/stpmic1.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include + +#define STMPU1_NUM_OF_REGS 0x100 + +#ifndef CONFIG_SPL_BUILD +static const struct pmic_child_info stpmu1_children_info[] = { + { .prefix = "ldo", .driver = "stpmu1_ldo" }, + { .prefix = "buck", .driver = "stpmu1_buck" }, + { .prefix = "vref_ddr", .driver = "stpmu1_vref_ddr" }, + { .prefix = "pwr_sw", .driver = "stpmu1_pwr_sw" }, + { .prefix = "boost", .driver = "stpmu1_boost" }, + { }, +}; +#endif /* CONFIG_SPL_BUILD */ + +static int stpmu1_reg_count(struct udevice *dev) +{ + return STMPU1_NUM_OF_REGS; +} + +static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + dev_err(dev, "%s: failed to write register %#x :%d", + __func__, reg, ret); + + return ret; +} + +static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + dev_err(dev, "%s: failed to read register %#x : %d", + __func__, reg, ret); + + return ret; +} + +static int stpmu1_bind(struct udevice *dev) +{ +#ifndef CONFIG_SPL_BUILD + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + dev_dbg(dev, "regulators subnode not found!\n"); + return -ENXIO; + } + dev_dbg(dev, "found regulators subnode\n"); + + children = pmic_bind_children(dev, regulators_node, + stpmu1_children_info); + if (!children) + dev_dbg(dev, "no child found\n"); +#endif /* CONFIG_SPL_BUILD */ + + return 0; +} + +static struct dm_pmic_ops stpmu1_ops = { + .reg_count = stpmu1_reg_count, + .read = stpmu1_read, + .write = stpmu1_write, +}; + +static const struct udevice_id stpmu1_ids[] = { + { .compatible = "st,stpmu1" }, + { } +}; + +U_BOOT_DRIVER(pmic_stpmu1) = { + .name = "stpmu1_pmic", + .id = UCLASS_PMIC, + .of_match = stpmu1_ids, + .bind = stpmu1_bind, + .ops = &stpmu1_ops, +}; diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c deleted file mode 100644 index 47af012332..0000000000 --- a/drivers/power/pmic/stpmu1.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause -/* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ - -#include -#include -#include -#include -#include -#include - -#define STMPU1_NUM_OF_REGS 0x100 - -#ifndef CONFIG_SPL_BUILD -static const struct pmic_child_info stpmu1_children_info[] = { - { .prefix = "ldo", .driver = "stpmu1_ldo" }, - { .prefix = "buck", .driver = "stpmu1_buck" }, - { .prefix = "vref_ddr", .driver = "stpmu1_vref_ddr" }, - { .prefix = "pwr_sw", .driver = "stpmu1_pwr_sw" }, - { .prefix = "boost", .driver = "stpmu1_boost" }, - { }, -}; -#endif /* CONFIG_SPL_BUILD */ - -static int stpmu1_reg_count(struct udevice *dev) -{ - return STMPU1_NUM_OF_REGS; -} - -static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff, - int len) -{ - int ret; - - ret = dm_i2c_write(dev, reg, buff, len); - if (ret) - dev_err(dev, "%s: failed to write register %#x :%d", - __func__, reg, ret); - - return ret; -} - -static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) -{ - int ret; - - ret = dm_i2c_read(dev, reg, buff, len); - if (ret) - dev_err(dev, "%s: failed to read register %#x : %d", - __func__, reg, ret); - - return ret; -} - -static int stpmu1_bind(struct udevice *dev) -{ -#ifndef CONFIG_SPL_BUILD - ofnode regulators_node; - int children; - - regulators_node = dev_read_subnode(dev, "regulators"); - if (!ofnode_valid(regulators_node)) { - dev_dbg(dev, "regulators subnode not found!\n"); - return -ENXIO; - } - dev_dbg(dev, "found regulators subnode\n"); - - children = pmic_bind_children(dev, regulators_node, - stpmu1_children_info); - if (!children) - dev_dbg(dev, "no child found\n"); -#endif /* CONFIG_SPL_BUILD */ - - return 0; -} - -static struct dm_pmic_ops stpmu1_ops = { - .reg_count = stpmu1_reg_count, - .read = stpmu1_read, - .write = stpmu1_write, -}; - -static const struct udevice_id stpmu1_ids[] = { - { .compatible = "st,stpmu1" }, - { } -}; - -U_BOOT_DRIVER(pmic_stpmu1) = { - .name = "stpmu1_pmic", - .id = UCLASS_PMIC, - .of_match = stpmu1_ids, - .bind = stpmu1_bind, - .ops = &stpmu1_ops, -}; diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index f617ce723a..cfc91e83a1 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -24,4 +24,4 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMU1) += stpmu1.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMU1) += stpmic1.o diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c new file mode 100644 index 0000000000..c62a19a68a --- /dev/null +++ b/drivers/power/regulator/stpmic1.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Christophe Kerello + */ + +#include +#include +#include +#include +#include +#include + +struct stpmu1_range { + int min_uv; + int min_sel; + int max_sel; + int step; +}; + +struct stpmu1_output_range { + const struct stpmu1_range *ranges; + int nbranges; +}; + +#define STPMU1_MODE(_id, _val, _name) { \ + .id = _id, \ + .register_value = _val, \ + .name = _name, \ +} + +#define STPMU1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \ + .min_uv = _min_uv, \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .step = _step, \ +} + +#define STPMU1_OUTPUT_RANGE(_ranges, _nbranges) { \ + .ranges = _ranges, \ + .nbranges = _nbranges, \ +} + +static int stpmu1_output_find_uv(int sel, + const struct stpmu1_output_range *output_range) +{ + const struct stpmu1_range *range; + int i; + + for (i = 0, range = output_range->ranges; + i < output_range->nbranges; i++, range++) { + if (sel >= range->min_sel && sel <= range->max_sel) + return range->min_uv + + (sel - range->min_sel) * range->step; + } + + return -EINVAL; +} + +static int stpmu1_output_find_sel(int uv, + const struct stpmu1_output_range *output_range) +{ + const struct stpmu1_range *range; + int i; + + for (i = 0, range = output_range->ranges; + i < output_range->nbranges; i++, range++) { + if (uv == range->min_uv && !range->step) + return range->min_sel; + + if (uv >= range->min_uv && + uv <= range->min_uv + + (range->max_sel - range->min_sel) * range->step) + return range->min_sel + + (uv - range->min_uv) / range->step; + } + + return -EINVAL; +} + +/* + * BUCK regulators + */ + +static const struct stpmu1_range buck1_ranges[] = { + STPMU1_RANGE(725000, 0, 4, 0), + STPMU1_RANGE(725000, 5, 36, 25000), + STPMU1_RANGE(1500000, 37, 63, 0), +}; + +static const struct stpmu1_range buck2_ranges[] = { + STPMU1_RANGE(1000000, 0, 17, 0), + STPMU1_RANGE(1050000, 18, 19, 0), + STPMU1_RANGE(1100000, 20, 21, 0), + STPMU1_RANGE(1150000, 22, 23, 0), + STPMU1_RANGE(1200000, 24, 25, 0), + STPMU1_RANGE(1250000, 26, 27, 0), + STPMU1_RANGE(1300000, 28, 29, 0), + STPMU1_RANGE(1350000, 30, 31, 0), + STPMU1_RANGE(1400000, 32, 33, 0), + STPMU1_RANGE(1450000, 34, 35, 0), + STPMU1_RANGE(1500000, 36, 63, 0), +}; + +static const struct stpmu1_range buck3_ranges[] = { + STPMU1_RANGE(1000000, 0, 19, 0), + STPMU1_RANGE(1100000, 20, 23, 0), + STPMU1_RANGE(1200000, 24, 27, 0), + STPMU1_RANGE(1300000, 28, 31, 0), + STPMU1_RANGE(1400000, 32, 35, 0), + STPMU1_RANGE(1500000, 36, 55, 100000), + STPMU1_RANGE(3400000, 56, 63, 0), +}; + +static const struct stpmu1_range buck4_ranges[] = { + STPMU1_RANGE(600000, 0, 27, 25000), + STPMU1_RANGE(1300000, 28, 29, 0), + STPMU1_RANGE(1350000, 30, 31, 0), + STPMU1_RANGE(1400000, 32, 33, 0), + STPMU1_RANGE(1450000, 34, 35, 0), + STPMU1_RANGE(1500000, 36, 60, 100000), + STPMU1_RANGE(3900000, 61, 63, 0), +}; + +/* BUCK: 1,2,3,4 - voltage ranges */ +static const struct stpmu1_output_range buck_voltage_range[] = { + STPMU1_OUTPUT_RANGE(buck1_ranges, ARRAY_SIZE(buck1_ranges)), + STPMU1_OUTPUT_RANGE(buck2_ranges, ARRAY_SIZE(buck2_ranges)), + STPMU1_OUTPUT_RANGE(buck3_ranges, ARRAY_SIZE(buck3_ranges)), + STPMU1_OUTPUT_RANGE(buck4_ranges, ARRAY_SIZE(buck4_ranges)), +}; + +/* BUCK modes */ +static const struct dm_regulator_mode buck_modes[] = { + STPMU1_MODE(STPMU1_BUCK_MODE_HP, STPMU1_BUCK_MODE_HP, "HP"), + STPMU1_MODE(STPMU1_BUCK_MODE_LP, STPMU1_BUCK_MODE_LP, "LP"), +}; + +static int stpmu1_buck_get_uv(struct udevice *dev, int buck) +{ + int sel; + + sel = pmic_reg_read(dev, STPMU1_BUCKX_CTRL_REG(buck)); + if (sel < 0) + return sel; + + sel &= STPMU1_BUCK_OUTPUT_MASK; + sel >>= STPMU1_BUCK_OUTPUT_SHIFT; + + return stpmu1_output_find_uv(sel, &buck_voltage_range[buck]); +} + +static int stpmu1_buck_get_value(struct udevice *dev) +{ + return stpmu1_buck_get_uv(dev->parent, dev->driver_data - 1); +} + +static int stpmu1_buck_set_value(struct udevice *dev, int uv) +{ + int sel, buck = dev->driver_data - 1; + + sel = stpmu1_output_find_sel(uv, &buck_voltage_range[buck]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(buck), + STPMU1_BUCK_OUTPUT_MASK, + sel << STPMU1_BUCK_OUTPUT_SHIFT); +} + +static int stpmu1_buck_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMU1_BUCK_EN ? true : false; +} + +static int stpmu1_buck_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : + STPMU1_DEFAULT_STOP_DELAY_MS; + int ret, uv; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_buck_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + uv = stpmu1_buck_get_value(dev); + if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) + stpmu1_buck_set_value(dev, uc_pdata->min_uV); + } + + ret = pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMU1_BUCK_EN, enable ? STPMU1_BUCK_EN : 0); + mdelay(delay); + + return ret; +} + +static int stpmu1_buck_get_mode(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return ret; + + return ret & STPMU1_BUCK_MODE ? STPMU1_BUCK_MODE_LP : + STPMU1_BUCK_MODE_HP; +} + +static int stpmu1_buck_set_mode(struct udevice *dev, int mode) +{ + return pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMU1_BUCK_MODE, + mode ? STPMU1_BUCK_MODE : 0); +} + +static int stpmu1_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_BUCK) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode = (struct dm_regulator_mode *)buck_modes; + uc_pdata->mode_count = ARRAY_SIZE(buck_modes); + + return 0; +} + +static const struct dm_regulator_ops stpmu1_buck_ops = { + .get_value = stpmu1_buck_get_value, + .set_value = stpmu1_buck_set_value, + .get_enable = stpmu1_buck_get_enable, + .set_enable = stpmu1_buck_set_enable, + .get_mode = stpmu1_buck_get_mode, + .set_mode = stpmu1_buck_set_mode, +}; + +U_BOOT_DRIVER(stpmu1_buck) = { + .name = "stpmu1_buck", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_buck_ops, + .probe = stpmu1_buck_probe, +}; + +/* + * LDO regulators + */ + +static const struct stpmu1_range ldo12_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 24, 100000), + STPMU1_RANGE(3300000, 25, 31, 0), +}; + +static const struct stpmu1_range ldo3_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 24, 100000), + STPMU1_RANGE(3300000, 25, 30, 0), + /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */ +}; + +static const struct stpmu1_range ldo5_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 30, 100000), + STPMU1_RANGE(3900000, 31, 31, 0), +}; + +static const struct stpmu1_range ldo6_ranges[] = { + STPMU1_RANGE(900000, 0, 24, 100000), + STPMU1_RANGE(3300000, 25, 31, 0), +}; + +/* LDO: 1,2,3,4,5,6 - voltage ranges */ +static const struct stpmu1_output_range ldo_voltage_range[] = { + STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMU1_OUTPUT_RANGE(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)), + STPMU1_OUTPUT_RANGE(NULL, 0), + STPMU1_OUTPUT_RANGE(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)), + STPMU1_OUTPUT_RANGE(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)), +}; + +/* LDO modes */ +static const struct dm_regulator_mode ldo_modes[] = { + STPMU1_MODE(STPMU1_LDO_MODE_NORMAL, + STPMU1_LDO_MODE_NORMAL, "NORMAL"), + STPMU1_MODE(STPMU1_LDO_MODE_BYPASS, + STPMU1_LDO_MODE_BYPASS, "BYPASS"), + STPMU1_MODE(STPMU1_LDO_MODE_SINK_SOURCE, + STPMU1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"), +}; + +static int stpmu1_ldo_get_value(struct udevice *dev) +{ + int sel, ldo = dev->driver_data - 1; + + sel = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (sel < 0) + return sel; + + /* ldo4 => 3,3V */ + if (ldo == STPMU1_LDO4) + return STPMU1_LDO4_UV; + + sel &= STPMU1_LDO12356_OUTPUT_MASK; + sel >>= STPMU1_LDO12356_OUTPUT_SHIFT; + + /* ldo3, sel = 31 => BUCK2/2 */ + if (ldo == STPMU1_LDO3 && sel == STPMU1_LDO3_DDR_SEL) + return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; + + return stpmu1_output_find_uv(sel, &ldo_voltage_range[ldo]); +} + +static int stpmu1_ldo_set_value(struct udevice *dev, int uv) +{ + int sel, ldo = dev->driver_data - 1; + + /* ldo4 => not possible */ + if (ldo == STPMU1_LDO4) + return -EINVAL; + + sel = stpmu1_output_find_sel(uv, &ldo_voltage_range[ldo]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMU1_LDOX_CTRL_REG(ldo), + STPMU1_LDO12356_OUTPUT_MASK, + sel << STPMU1_LDO12356_OUTPUT_SHIFT); +} + +static int stpmu1_ldo_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_LDOX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMU1_LDO_EN ? true : false; +} + +static int stpmu1_ldo_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : + STPMU1_DEFAULT_STOP_DELAY_MS; + int ret, uv; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_ldo_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + uv = stpmu1_ldo_get_value(dev); + if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) + stpmu1_ldo_set_value(dev, uc_pdata->min_uV); + } + + ret = pmic_clrsetbits(dev->parent, + STPMU1_LDOX_CTRL_REG(dev->driver_data - 1), + STPMU1_LDO_EN, enable ? STPMU1_LDO_EN : 0); + mdelay(delay); + + return ret; +} + +static int stpmu1_ldo_get_mode(struct udevice *dev) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMU1_LDO3) + return -EINVAL; + + ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (ret < 0) + return ret; + + if (ret & STPMU1_LDO3_MODE) + return STPMU1_LDO_MODE_BYPASS; + + ret &= STPMU1_LDO12356_OUTPUT_MASK; + ret >>= STPMU1_LDO12356_OUTPUT_SHIFT; + + return ret == STPMU1_LDO3_DDR_SEL ? STPMU1_LDO_MODE_SINK_SOURCE : + STPMU1_LDO_MODE_NORMAL; +} + +static int stpmu1_ldo_set_mode(struct udevice *dev, int mode) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMU1_LDO3) + return -EINVAL; + + ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (ret < 0) + return ret; + + switch (mode) { + case STPMU1_LDO_MODE_SINK_SOURCE: + ret &= ~STPMU1_LDO12356_OUTPUT_MASK; + ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + case STPMU1_LDO_MODE_NORMAL: + ret &= ~STPMU1_LDO3_MODE; + break; + case STPMU1_LDO_MODE_BYPASS: + ret |= STPMU1_LDO3_MODE; + break; + } + + return pmic_reg_write(dev->parent, STPMU1_LDOX_CTRL_REG(ldo), ret); +} + +static int stpmu1_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_LDO) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + if (dev->driver_data - 1 == STPMU1_LDO3) { + uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes; + uc_pdata->mode_count = ARRAY_SIZE(ldo_modes); + } else { + uc_pdata->mode_count = 0; + } + + return 0; +} + +static const struct dm_regulator_ops stpmu1_ldo_ops = { + .get_value = stpmu1_ldo_get_value, + .set_value = stpmu1_ldo_set_value, + .get_enable = stpmu1_ldo_get_enable, + .set_enable = stpmu1_ldo_set_enable, + .get_mode = stpmu1_ldo_get_mode, + .set_mode = stpmu1_ldo_set_mode, +}; + +U_BOOT_DRIVER(stpmu1_ldo) = { + .name = "stpmu1_ldo", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_ldo_ops, + .probe = stpmu1_ldo_probe, +}; + +/* + * VREF DDR regulator + */ + +static int stpmu1_vref_ddr_get_value(struct udevice *dev) +{ + /* BUCK2/2 */ + return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; +} + +static int stpmu1_vref_ddr_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_VREF_CTRL_REG); + if (ret < 0) + return false; + + return ret & STPMU1_VREF_EN ? true : false; +} + +static int stpmu1_vref_ddr_set_enable(struct udevice *dev, bool enable) +{ + int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : + STPMU1_DEFAULT_STOP_DELAY_MS; + int ret; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_vref_ddr_get_enable(dev) == enable) + return 0; + + ret = pmic_clrsetbits(dev->parent, STPMU1_VREF_CTRL_REG, + STPMU1_VREF_EN, enable ? STPMU1_VREF_EN : 0); + mdelay(delay); + + return ret; +} + +static int stpmu1_vref_ddr_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_vref_ddr_ops = { + .get_value = stpmu1_vref_ddr_get_value, + .get_enable = stpmu1_vref_ddr_get_enable, + .set_enable = stpmu1_vref_ddr_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_vref_ddr) = { + .name = "stpmu1_vref_ddr", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_vref_ddr_ops, + .probe = stpmu1_vref_ddr_probe, +}; + +/* + * BOOST regulator + */ + +static int stpmu1_boost_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return false; + + return ret & STPMU1_USB_BOOST_EN ? true : false; +} + +static int stpmu1_boost_set_enable(struct udevice *dev, bool enable) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return ret; + + if (!enable && ret & STPMU1_USB_PWR_SW_EN) + return -EINVAL; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(ret & STPMU1_USB_BOOST_EN) == enable) + return 0; + + ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, + enable ? STPMU1_USB_BOOST_EN : 0); + if (enable) + mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_boost_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_boost_ops = { + .get_enable = stpmu1_boost_get_enable, + .set_enable = stpmu1_boost_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_boost) = { + .name = "stpmu1_boost", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_boost_ops, + .probe = stpmu1_boost_probe, +}; + +/* + * USB power switch + */ + +static int stpmu1_pwr_sw_get_enable(struct udevice *dev) +{ + uint mask = 1 << dev->driver_data; + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return false; + + return ret & mask ? true : false; +} + +static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable) +{ + uint mask = 1 << dev->driver_data; + int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : + STPMU1_DEFAULT_STOP_DELAY_MS; + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return ret; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(ret & mask) == enable) + return 0; + + /* Boost management */ + if (enable && !(ret & STPMU1_USB_BOOST_EN)) { + pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, STPMU1_USB_BOOST_EN); + mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); + } else if (!enable && ret & STPMU1_USB_BOOST_EN && + (ret & STPMU1_USB_PWR_SW_EN) != STPMU1_USB_PWR_SW_EN) { + pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, 0); + } + + ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + mask, enable ? mask : 0); + mdelay(delay); + + return ret; +} + +static int stpmu1_pwr_sw_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_PWR_SW) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_pwr_sw_ops = { + .get_enable = stpmu1_pwr_sw_get_enable, + .set_enable = stpmu1_pwr_sw_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_pwr_sw) = { + .name = "stpmu1_pwr_sw", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_pwr_sw_ops, + .probe = stpmu1_pwr_sw_probe, +}; diff --git a/drivers/power/regulator/stpmu1.c b/drivers/power/regulator/stpmu1.c deleted file mode 100644 index 2e64051ac0..0000000000 --- a/drivers/power/regulator/stpmu1.c +++ /dev/null @@ -1,672 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause -/* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - * Author: Christophe Kerello - */ - -#include -#include -#include -#include -#include -#include - -struct stpmu1_range { - int min_uv; - int min_sel; - int max_sel; - int step; -}; - -struct stpmu1_output_range { - const struct stpmu1_range *ranges; - int nbranges; -}; - -#define STPMU1_MODE(_id, _val, _name) { \ - .id = _id, \ - .register_value = _val, \ - .name = _name, \ -} - -#define STPMU1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \ - .min_uv = _min_uv, \ - .min_sel = _min_sel, \ - .max_sel = _max_sel, \ - .step = _step, \ -} - -#define STPMU1_OUTPUT_RANGE(_ranges, _nbranges) { \ - .ranges = _ranges, \ - .nbranges = _nbranges, \ -} - -static int stpmu1_output_find_uv(int sel, - const struct stpmu1_output_range *output_range) -{ - const struct stpmu1_range *range; - int i; - - for (i = 0, range = output_range->ranges; - i < output_range->nbranges; i++, range++) { - if (sel >= range->min_sel && sel <= range->max_sel) - return range->min_uv + - (sel - range->min_sel) * range->step; - } - - return -EINVAL; -} - -static int stpmu1_output_find_sel(int uv, - const struct stpmu1_output_range *output_range) -{ - const struct stpmu1_range *range; - int i; - - for (i = 0, range = output_range->ranges; - i < output_range->nbranges; i++, range++) { - if (uv == range->min_uv && !range->step) - return range->min_sel; - - if (uv >= range->min_uv && - uv <= range->min_uv + - (range->max_sel - range->min_sel) * range->step) - return range->min_sel + - (uv - range->min_uv) / range->step; - } - - return -EINVAL; -} - -/* - * BUCK regulators - */ - -static const struct stpmu1_range buck1_ranges[] = { - STPMU1_RANGE(725000, 0, 4, 0), - STPMU1_RANGE(725000, 5, 36, 25000), - STPMU1_RANGE(1500000, 37, 63, 0), -}; - -static const struct stpmu1_range buck2_ranges[] = { - STPMU1_RANGE(1000000, 0, 17, 0), - STPMU1_RANGE(1050000, 18, 19, 0), - STPMU1_RANGE(1100000, 20, 21, 0), - STPMU1_RANGE(1150000, 22, 23, 0), - STPMU1_RANGE(1200000, 24, 25, 0), - STPMU1_RANGE(1250000, 26, 27, 0), - STPMU1_RANGE(1300000, 28, 29, 0), - STPMU1_RANGE(1350000, 30, 31, 0), - STPMU1_RANGE(1400000, 32, 33, 0), - STPMU1_RANGE(1450000, 34, 35, 0), - STPMU1_RANGE(1500000, 36, 63, 0), -}; - -static const struct stpmu1_range buck3_ranges[] = { - STPMU1_RANGE(1000000, 0, 19, 0), - STPMU1_RANGE(1100000, 20, 23, 0), - STPMU1_RANGE(1200000, 24, 27, 0), - STPMU1_RANGE(1300000, 28, 31, 0), - STPMU1_RANGE(1400000, 32, 35, 0), - STPMU1_RANGE(1500000, 36, 55, 100000), - STPMU1_RANGE(3400000, 56, 63, 0), -}; - -static const struct stpmu1_range buck4_ranges[] = { - STPMU1_RANGE(600000, 0, 27, 25000), - STPMU1_RANGE(1300000, 28, 29, 0), - STPMU1_RANGE(1350000, 30, 31, 0), - STPMU1_RANGE(1400000, 32, 33, 0), - STPMU1_RANGE(1450000, 34, 35, 0), - STPMU1_RANGE(1500000, 36, 60, 100000), - STPMU1_RANGE(3900000, 61, 63, 0), -}; - -/* BUCK: 1,2,3,4 - voltage ranges */ -static const struct stpmu1_output_range buck_voltage_range[] = { - STPMU1_OUTPUT_RANGE(buck1_ranges, ARRAY_SIZE(buck1_ranges)), - STPMU1_OUTPUT_RANGE(buck2_ranges, ARRAY_SIZE(buck2_ranges)), - STPMU1_OUTPUT_RANGE(buck3_ranges, ARRAY_SIZE(buck3_ranges)), - STPMU1_OUTPUT_RANGE(buck4_ranges, ARRAY_SIZE(buck4_ranges)), -}; - -/* BUCK modes */ -static const struct dm_regulator_mode buck_modes[] = { - STPMU1_MODE(STPMU1_BUCK_MODE_HP, STPMU1_BUCK_MODE_HP, "HP"), - STPMU1_MODE(STPMU1_BUCK_MODE_LP, STPMU1_BUCK_MODE_LP, "LP"), -}; - -static int stpmu1_buck_get_uv(struct udevice *dev, int buck) -{ - int sel; - - sel = pmic_reg_read(dev, STPMU1_BUCKX_CTRL_REG(buck)); - if (sel < 0) - return sel; - - sel &= STPMU1_BUCK_OUTPUT_MASK; - sel >>= STPMU1_BUCK_OUTPUT_SHIFT; - - return stpmu1_output_find_uv(sel, &buck_voltage_range[buck]); -} - -static int stpmu1_buck_get_value(struct udevice *dev) -{ - return stpmu1_buck_get_uv(dev->parent, dev->driver_data - 1); -} - -static int stpmu1_buck_set_value(struct udevice *dev, int uv) -{ - int sel, buck = dev->driver_data - 1; - - sel = stpmu1_output_find_sel(uv, &buck_voltage_range[buck]); - if (sel < 0) - return sel; - - return pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(buck), - STPMU1_BUCK_OUTPUT_MASK, - sel << STPMU1_BUCK_OUTPUT_SHIFT); -} - -static int stpmu1_buck_get_enable(struct udevice *dev) -{ - int ret; - - ret = pmic_reg_read(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); - if (ret < 0) - return false; - - return ret & STPMU1_BUCK_EN ? true : false; -} - -static int stpmu1_buck_set_enable(struct udevice *dev, bool enable) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; - int ret, uv; - - /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_buck_get_enable(dev) == enable) - return 0; - - if (enable) { - uc_pdata = dev_get_uclass_platdata(dev); - uv = stpmu1_buck_get_value(dev); - if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) - stpmu1_buck_set_value(dev, uc_pdata->min_uV); - } - - ret = pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMU1_BUCK_EN, enable ? STPMU1_BUCK_EN : 0); - mdelay(delay); - - return ret; -} - -static int stpmu1_buck_get_mode(struct udevice *dev) -{ - int ret; - - ret = pmic_reg_read(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); - if (ret < 0) - return ret; - - return ret & STPMU1_BUCK_MODE ? STPMU1_BUCK_MODE_LP : - STPMU1_BUCK_MODE_HP; -} - -static int stpmu1_buck_set_mode(struct udevice *dev, int mode) -{ - return pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMU1_BUCK_MODE, - mode ? STPMU1_BUCK_MODE : 0); -} - -static int stpmu1_buck_probe(struct udevice *dev) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_BUCK) - return -EINVAL; - - uc_pdata = dev_get_uclass_platdata(dev); - - uc_pdata->type = REGULATOR_TYPE_BUCK; - uc_pdata->mode = (struct dm_regulator_mode *)buck_modes; - uc_pdata->mode_count = ARRAY_SIZE(buck_modes); - - return 0; -} - -static const struct dm_regulator_ops stpmu1_buck_ops = { - .get_value = stpmu1_buck_get_value, - .set_value = stpmu1_buck_set_value, - .get_enable = stpmu1_buck_get_enable, - .set_enable = stpmu1_buck_set_enable, - .get_mode = stpmu1_buck_get_mode, - .set_mode = stpmu1_buck_set_mode, -}; - -U_BOOT_DRIVER(stpmu1_buck) = { - .name = "stpmu1_buck", - .id = UCLASS_REGULATOR, - .ops = &stpmu1_buck_ops, - .probe = stpmu1_buck_probe, -}; - -/* - * LDO regulators - */ - -static const struct stpmu1_range ldo12_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 24, 100000), - STPMU1_RANGE(3300000, 25, 31, 0), -}; - -static const struct stpmu1_range ldo3_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 24, 100000), - STPMU1_RANGE(3300000, 25, 30, 0), - /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */ -}; - -static const struct stpmu1_range ldo5_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 30, 100000), - STPMU1_RANGE(3900000, 31, 31, 0), -}; - -static const struct stpmu1_range ldo6_ranges[] = { - STPMU1_RANGE(900000, 0, 24, 100000), - STPMU1_RANGE(3300000, 25, 31, 0), -}; - -/* LDO: 1,2,3,4,5,6 - voltage ranges */ -static const struct stpmu1_output_range ldo_voltage_range[] = { - STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), - STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), - STPMU1_OUTPUT_RANGE(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)), - STPMU1_OUTPUT_RANGE(NULL, 0), - STPMU1_OUTPUT_RANGE(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)), - STPMU1_OUTPUT_RANGE(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)), -}; - -/* LDO modes */ -static const struct dm_regulator_mode ldo_modes[] = { - STPMU1_MODE(STPMU1_LDO_MODE_NORMAL, - STPMU1_LDO_MODE_NORMAL, "NORMAL"), - STPMU1_MODE(STPMU1_LDO_MODE_BYPASS, - STPMU1_LDO_MODE_BYPASS, "BYPASS"), - STPMU1_MODE(STPMU1_LDO_MODE_SINK_SOURCE, - STPMU1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"), -}; - -static int stpmu1_ldo_get_value(struct udevice *dev) -{ - int sel, ldo = dev->driver_data - 1; - - sel = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); - if (sel < 0) - return sel; - - /* ldo4 => 3,3V */ - if (ldo == STPMU1_LDO4) - return STPMU1_LDO4_UV; - - sel &= STPMU1_LDO12356_OUTPUT_MASK; - sel >>= STPMU1_LDO12356_OUTPUT_SHIFT; - - /* ldo3, sel = 31 => BUCK2/2 */ - if (ldo == STPMU1_LDO3 && sel == STPMU1_LDO3_DDR_SEL) - return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; - - return stpmu1_output_find_uv(sel, &ldo_voltage_range[ldo]); -} - -static int stpmu1_ldo_set_value(struct udevice *dev, int uv) -{ - int sel, ldo = dev->driver_data - 1; - - /* ldo4 => not possible */ - if (ldo == STPMU1_LDO4) - return -EINVAL; - - sel = stpmu1_output_find_sel(uv, &ldo_voltage_range[ldo]); - if (sel < 0) - return sel; - - return pmic_clrsetbits(dev->parent, - STPMU1_LDOX_CTRL_REG(ldo), - STPMU1_LDO12356_OUTPUT_MASK, - sel << STPMU1_LDO12356_OUTPUT_SHIFT); -} - -static int stpmu1_ldo_get_enable(struct udevice *dev) -{ - int ret; - - ret = pmic_reg_read(dev->parent, - STPMU1_LDOX_CTRL_REG(dev->driver_data - 1)); - if (ret < 0) - return false; - - return ret & STPMU1_LDO_EN ? true : false; -} - -static int stpmu1_ldo_set_enable(struct udevice *dev, bool enable) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; - int ret, uv; - - /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_ldo_get_enable(dev) == enable) - return 0; - - if (enable) { - uc_pdata = dev_get_uclass_platdata(dev); - uv = stpmu1_ldo_get_value(dev); - if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) - stpmu1_ldo_set_value(dev, uc_pdata->min_uV); - } - - ret = pmic_clrsetbits(dev->parent, - STPMU1_LDOX_CTRL_REG(dev->driver_data - 1), - STPMU1_LDO_EN, enable ? STPMU1_LDO_EN : 0); - mdelay(delay); - - return ret; -} - -static int stpmu1_ldo_get_mode(struct udevice *dev) -{ - int ret, ldo = dev->driver_data - 1; - - if (ldo != STPMU1_LDO3) - return -EINVAL; - - ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); - if (ret < 0) - return ret; - - if (ret & STPMU1_LDO3_MODE) - return STPMU1_LDO_MODE_BYPASS; - - ret &= STPMU1_LDO12356_OUTPUT_MASK; - ret >>= STPMU1_LDO12356_OUTPUT_SHIFT; - - return ret == STPMU1_LDO3_DDR_SEL ? STPMU1_LDO_MODE_SINK_SOURCE : - STPMU1_LDO_MODE_NORMAL; -} - -static int stpmu1_ldo_set_mode(struct udevice *dev, int mode) -{ - int ret, ldo = dev->driver_data - 1; - - if (ldo != STPMU1_LDO3) - return -EINVAL; - - ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); - if (ret < 0) - return ret; - - switch (mode) { - case STPMU1_LDO_MODE_SINK_SOURCE: - ret &= ~STPMU1_LDO12356_OUTPUT_MASK; - ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; - case STPMU1_LDO_MODE_NORMAL: - ret &= ~STPMU1_LDO3_MODE; - break; - case STPMU1_LDO_MODE_BYPASS: - ret |= STPMU1_LDO3_MODE; - break; - } - - return pmic_reg_write(dev->parent, STPMU1_LDOX_CTRL_REG(ldo), ret); -} - -static int stpmu1_ldo_probe(struct udevice *dev) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_LDO) - return -EINVAL; - - uc_pdata = dev_get_uclass_platdata(dev); - - uc_pdata->type = REGULATOR_TYPE_LDO; - if (dev->driver_data - 1 == STPMU1_LDO3) { - uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes; - uc_pdata->mode_count = ARRAY_SIZE(ldo_modes); - } else { - uc_pdata->mode_count = 0; - } - - return 0; -} - -static const struct dm_regulator_ops stpmu1_ldo_ops = { - .get_value = stpmu1_ldo_get_value, - .set_value = stpmu1_ldo_set_value, - .get_enable = stpmu1_ldo_get_enable, - .set_enable = stpmu1_ldo_set_enable, - .get_mode = stpmu1_ldo_get_mode, - .set_mode = stpmu1_ldo_set_mode, -}; - -U_BOOT_DRIVER(stpmu1_ldo) = { - .name = "stpmu1_ldo", - .id = UCLASS_REGULATOR, - .ops = &stpmu1_ldo_ops, - .probe = stpmu1_ldo_probe, -}; - -/* - * VREF DDR regulator - */ - -static int stpmu1_vref_ddr_get_value(struct udevice *dev) -{ - /* BUCK2/2 */ - return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; -} - -static int stpmu1_vref_ddr_get_enable(struct udevice *dev) -{ - int ret; - - ret = pmic_reg_read(dev->parent, STPMU1_VREF_CTRL_REG); - if (ret < 0) - return false; - - return ret & STPMU1_VREF_EN ? true : false; -} - -static int stpmu1_vref_ddr_set_enable(struct udevice *dev, bool enable) -{ - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; - int ret; - - /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_vref_ddr_get_enable(dev) == enable) - return 0; - - ret = pmic_clrsetbits(dev->parent, STPMU1_VREF_CTRL_REG, - STPMU1_VREF_EN, enable ? STPMU1_VREF_EN : 0); - mdelay(delay); - - return ret; -} - -static int stpmu1_vref_ddr_probe(struct udevice *dev) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - - uc_pdata = dev_get_uclass_platdata(dev); - - uc_pdata->type = REGULATOR_TYPE_FIXED; - uc_pdata->mode_count = 0; - - return 0; -} - -static const struct dm_regulator_ops stpmu1_vref_ddr_ops = { - .get_value = stpmu1_vref_ddr_get_value, - .get_enable = stpmu1_vref_ddr_get_enable, - .set_enable = stpmu1_vref_ddr_set_enable, -}; - -U_BOOT_DRIVER(stpmu1_vref_ddr) = { - .name = "stpmu1_vref_ddr", - .id = UCLASS_REGULATOR, - .ops = &stpmu1_vref_ddr_ops, - .probe = stpmu1_vref_ddr_probe, -}; - -/* - * BOOST regulator - */ - -static int stpmu1_boost_get_enable(struct udevice *dev) -{ - int ret; - - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); - if (ret < 0) - return false; - - return ret & STPMU1_USB_BOOST_EN ? true : false; -} - -static int stpmu1_boost_set_enable(struct udevice *dev, bool enable) -{ - int ret; - - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); - if (ret < 0) - return ret; - - if (!enable && ret & STPMU1_USB_PWR_SW_EN) - return -EINVAL; - - /* if regulator is already in the wanted state, nothing to do */ - if (!!(ret & STPMU1_USB_BOOST_EN) == enable) - return 0; - - ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, - enable ? STPMU1_USB_BOOST_EN : 0); - if (enable) - mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); - - return ret; -} - -static int stpmu1_boost_probe(struct udevice *dev) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - - uc_pdata = dev_get_uclass_platdata(dev); - - uc_pdata->type = REGULATOR_TYPE_FIXED; - uc_pdata->mode_count = 0; - - return 0; -} - -static const struct dm_regulator_ops stpmu1_boost_ops = { - .get_enable = stpmu1_boost_get_enable, - .set_enable = stpmu1_boost_set_enable, -}; - -U_BOOT_DRIVER(stpmu1_boost) = { - .name = "stpmu1_boost", - .id = UCLASS_REGULATOR, - .ops = &stpmu1_boost_ops, - .probe = stpmu1_boost_probe, -}; - -/* - * USB power switch - */ - -static int stpmu1_pwr_sw_get_enable(struct udevice *dev) -{ - uint mask = 1 << dev->driver_data; - int ret; - - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); - if (ret < 0) - return false; - - return ret & mask ? true : false; -} - -static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable) -{ - uint mask = 1 << dev->driver_data; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; - int ret; - - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); - if (ret < 0) - return ret; - - /* if regulator is already in the wanted state, nothing to do */ - if (!!(ret & mask) == enable) - return 0; - - /* Boost management */ - if (enable && !(ret & STPMU1_USB_BOOST_EN)) { - pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, STPMU1_USB_BOOST_EN); - mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); - } else if (!enable && ret & STPMU1_USB_BOOST_EN && - (ret & STPMU1_USB_PWR_SW_EN) != STPMU1_USB_PWR_SW_EN) { - pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, 0); - } - - ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - mask, enable ? mask : 0); - mdelay(delay); - - return ret; -} - -static int stpmu1_pwr_sw_probe(struct udevice *dev) -{ - struct dm_regulator_uclass_platdata *uc_pdata; - - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_PWR_SW) - return -EINVAL; - - uc_pdata = dev_get_uclass_platdata(dev); - - uc_pdata->type = REGULATOR_TYPE_FIXED; - uc_pdata->mode_count = 0; - - return 0; -} - -static const struct dm_regulator_ops stpmu1_pwr_sw_ops = { - .get_enable = stpmu1_pwr_sw_get_enable, - .set_enable = stpmu1_pwr_sw_set_enable, -}; - -U_BOOT_DRIVER(stpmu1_pwr_sw) = { - .name = "stpmu1_pwr_sw", - .id = UCLASS_REGULATOR, - .ops = &stpmu1_pwr_sw_ops, - .probe = stpmu1_pwr_sw_probe, -}; diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h new file mode 100644 index 0000000000..81982ebe2c --- /dev/null +++ b/include/dt-bindings/mfd/st,stpmic1.h @@ -0,0 +1,60 @@ +/* + * This file is part of stpmu1 pmic driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author: Pascal Paillet for STMicroelectronics. + * + * License type: GPLv2 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __DT_BINDINGS_STPMU1_H__ +#define __DT_BINDINGS_STPMU1_H__ + +/* IRQ definitions */ +#define IT_PONKEY_F 0 +#define IT_PONKEY_R 1 +#define IT_WAKEUP_F 2 +#define IT_WAKEUP_R 3 +#define IT_VBUS_OTG_F 4 +#define IT_VBUS_OTG_R 5 +#define IT_SWOUT_F 6 +#define IT_SWOUT_R 7 + +#define IT_CURLIM_BUCK1 8 +#define IT_CURLIM_BUCK2 9 +#define IT_CURLIM_BUCK3 10 +#define IT_CURLIM_BUCK4 11 +#define IT_OCP_OTG 12 +#define IT_OCP_SWOUT 13 +#define IT_OCP_BOOST 14 +#define IT_OVP_BOOST 15 + +#define IT_CURLIM_LDO1 16 +#define IT_CURLIM_LDO2 17 +#define IT_CURLIM_LDO3 18 +#define IT_CURLIM_LDO4 19 +#define IT_CURLIM_LDO5 20 +#define IT_CURLIM_LDO6 21 +#define IT_SHORT_SWOTG 22 +#define IT_SHORT_SWOUT 23 + +#define IT_TWARN_F 24 +#define IT_TWARN_R 25 +#define IT_VINLOW_F 26 +#define IT_VINLOW_R 27 +#define IT_SWIN_F 30 +#define IT_SWIN_R 31 + +#endif /* __DT_BINDINGS_STPMU1_H__ */ diff --git a/include/dt-bindings/mfd/st,stpmu1.h b/include/dt-bindings/mfd/st,stpmu1.h deleted file mode 100644 index 81982ebe2c..0000000000 --- a/include/dt-bindings/mfd/st,stpmu1.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of stpmu1 pmic driver - * - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author: Pascal Paillet for STMicroelectronics. - * - * License type: GPLv2 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#ifndef __DT_BINDINGS_STPMU1_H__ -#define __DT_BINDINGS_STPMU1_H__ - -/* IRQ definitions */ -#define IT_PONKEY_F 0 -#define IT_PONKEY_R 1 -#define IT_WAKEUP_F 2 -#define IT_WAKEUP_R 3 -#define IT_VBUS_OTG_F 4 -#define IT_VBUS_OTG_R 5 -#define IT_SWOUT_F 6 -#define IT_SWOUT_R 7 - -#define IT_CURLIM_BUCK1 8 -#define IT_CURLIM_BUCK2 9 -#define IT_CURLIM_BUCK3 10 -#define IT_CURLIM_BUCK4 11 -#define IT_OCP_OTG 12 -#define IT_OCP_SWOUT 13 -#define IT_OCP_BOOST 14 -#define IT_OVP_BOOST 15 - -#define IT_CURLIM_LDO1 16 -#define IT_CURLIM_LDO2 17 -#define IT_CURLIM_LDO3 18 -#define IT_CURLIM_LDO4 19 -#define IT_CURLIM_LDO5 20 -#define IT_CURLIM_LDO6 21 -#define IT_SHORT_SWOTG 22 -#define IT_SHORT_SWOUT 23 - -#define IT_TWARN_F 24 -#define IT_TWARN_R 25 -#define IT_VINLOW_F 26 -#define IT_VINLOW_R 27 -#define IT_SWIN_F 30 -#define IT_SWIN_R 31 - -#endif /* __DT_BINDINGS_STPMU1_H__ */ diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h new file mode 100644 index 0000000000..5906fbf832 --- /dev/null +++ b/include/power/stpmic1.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef __PMIC_STPMU1_H_ +#define __PMIC_STPMU1_H_ + +#define STPMU1_MASK_RESET_BUCK 0x18 +#define STPMU1_BUCKX_CTRL_REG(buck) (0x20 + (buck)) +#define STPMU1_VREF_CTRL_REG 0x24 +#define STPMU1_LDOX_CTRL_REG(ldo) (0x25 + (ldo)) +#define STPMU1_USB_CTRL_REG 0x40 +#define STPMU1_NVM_USER_STATUS_REG 0xb8 +#define STPMU1_NVM_USER_CONTROL_REG 0xb9 + +#define STPMU1_MASK_RESET_BUCK3 BIT(2) + +#define STPMU1_BUCK_EN BIT(0) +#define STPMU1_BUCK_MODE BIT(1) +#define STPMU1_BUCK_OUTPUT_MASK GENMASK(7, 2) +#define STPMU1_BUCK_OUTPUT_SHIFT 2 +#define STPMU1_BUCK2_1200000V (24 << STPMU1_BUCK_OUTPUT_SHIFT) +#define STPMU1_BUCK2_1350000V (30 << STPMU1_BUCK_OUTPUT_SHIFT) +#define STPMU1_BUCK3_1800000V (39 << STPMU1_BUCK_OUTPUT_SHIFT) + +#define STPMU1_VREF_EN BIT(0) + +#define STPMU1_LDO_EN BIT(0) +#define STPMU1_LDO12356_OUTPUT_MASK GENMASK(6, 2) +#define STPMU1_LDO12356_OUTPUT_SHIFT 2 +#define STPMU1_LDO3_MODE BIT(7) +#define STPMU1_LDO3_DDR_SEL 31 +#define STPMU1_LDO3_1800000 (9 << STPMU1_LDO12356_OUTPUT_SHIFT) +#define STPMU1_LDO4_UV 3300000 + +#define STPMU1_USB_BOOST_EN BIT(0) +#define STPMU1_USB_PWR_SW_EN GENMASK(2, 1) + +#define STPMU1_NVM_USER_CONTROL_PROGRAM BIT(0) +#define STPMU1_NVM_USER_CONTROL_READ BIT(1) + +#define STPMU1_NVM_USER_STATUS_BUSY BIT(0) +#define STPMU1_NVM_USER_STATUS_ERROR BIT(1) + +#define STPMU1_DEFAULT_START_UP_DELAY_MS 1 +#define STPMU1_DEFAULT_STOP_DELAY_MS 5 +#define STPMU1_USB_BOOST_START_UP_DELAY_MS 10 + +enum { + STPMU1_BUCK1, + STPMU1_BUCK2, + STPMU1_BUCK3, + STPMU1_BUCK4, + STPMU1_MAX_BUCK, +}; + +enum { + STPMU1_BUCK_MODE_HP, + STPMU1_BUCK_MODE_LP, +}; + +enum { + STPMU1_LDO1, + STPMU1_LDO2, + STPMU1_LDO3, + STPMU1_LDO4, + STPMU1_LDO5, + STPMU1_LDO6, + STPMU1_MAX_LDO, +}; + +enum { + STPMU1_LDO_MODE_NORMAL, + STPMU1_LDO_MODE_BYPASS, + STPMU1_LDO_MODE_SINK_SOURCE, +}; + +enum { + STPMU1_PWR_SW1, + STPMU1_PWR_SW2, + STPMU1_MAX_PWR_SW, +}; + +#endif diff --git a/include/power/stpmu1.h b/include/power/stpmu1.h deleted file mode 100644 index 5906fbf832..0000000000 --- a/include/power/stpmu1.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ -/* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ - -#ifndef __PMIC_STPMU1_H_ -#define __PMIC_STPMU1_H_ - -#define STPMU1_MASK_RESET_BUCK 0x18 -#define STPMU1_BUCKX_CTRL_REG(buck) (0x20 + (buck)) -#define STPMU1_VREF_CTRL_REG 0x24 -#define STPMU1_LDOX_CTRL_REG(ldo) (0x25 + (ldo)) -#define STPMU1_USB_CTRL_REG 0x40 -#define STPMU1_NVM_USER_STATUS_REG 0xb8 -#define STPMU1_NVM_USER_CONTROL_REG 0xb9 - -#define STPMU1_MASK_RESET_BUCK3 BIT(2) - -#define STPMU1_BUCK_EN BIT(0) -#define STPMU1_BUCK_MODE BIT(1) -#define STPMU1_BUCK_OUTPUT_MASK GENMASK(7, 2) -#define STPMU1_BUCK_OUTPUT_SHIFT 2 -#define STPMU1_BUCK2_1200000V (24 << STPMU1_BUCK_OUTPUT_SHIFT) -#define STPMU1_BUCK2_1350000V (30 << STPMU1_BUCK_OUTPUT_SHIFT) -#define STPMU1_BUCK3_1800000V (39 << STPMU1_BUCK_OUTPUT_SHIFT) - -#define STPMU1_VREF_EN BIT(0) - -#define STPMU1_LDO_EN BIT(0) -#define STPMU1_LDO12356_OUTPUT_MASK GENMASK(6, 2) -#define STPMU1_LDO12356_OUTPUT_SHIFT 2 -#define STPMU1_LDO3_MODE BIT(7) -#define STPMU1_LDO3_DDR_SEL 31 -#define STPMU1_LDO3_1800000 (9 << STPMU1_LDO12356_OUTPUT_SHIFT) -#define STPMU1_LDO4_UV 3300000 - -#define STPMU1_USB_BOOST_EN BIT(0) -#define STPMU1_USB_PWR_SW_EN GENMASK(2, 1) - -#define STPMU1_NVM_USER_CONTROL_PROGRAM BIT(0) -#define STPMU1_NVM_USER_CONTROL_READ BIT(1) - -#define STPMU1_NVM_USER_STATUS_BUSY BIT(0) -#define STPMU1_NVM_USER_STATUS_ERROR BIT(1) - -#define STPMU1_DEFAULT_START_UP_DELAY_MS 1 -#define STPMU1_DEFAULT_STOP_DELAY_MS 5 -#define STPMU1_USB_BOOST_START_UP_DELAY_MS 10 - -enum { - STPMU1_BUCK1, - STPMU1_BUCK2, - STPMU1_BUCK3, - STPMU1_BUCK4, - STPMU1_MAX_BUCK, -}; - -enum { - STPMU1_BUCK_MODE_HP, - STPMU1_BUCK_MODE_LP, -}; - -enum { - STPMU1_LDO1, - STPMU1_LDO2, - STPMU1_LDO3, - STPMU1_LDO4, - STPMU1_LDO5, - STPMU1_LDO6, - STPMU1_MAX_LDO, -}; - -enum { - STPMU1_LDO_MODE_NORMAL, - STPMU1_LDO_MODE_BYPASS, - STPMU1_LDO_MODE_SINK_SOURCE, -}; - -enum { - STPMU1_PWR_SW1, - STPMU1_PWR_SW2, - STPMU1_MAX_PWR_SW, -}; - -#endif -- cgit From 42f01aacfd508ddaab5fbc21dd1d3c04dcf61990 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:17 +0100 Subject: power: rename stpmu1 to official name stpmic1 Alignment with kernel driver name & binding introduced by https://patchwork.kernel.org/cover/10761943/ to use the final marketing name = STPMIC1. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- MAINTAINERS | 2 + arch/arm/dts/stm32mp157c-ed1.dts | 6 +- board/st/stm32mp1/README | 6 +- board/st/stm32mp1/board.c | 45 ++-- board/st/stm32mp1/spl.c | 10 +- configs/stm32mp15_basic_defconfig | 4 +- configs/stm32mp15_trusted_defconfig | 4 +- drivers/power/pmic/Kconfig | 6 +- drivers/power/pmic/Makefile | 2 +- drivers/power/pmic/stpmic1.c | 62 ++--- drivers/power/regulator/Kconfig | 14 +- drivers/power/regulator/Makefile | 2 +- drivers/power/regulator/stpmic1.c | 504 +++++++++++++++++------------------ include/dt-bindings/mfd/st,stpmic1.h | 88 +++--- include/power/stpmic1.h | 135 +++++----- 15 files changed, 446 insertions(+), 444 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index f9ee4281d9..083bf47c8b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -295,7 +295,9 @@ F: drivers/misc/stm32mp_fuse.c F: drivers/mmc/stm32_sdmmc2.c F: drivers/phy/phy-stm32-usbphyc.c F: drivers/pinctrl/pinctrl_stm32.c +F: drivers/power/pmic/stpmic1.c F: drivers/power/regulator/stm32-vrefbuf.c +F: drivers/power/regulator/stpmic1.c F: drivers/ram/stm32mp1/ F: drivers/misc/stm32_rcc.c F: drivers/reset/stm32-reset.c diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index ddee286ab1..1d0306e2f4 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -54,8 +54,8 @@ i2c-scl-falling-time-ns = <20>; status = "okay"; - pmic: stpmu1@33 { - compatible = "st,stpmu1"; + pmic: stpmic1@33 { + compatible = "st,stpmic1"; reg = <0x33>; interrupts = <0 2>; interrupt-parent = <&gpioa>; @@ -68,7 +68,7 @@ st,usb_control_register = <0x30>; regulators { - compatible = "st,stpmu1-regulators"; + compatible = "st,stpmic1-regulators"; ldo1-supply = <&v3v3>; ldo2-supply = <&v3v3>; diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 1c3e865e20..72b28fabfc 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -28,7 +28,7 @@ Everything is supported in Linux but U-Boot is limited to: And the necessary drivers 1. I2C -2. STPMU1 (PMIC and regulator) +2. STPMIC1 (PMIC and regulator) 3. Clock, Reset, Sysreset 4. Fuse @@ -70,10 +70,10 @@ Each board is configurated only with the associated device tree. You need to select the appropriate device tree for your board, the supported device trees for stm32mp157 are: -+ ev1: eval board with pmic stpmu1 (ev1 = mother board + daughter ed1) ++ ev1: eval board with pmic stpmic1 (ev1 = mother board + daughter ed1) dts: stm32mp157c-ev1 -+ ed1: daughter board with pmic stpmu1 ++ ed1: daughter board with pmic stpmic1 dts: stm32mp157c-ed1 5. Build Procedure diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 1bb97792c9..2a94f10155 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -37,64 +37,65 @@ void board_debug_uart_init(void) } #endif -#ifdef CONFIG_PMIC_STPMU1 +#ifdef CONFIG_PMIC_STPMIC1 int board_ddr_power_init(void) { struct udevice *dev; int ret; ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(pmic_stpmu1), &dev); + DM_GET_DRIVER(pmic_stpmic1), &dev); if (ret) /* No PMIC on board */ return 0; - /* Set LDO3 to sync mode */ - ret = pmic_reg_read(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3)); + /* VTT = Set LDO3 to sync mode */ + ret = pmic_reg_read(dev, STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3)); if (ret < 0) return ret; - ret &= ~STPMU1_LDO3_MODE; - ret &= ~STPMU1_LDO12356_OUTPUT_MASK; - ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + ret &= ~STPMIC1_LDO3_MODE; + ret &= ~STPMIC1_LDO12356_OUTPUT_MASK; + ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_OUTPUT_SHIFT; - ret = pmic_reg_write(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), + ret = pmic_reg_write(dev, STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3), ret); if (ret < 0) return ret; - /* Set BUCK2 to 1.35V */ + /* VDD_DDR = Set BUCK2 to 1.35V */ ret = pmic_clrsetbits(dev, - STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), - STPMU1_BUCK_OUTPUT_MASK, - STPMU1_BUCK2_1350000V); + STPMIC1_BUCKX_CTRL_REG(STPMIC1_BUCK2), + STPMIC1_BUCK_OUTPUT_MASK, + STPMIC1_BUCK2_1350000V); if (ret < 0) return ret; - /* Enable BUCK2 and VREF */ + /* Enable VDD_DDR = BUCK2 */ ret = pmic_clrsetbits(dev, - STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), - STPMU1_BUCK_EN, STPMU1_BUCK_EN); + STPMIC1_BUCKX_CTRL_REG(STPMIC1_BUCK2), + STPMIC1_BUCK_EN, STPMIC1_BUCK_EN); if (ret < 0) return ret; - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - ret = pmic_clrsetbits(dev, STPMU1_VREF_CTRL_REG, - STPMU1_VREF_EN, STPMU1_VREF_EN); + /* Enable VREF */ + ret = pmic_clrsetbits(dev, STPMIC1_VREF_CTRL_REG, + STPMIC1_VREF_EN, STPMIC1_VREF_EN); if (ret < 0) return ret; - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); /* Enable LDO3 */ ret = pmic_clrsetbits(dev, - STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), - STPMU1_LDO_EN, STPMU1_LDO_EN); + STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3), + STPMIC1_LDO_EN, STPMIC1_LDO_EN); if (ret < 0) return ret; - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); return 0; } diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index 1202297d2e..546a92325c 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -17,16 +17,16 @@ void spl_board_init(void) { /* Keep vdd on during the reset cycle */ -#if defined(CONFIG_PMIC_STPMU1) && defined(CONFIG_SPL_POWER_SUPPORT) +#if defined(CONFIG_PMIC_STPMIC1) && defined(CONFIG_SPL_POWER_SUPPORT) struct udevice *dev; int ret; ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(pmic_stpmu1), &dev); + DM_GET_DRIVER(pmic_stpmic1), &dev); if (!ret) pmic_clrsetbits(dev, - STPMU1_MASK_RESET_BUCK, - STPMU1_MASK_RESET_BUCK3, - STPMU1_MASK_RESET_BUCK3); + STPMIC1_MASK_RESET_BUCK, + STPMIC1_MASK_RESET_BUCK3, + STPMIC1_MASK_RESET_BUCK3); #endif } diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index fa27cad8ba..ac52155699 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -59,11 +59,11 @@ CONFIG_PHY_STM32_USBPHYC=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_DM_PMIC=y # CONFIG_SPL_PMIC_CHILDREN is not set -CONFIG_PMIC_STPMU1=y +CONFIG_PMIC_STPMIC1=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y -CONFIG_DM_REGULATOR_STPMU1=y +CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y CONFIG_USB=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 447c1d96c3..0ffea5bfb3 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -50,11 +50,11 @@ CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y # CONFIG_PINCTRL_FULL is not set CONFIG_DM_PMIC=y -CONFIG_PMIC_STPMU1=y +CONFIG_PMIC_STPMIC1=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y -CONFIG_DM_REGULATOR_STPMU1=y +CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y CONFIG_USB=y diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 8cf60ebcf3..b0cd260354 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -231,10 +231,10 @@ config DM_PMIC_TPS65910 DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO pmic children. -config PMIC_STPMU1 - bool "Enable support for STMicroelectronics STPMU1 PMIC" +config PMIC_STPMIC1 + bool "Enable support for STMicroelectronics STPMIC1 PMIC" depends on DM_PMIC && DM_I2C ---help--- - The STPMU1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. + The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. It is accessed via an I2C interface. The device is used with STM32MP1 SoCs. This driver implements register read/write operations. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 147ac76366..ce250cb155 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o -obj-$(CONFIG_PMIC_STPMU1) += stpmic1.o +obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index 157ce8bfb6..25450ebd42 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -10,26 +10,26 @@ #include #include -#define STMPU1_NUM_OF_REGS 0x100 - -#ifndef CONFIG_SPL_BUILD -static const struct pmic_child_info stpmu1_children_info[] = { - { .prefix = "ldo", .driver = "stpmu1_ldo" }, - { .prefix = "buck", .driver = "stpmu1_buck" }, - { .prefix = "vref_ddr", .driver = "stpmu1_vref_ddr" }, - { .prefix = "pwr_sw", .driver = "stpmu1_pwr_sw" }, - { .prefix = "boost", .driver = "stpmu1_boost" }, +#define STPMIC1_NUM_OF_REGS 0x100 + +#if CONFIG_IS_ENABLED(DM_REGULATOR) +static const struct pmic_child_info stpmic1_children_info[] = { + { .prefix = "ldo", .driver = "stpmic1_ldo" }, + { .prefix = "buck", .driver = "stpmic1_buck" }, + { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" }, + { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" }, + { .prefix = "boost", .driver = "stpmic1_boost" }, { }, }; -#endif /* CONFIG_SPL_BUILD */ +#endif /* DM_REGULATOR */ -static int stpmu1_reg_count(struct udevice *dev) +static int stpmic1_reg_count(struct udevice *dev) { - return STMPU1_NUM_OF_REGS; + return STPMIC1_NUM_OF_REGS; } -static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff, - int len) +static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) { int ret; @@ -41,7 +41,7 @@ static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff, return ret; } -static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { int ret; @@ -53,43 +53,43 @@ static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) return ret; } -static int stpmu1_bind(struct udevice *dev) +static int stpmic1_bind(struct udevice *dev) { -#ifndef CONFIG_SPL_BUILD +#if CONFIG_IS_ENABLED(DM_REGULATOR) ofnode regulators_node; int children; regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - dev_dbg(dev, "regulators subnode not found!\n"); + dev_dbg(dev, "regulators subnode not found!"); return -ENXIO; } dev_dbg(dev, "found regulators subnode\n"); children = pmic_bind_children(dev, regulators_node, - stpmu1_children_info); + stpmic1_children_info); if (!children) dev_dbg(dev, "no child found\n"); -#endif /* CONFIG_SPL_BUILD */ +#endif /* DM_REGULATOR */ return 0; } -static struct dm_pmic_ops stpmu1_ops = { - .reg_count = stpmu1_reg_count, - .read = stpmu1_read, - .write = stpmu1_write, +static struct dm_pmic_ops stpmic1_ops = { + .reg_count = stpmic1_reg_count, + .read = stpmic1_read, + .write = stpmic1_write, }; -static const struct udevice_id stpmu1_ids[] = { - { .compatible = "st,stpmu1" }, +static const struct udevice_id stpmic1_ids[] = { + { .compatible = "st,stpmic1" }, { } }; -U_BOOT_DRIVER(pmic_stpmu1) = { - .name = "stpmu1_pmic", +U_BOOT_DRIVER(pmic_stpmic1) = { + .name = "stpmic1_pmic", .id = UCLASS_PMIC, - .of_match = stpmu1_ids, - .bind = stpmu1_bind, - .ops = &stpmu1_ops, + .of_match = stpmic1_ids, + .bind = stpmic1_bind, + .ops = &stpmic1_ops, }; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 3ed0dd2264..72dfc48981 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -244,11 +244,17 @@ config DM_REGULATOR_TPS65910 regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements the get/set api for value and enable. -config DM_REGULATOR_STPMU1 - bool "Enable driver for STPMU1 regulators" - depends on DM_REGULATOR && PMIC_STPMU1 +config DM_REGULATOR_STPMIC1 + bool "Enable driver for STPMIC1 regulators" + depends on DM_REGULATOR && PMIC_STPMIC1 ---help--- - Enable support for the regulator functions of the STPMU1 PMIC. The + Enable support for the regulator functions of the STPMIC1 PMIC. The driver implements get/set api for the various BUCKS and LDOs supported by the PMIC device. This driver is controlled by a device tree node which includes voltage limits. + +config SPL_DM_REGULATOR_STPMIC1 + bool "Enable driver for STPMIC1 regulators in SPL" + depends on SPL_DM_REGULATOR && PMIC_STPMIC1 + help + Enable support for the regulator functions of the STPMIC1 PMIC in SPL. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index cfc91e83a1..8c1506c88e 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -24,4 +24,4 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMU1) += stpmic1.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c index c62a19a68a..860258388e 100644 --- a/drivers/power/regulator/stpmic1.c +++ b/drivers/power/regulator/stpmic1.c @@ -11,44 +11,44 @@ #include #include -struct stpmu1_range { +struct stpmic1_range { int min_uv; int min_sel; int max_sel; int step; }; -struct stpmu1_output_range { - const struct stpmu1_range *ranges; +struct stpmic1_output { + const struct stpmic1_range *ranges; int nbranges; }; -#define STPMU1_MODE(_id, _val, _name) { \ +#define STPMIC1_MODE(_id, _val, _name) { \ .id = _id, \ .register_value = _val, \ .name = _name, \ } -#define STPMU1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \ +#define STPMIC1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \ .min_uv = _min_uv, \ .min_sel = _min_sel, \ .max_sel = _max_sel, \ .step = _step, \ } -#define STPMU1_OUTPUT_RANGE(_ranges, _nbranges) { \ +#define STPMIC1_OUTPUT(_ranges, _nbranges) { \ .ranges = _ranges, \ .nbranges = _nbranges, \ } -static int stpmu1_output_find_uv(int sel, - const struct stpmu1_output_range *output_range) +static int stpmic1_output_find_uv(int sel, + const struct stpmic1_output *output) { - const struct stpmu1_range *range; + const struct stpmic1_range *range; int i; - for (i = 0, range = output_range->ranges; - i < output_range->nbranges; i++, range++) { + for (i = 0, range = output->ranges; + i < output->nbranges; i++, range++) { if (sel >= range->min_sel && sel <= range->max_sel) return range->min_uv + (sel - range->min_sel) * range->step; @@ -57,14 +57,14 @@ static int stpmu1_output_find_uv(int sel, return -EINVAL; } -static int stpmu1_output_find_sel(int uv, - const struct stpmu1_output_range *output_range) +static int stpmic1_output_find_sel(int uv, + const struct stpmic1_output *output) { - const struct stpmu1_range *range; + const struct stpmic1_range *range; int i; - for (i = 0, range = output_range->ranges; - i < output_range->nbranges; i++, range++) { + for (i = 0, range = output->ranges; + i < output->nbranges; i++, range++) { if (uv == range->min_uv && !range->step) return range->min_sel; @@ -82,157 +82,157 @@ static int stpmu1_output_find_sel(int uv, * BUCK regulators */ -static const struct stpmu1_range buck1_ranges[] = { - STPMU1_RANGE(725000, 0, 4, 0), - STPMU1_RANGE(725000, 5, 36, 25000), - STPMU1_RANGE(1500000, 37, 63, 0), +static const struct stpmic1_range buck1_ranges[] = { + STPMIC1_RANGE(725000, 0, 4, 0), + STPMIC1_RANGE(725000, 5, 36, 25000), + STPMIC1_RANGE(1500000, 37, 63, 0), }; -static const struct stpmu1_range buck2_ranges[] = { - STPMU1_RANGE(1000000, 0, 17, 0), - STPMU1_RANGE(1050000, 18, 19, 0), - STPMU1_RANGE(1100000, 20, 21, 0), - STPMU1_RANGE(1150000, 22, 23, 0), - STPMU1_RANGE(1200000, 24, 25, 0), - STPMU1_RANGE(1250000, 26, 27, 0), - STPMU1_RANGE(1300000, 28, 29, 0), - STPMU1_RANGE(1350000, 30, 31, 0), - STPMU1_RANGE(1400000, 32, 33, 0), - STPMU1_RANGE(1450000, 34, 35, 0), - STPMU1_RANGE(1500000, 36, 63, 0), +static const struct stpmic1_range buck2_ranges[] = { + STPMIC1_RANGE(1000000, 0, 17, 0), + STPMIC1_RANGE(1050000, 18, 19, 0), + STPMIC1_RANGE(1100000, 20, 21, 0), + STPMIC1_RANGE(1150000, 22, 23, 0), + STPMIC1_RANGE(1200000, 24, 25, 0), + STPMIC1_RANGE(1250000, 26, 27, 0), + STPMIC1_RANGE(1300000, 28, 29, 0), + STPMIC1_RANGE(1350000, 30, 31, 0), + STPMIC1_RANGE(1400000, 32, 33, 0), + STPMIC1_RANGE(1450000, 34, 35, 0), + STPMIC1_RANGE(1500000, 36, 63, 0), }; -static const struct stpmu1_range buck3_ranges[] = { - STPMU1_RANGE(1000000, 0, 19, 0), - STPMU1_RANGE(1100000, 20, 23, 0), - STPMU1_RANGE(1200000, 24, 27, 0), - STPMU1_RANGE(1300000, 28, 31, 0), - STPMU1_RANGE(1400000, 32, 35, 0), - STPMU1_RANGE(1500000, 36, 55, 100000), - STPMU1_RANGE(3400000, 56, 63, 0), +static const struct stpmic1_range buck3_ranges[] = { + STPMIC1_RANGE(1000000, 0, 19, 0), + STPMIC1_RANGE(1100000, 20, 23, 0), + STPMIC1_RANGE(1200000, 24, 27, 0), + STPMIC1_RANGE(1300000, 28, 31, 0), + STPMIC1_RANGE(1400000, 32, 35, 0), + STPMIC1_RANGE(1500000, 36, 55, 100000), + STPMIC1_RANGE(3400000, 56, 63, 0), }; -static const struct stpmu1_range buck4_ranges[] = { - STPMU1_RANGE(600000, 0, 27, 25000), - STPMU1_RANGE(1300000, 28, 29, 0), - STPMU1_RANGE(1350000, 30, 31, 0), - STPMU1_RANGE(1400000, 32, 33, 0), - STPMU1_RANGE(1450000, 34, 35, 0), - STPMU1_RANGE(1500000, 36, 60, 100000), - STPMU1_RANGE(3900000, 61, 63, 0), +static const struct stpmic1_range buck4_ranges[] = { + STPMIC1_RANGE(600000, 0, 27, 25000), + STPMIC1_RANGE(1300000, 28, 29, 0), + STPMIC1_RANGE(1350000, 30, 31, 0), + STPMIC1_RANGE(1400000, 32, 33, 0), + STPMIC1_RANGE(1450000, 34, 35, 0), + STPMIC1_RANGE(1500000, 36, 60, 100000), + STPMIC1_RANGE(3900000, 61, 63, 0), }; /* BUCK: 1,2,3,4 - voltage ranges */ -static const struct stpmu1_output_range buck_voltage_range[] = { - STPMU1_OUTPUT_RANGE(buck1_ranges, ARRAY_SIZE(buck1_ranges)), - STPMU1_OUTPUT_RANGE(buck2_ranges, ARRAY_SIZE(buck2_ranges)), - STPMU1_OUTPUT_RANGE(buck3_ranges, ARRAY_SIZE(buck3_ranges)), - STPMU1_OUTPUT_RANGE(buck4_ranges, ARRAY_SIZE(buck4_ranges)), +static const struct stpmic1_output buck_voltage_range[] = { + STPMIC1_OUTPUT(buck1_ranges, ARRAY_SIZE(buck1_ranges)), + STPMIC1_OUTPUT(buck2_ranges, ARRAY_SIZE(buck2_ranges)), + STPMIC1_OUTPUT(buck3_ranges, ARRAY_SIZE(buck3_ranges)), + STPMIC1_OUTPUT(buck4_ranges, ARRAY_SIZE(buck4_ranges)), }; /* BUCK modes */ static const struct dm_regulator_mode buck_modes[] = { - STPMU1_MODE(STPMU1_BUCK_MODE_HP, STPMU1_BUCK_MODE_HP, "HP"), - STPMU1_MODE(STPMU1_BUCK_MODE_LP, STPMU1_BUCK_MODE_LP, "LP"), + STPMIC1_MODE(STPMIC1_BUCK_MODE_HP, STPMIC1_BUCK_MODE_HP, "HP"), + STPMIC1_MODE(STPMIC1_BUCK_MODE_LP, STPMIC1_BUCK_MODE_LP, "LP"), }; -static int stpmu1_buck_get_uv(struct udevice *dev, int buck) +static int stpmic1_buck_get_uv(struct udevice *dev, int buck) { int sel; - sel = pmic_reg_read(dev, STPMU1_BUCKX_CTRL_REG(buck)); + sel = pmic_reg_read(dev, STPMIC1_BUCKX_CTRL_REG(buck)); if (sel < 0) return sel; - sel &= STPMU1_BUCK_OUTPUT_MASK; - sel >>= STPMU1_BUCK_OUTPUT_SHIFT; + sel &= STPMIC1_BUCK_OUTPUT_MASK; + sel >>= STPMIC1_BUCK_OUTPUT_SHIFT; - return stpmu1_output_find_uv(sel, &buck_voltage_range[buck]); + return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]); } -static int stpmu1_buck_get_value(struct udevice *dev) +static int stpmic1_buck_get_value(struct udevice *dev) { - return stpmu1_buck_get_uv(dev->parent, dev->driver_data - 1); + return stpmic1_buck_get_uv(dev->parent, dev->driver_data - 1); } -static int stpmu1_buck_set_value(struct udevice *dev, int uv) +static int stpmic1_buck_set_value(struct udevice *dev, int uv) { int sel, buck = dev->driver_data - 1; - sel = stpmu1_output_find_sel(uv, &buck_voltage_range[buck]); + sel = stpmic1_output_find_sel(uv, &buck_voltage_range[buck]); if (sel < 0) return sel; return pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(buck), - STPMU1_BUCK_OUTPUT_MASK, - sel << STPMU1_BUCK_OUTPUT_SHIFT); + STPMIC1_BUCKX_CTRL_REG(buck), + STPMIC1_BUCK_OUTPUT_MASK, + sel << STPMIC1_BUCK_OUTPUT_SHIFT); } -static int stpmu1_buck_get_enable(struct udevice *dev) +static int stpmic1_buck_get_enable(struct udevice *dev) { int ret; ret = pmic_reg_read(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1)); if (ret < 0) return false; - return ret & STPMU1_BUCK_EN ? true : false; + return ret & STPMIC1_BUCK_EN ? true : false; } -static int stpmu1_buck_set_enable(struct udevice *dev, bool enable) +static int stpmic1_buck_set_enable(struct udevice *dev, bool enable) { struct dm_regulator_uclass_platdata *uc_pdata; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; + int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS : + STPMIC1_DEFAULT_STOP_DELAY_MS; int ret, uv; /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_buck_get_enable(dev) == enable) + if (stpmic1_buck_get_enable(dev) == enable) return 0; if (enable) { uc_pdata = dev_get_uclass_platdata(dev); - uv = stpmu1_buck_get_value(dev); - if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) - stpmu1_buck_set_value(dev, uc_pdata->min_uV); + uv = stpmic1_buck_get_value(dev); + if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV) + stpmic1_buck_set_value(dev, uc_pdata->min_uV); } ret = pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMU1_BUCK_EN, enable ? STPMU1_BUCK_EN : 0); + STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMIC1_BUCK_EN, enable ? STPMIC1_BUCK_EN : 0); mdelay(delay); return ret; } -static int stpmu1_buck_get_mode(struct udevice *dev) +static int stpmic1_buck_get_mode(struct udevice *dev) { int ret; ret = pmic_reg_read(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1)); if (ret < 0) return ret; - return ret & STPMU1_BUCK_MODE ? STPMU1_BUCK_MODE_LP : - STPMU1_BUCK_MODE_HP; + return ret & STPMIC1_BUCK_MODE ? STPMIC1_BUCK_MODE_LP : + STPMIC1_BUCK_MODE_HP; } -static int stpmu1_buck_set_mode(struct udevice *dev, int mode) +static int stpmic1_buck_set_mode(struct udevice *dev, int mode) { return pmic_clrsetbits(dev->parent, - STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMU1_BUCK_MODE, - mode ? STPMU1_BUCK_MODE : 0); + STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMIC1_BUCK_MODE, + mode ? STPMIC1_BUCK_MODE : 0); } -static int stpmu1_buck_probe(struct udevice *dev) +static int stpmic1_buck_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_BUCK) + if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_BUCK) return -EINVAL; uc_pdata = dev_get_uclass_platdata(dev); @@ -244,206 +244,206 @@ static int stpmu1_buck_probe(struct udevice *dev) return 0; } -static const struct dm_regulator_ops stpmu1_buck_ops = { - .get_value = stpmu1_buck_get_value, - .set_value = stpmu1_buck_set_value, - .get_enable = stpmu1_buck_get_enable, - .set_enable = stpmu1_buck_set_enable, - .get_mode = stpmu1_buck_get_mode, - .set_mode = stpmu1_buck_set_mode, +static const struct dm_regulator_ops stpmic1_buck_ops = { + .get_value = stpmic1_buck_get_value, + .set_value = stpmic1_buck_set_value, + .get_enable = stpmic1_buck_get_enable, + .set_enable = stpmic1_buck_set_enable, + .get_mode = stpmic1_buck_get_mode, + .set_mode = stpmic1_buck_set_mode, }; -U_BOOT_DRIVER(stpmu1_buck) = { - .name = "stpmu1_buck", +U_BOOT_DRIVER(stpmic1_buck) = { + .name = "stpmic1_buck", .id = UCLASS_REGULATOR, - .ops = &stpmu1_buck_ops, - .probe = stpmu1_buck_probe, + .ops = &stpmic1_buck_ops, + .probe = stpmic1_buck_probe, }; /* * LDO regulators */ -static const struct stpmu1_range ldo12_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 24, 100000), - STPMU1_RANGE(3300000, 25, 31, 0), +static const struct stpmic1_range ldo12_ranges[] = { + STPMIC1_RANGE(1700000, 0, 7, 0), + STPMIC1_RANGE(1700000, 8, 24, 100000), + STPMIC1_RANGE(3300000, 25, 31, 0), }; -static const struct stpmu1_range ldo3_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 24, 100000), - STPMU1_RANGE(3300000, 25, 30, 0), +static const struct stpmic1_range ldo3_ranges[] = { + STPMIC1_RANGE(1700000, 0, 7, 0), + STPMIC1_RANGE(1700000, 8, 24, 100000), + STPMIC1_RANGE(3300000, 25, 30, 0), /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */ }; -static const struct stpmu1_range ldo5_ranges[] = { - STPMU1_RANGE(1700000, 0, 7, 0), - STPMU1_RANGE(1700000, 8, 30, 100000), - STPMU1_RANGE(3900000, 31, 31, 0), +static const struct stpmic1_range ldo5_ranges[] = { + STPMIC1_RANGE(1700000, 0, 7, 0), + STPMIC1_RANGE(1700000, 8, 30, 100000), + STPMIC1_RANGE(3900000, 31, 31, 0), }; -static const struct stpmu1_range ldo6_ranges[] = { - STPMU1_RANGE(900000, 0, 24, 100000), - STPMU1_RANGE(3300000, 25, 31, 0), +static const struct stpmic1_range ldo6_ranges[] = { + STPMIC1_RANGE(900000, 0, 24, 100000), + STPMIC1_RANGE(3300000, 25, 31, 0), }; /* LDO: 1,2,3,4,5,6 - voltage ranges */ -static const struct stpmu1_output_range ldo_voltage_range[] = { - STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), - STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), - STPMU1_OUTPUT_RANGE(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)), - STPMU1_OUTPUT_RANGE(NULL, 0), - STPMU1_OUTPUT_RANGE(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)), - STPMU1_OUTPUT_RANGE(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)), +static const struct stpmic1_output ldo_voltage_range[] = { + STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMIC1_OUTPUT(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)), + STPMIC1_OUTPUT(NULL, 0), + STPMIC1_OUTPUT(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)), + STPMIC1_OUTPUT(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)), }; /* LDO modes */ static const struct dm_regulator_mode ldo_modes[] = { - STPMU1_MODE(STPMU1_LDO_MODE_NORMAL, - STPMU1_LDO_MODE_NORMAL, "NORMAL"), - STPMU1_MODE(STPMU1_LDO_MODE_BYPASS, - STPMU1_LDO_MODE_BYPASS, "BYPASS"), - STPMU1_MODE(STPMU1_LDO_MODE_SINK_SOURCE, - STPMU1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"), + STPMIC1_MODE(STPMIC1_LDO_MODE_NORMAL, + STPMIC1_LDO_MODE_NORMAL, "NORMAL"), + STPMIC1_MODE(STPMIC1_LDO_MODE_BYPASS, + STPMIC1_LDO_MODE_BYPASS, "BYPASS"), + STPMIC1_MODE(STPMIC1_LDO_MODE_SINK_SOURCE, + STPMIC1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"), }; -static int stpmu1_ldo_get_value(struct udevice *dev) +static int stpmic1_ldo_get_value(struct udevice *dev) { int sel, ldo = dev->driver_data - 1; - sel = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); if (sel < 0) return sel; /* ldo4 => 3,3V */ - if (ldo == STPMU1_LDO4) - return STPMU1_LDO4_UV; + if (ldo == STPMIC1_LDO4) + return STPMIC1_LDO4_UV; - sel &= STPMU1_LDO12356_OUTPUT_MASK; - sel >>= STPMU1_LDO12356_OUTPUT_SHIFT; + sel &= STPMIC1_LDO12356_OUTPUT_MASK; + sel >>= STPMIC1_LDO12356_OUTPUT_SHIFT; /* ldo3, sel = 31 => BUCK2/2 */ - if (ldo == STPMU1_LDO3 && sel == STPMU1_LDO3_DDR_SEL) - return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; + if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL) + return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2; - return stpmu1_output_find_uv(sel, &ldo_voltage_range[ldo]); + return stpmic1_output_find_uv(sel, &ldo_voltage_range[ldo]); } -static int stpmu1_ldo_set_value(struct udevice *dev, int uv) +static int stpmic1_ldo_set_value(struct udevice *dev, int uv) { int sel, ldo = dev->driver_data - 1; /* ldo4 => not possible */ - if (ldo == STPMU1_LDO4) + if (ldo == STPMIC1_LDO4) return -EINVAL; - sel = stpmu1_output_find_sel(uv, &ldo_voltage_range[ldo]); + sel = stpmic1_output_find_sel(uv, &ldo_voltage_range[ldo]); if (sel < 0) return sel; return pmic_clrsetbits(dev->parent, - STPMU1_LDOX_CTRL_REG(ldo), - STPMU1_LDO12356_OUTPUT_MASK, - sel << STPMU1_LDO12356_OUTPUT_SHIFT); + STPMIC1_LDOX_CTRL_REG(ldo), + STPMIC1_LDO12356_OUTPUT_MASK, + sel << STPMIC1_LDO12356_OUTPUT_SHIFT); } -static int stpmu1_ldo_get_enable(struct udevice *dev) +static int stpmic1_ldo_get_enable(struct udevice *dev) { int ret; ret = pmic_reg_read(dev->parent, - STPMU1_LDOX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_LDOX_CTRL_REG(dev->driver_data - 1)); if (ret < 0) return false; - return ret & STPMU1_LDO_EN ? true : false; + return ret & STPMIC1_LDO_EN ? true : false; } -static int stpmu1_ldo_set_enable(struct udevice *dev, bool enable) +static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable) { struct dm_regulator_uclass_platdata *uc_pdata; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; + int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS : + STPMIC1_DEFAULT_STOP_DELAY_MS; int ret, uv; /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_ldo_get_enable(dev) == enable) + if (stpmic1_ldo_get_enable(dev) == enable) return 0; if (enable) { uc_pdata = dev_get_uclass_platdata(dev); - uv = stpmu1_ldo_get_value(dev); - if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) - stpmu1_ldo_set_value(dev, uc_pdata->min_uV); + uv = stpmic1_ldo_get_value(dev); + if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV) + stpmic1_ldo_set_value(dev, uc_pdata->min_uV); } ret = pmic_clrsetbits(dev->parent, - STPMU1_LDOX_CTRL_REG(dev->driver_data - 1), - STPMU1_LDO_EN, enable ? STPMU1_LDO_EN : 0); + STPMIC1_LDOX_CTRL_REG(dev->driver_data - 1), + STPMIC1_LDO_EN, enable ? STPMIC1_LDO_EN : 0); mdelay(delay); return ret; } -static int stpmu1_ldo_get_mode(struct udevice *dev) +static int stpmic1_ldo_get_mode(struct udevice *dev) { int ret, ldo = dev->driver_data - 1; - if (ldo != STPMU1_LDO3) + if (ldo != STPMIC1_LDO3) return -EINVAL; - ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); if (ret < 0) return ret; - if (ret & STPMU1_LDO3_MODE) - return STPMU1_LDO_MODE_BYPASS; + if (ret & STPMIC1_LDO3_MODE) + return STPMIC1_LDO_MODE_BYPASS; - ret &= STPMU1_LDO12356_OUTPUT_MASK; - ret >>= STPMU1_LDO12356_OUTPUT_SHIFT; + ret &= STPMIC1_LDO12356_OUTPUT_MASK; + ret >>= STPMIC1_LDO12356_OUTPUT_SHIFT; - return ret == STPMU1_LDO3_DDR_SEL ? STPMU1_LDO_MODE_SINK_SOURCE : - STPMU1_LDO_MODE_NORMAL; + return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE : + STPMIC1_LDO_MODE_NORMAL; } -static int stpmu1_ldo_set_mode(struct udevice *dev, int mode) +static int stpmic1_ldo_set_mode(struct udevice *dev, int mode) { int ret, ldo = dev->driver_data - 1; - if (ldo != STPMU1_LDO3) + if (ldo != STPMIC1_LDO3) return -EINVAL; - ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); if (ret < 0) return ret; switch (mode) { - case STPMU1_LDO_MODE_SINK_SOURCE: - ret &= ~STPMU1_LDO12356_OUTPUT_MASK; - ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; - case STPMU1_LDO_MODE_NORMAL: - ret &= ~STPMU1_LDO3_MODE; + case STPMIC1_LDO_MODE_SINK_SOURCE: + ret &= ~STPMIC1_LDO12356_OUTPUT_MASK; + ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_OUTPUT_SHIFT; + case STPMIC1_LDO_MODE_NORMAL: + ret &= ~STPMIC1_LDO3_MODE; break; - case STPMU1_LDO_MODE_BYPASS: - ret |= STPMU1_LDO3_MODE; + case STPMIC1_LDO_MODE_BYPASS: + ret |= STPMIC1_LDO3_MODE; break; } - return pmic_reg_write(dev->parent, STPMU1_LDOX_CTRL_REG(ldo), ret); + return pmic_reg_write(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo), ret); } -static int stpmu1_ldo_probe(struct udevice *dev) +static int stpmic1_ldo_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_LDO) + if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_LDO) return -EINVAL; uc_pdata = dev_get_uclass_platdata(dev); uc_pdata->type = REGULATOR_TYPE_LDO; - if (dev->driver_data - 1 == STPMU1_LDO3) { + if (dev->driver_data - 1 == STPMIC1_LDO3) { uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes; uc_pdata->mode_count = ARRAY_SIZE(ldo_modes); } else { @@ -453,61 +453,61 @@ static int stpmu1_ldo_probe(struct udevice *dev) return 0; } -static const struct dm_regulator_ops stpmu1_ldo_ops = { - .get_value = stpmu1_ldo_get_value, - .set_value = stpmu1_ldo_set_value, - .get_enable = stpmu1_ldo_get_enable, - .set_enable = stpmu1_ldo_set_enable, - .get_mode = stpmu1_ldo_get_mode, - .set_mode = stpmu1_ldo_set_mode, +static const struct dm_regulator_ops stpmic1_ldo_ops = { + .get_value = stpmic1_ldo_get_value, + .set_value = stpmic1_ldo_set_value, + .get_enable = stpmic1_ldo_get_enable, + .set_enable = stpmic1_ldo_set_enable, + .get_mode = stpmic1_ldo_get_mode, + .set_mode = stpmic1_ldo_set_mode, }; -U_BOOT_DRIVER(stpmu1_ldo) = { - .name = "stpmu1_ldo", +U_BOOT_DRIVER(stpmic1_ldo) = { + .name = "stpmic1_ldo", .id = UCLASS_REGULATOR, - .ops = &stpmu1_ldo_ops, - .probe = stpmu1_ldo_probe, + .ops = &stpmic1_ldo_ops, + .probe = stpmic1_ldo_probe, }; /* * VREF DDR regulator */ -static int stpmu1_vref_ddr_get_value(struct udevice *dev) +static int stpmic1_vref_ddr_get_value(struct udevice *dev) { /* BUCK2/2 */ - return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; + return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2; } -static int stpmu1_vref_ddr_get_enable(struct udevice *dev) +static int stpmic1_vref_ddr_get_enable(struct udevice *dev) { int ret; - ret = pmic_reg_read(dev->parent, STPMU1_VREF_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_VREF_CTRL_REG); if (ret < 0) return false; - return ret & STPMU1_VREF_EN ? true : false; + return ret & STPMIC1_VREF_EN ? true : false; } -static int stpmu1_vref_ddr_set_enable(struct udevice *dev, bool enable) +static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable) { - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; + int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS : + STPMIC1_DEFAULT_STOP_DELAY_MS; int ret; /* if regulator is already in the wanted state, nothing to do */ - if (stpmu1_vref_ddr_get_enable(dev) == enable) + if (stpmic1_vref_ddr_get_enable(dev) == enable) return 0; - ret = pmic_clrsetbits(dev->parent, STPMU1_VREF_CTRL_REG, - STPMU1_VREF_EN, enable ? STPMU1_VREF_EN : 0); + ret = pmic_clrsetbits(dev->parent, STPMIC1_VREF_CTRL_REG, + STPMIC1_VREF_EN, enable ? STPMIC1_VREF_EN : 0); mdelay(delay); return ret; } -static int stpmu1_vref_ddr_probe(struct udevice *dev) +static int stpmic1_vref_ddr_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; @@ -519,59 +519,59 @@ static int stpmu1_vref_ddr_probe(struct udevice *dev) return 0; } -static const struct dm_regulator_ops stpmu1_vref_ddr_ops = { - .get_value = stpmu1_vref_ddr_get_value, - .get_enable = stpmu1_vref_ddr_get_enable, - .set_enable = stpmu1_vref_ddr_set_enable, +static const struct dm_regulator_ops stpmic1_vref_ddr_ops = { + .get_value = stpmic1_vref_ddr_get_value, + .get_enable = stpmic1_vref_ddr_get_enable, + .set_enable = stpmic1_vref_ddr_set_enable, }; -U_BOOT_DRIVER(stpmu1_vref_ddr) = { - .name = "stpmu1_vref_ddr", +U_BOOT_DRIVER(stpmic1_vref_ddr) = { + .name = "stpmic1_vref_ddr", .id = UCLASS_REGULATOR, - .ops = &stpmu1_vref_ddr_ops, - .probe = stpmu1_vref_ddr_probe, + .ops = &stpmic1_vref_ddr_ops, + .probe = stpmic1_vref_ddr_probe, }; /* * BOOST regulator */ -static int stpmu1_boost_get_enable(struct udevice *dev) +static int stpmic1_boost_get_enable(struct udevice *dev) { int ret; - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); if (ret < 0) return false; - return ret & STPMU1_USB_BOOST_EN ? true : false; + return ret & STPMIC1_USB_BOOST_EN ? true : false; } -static int stpmu1_boost_set_enable(struct udevice *dev, bool enable) +static int stpmic1_boost_set_enable(struct udevice *dev, bool enable) { int ret; - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); if (ret < 0) return ret; - if (!enable && ret & STPMU1_USB_PWR_SW_EN) + if (!enable && ret & STPMIC1_USB_PWR_SW_EN) return -EINVAL; /* if regulator is already in the wanted state, nothing to do */ - if (!!(ret & STPMU1_USB_BOOST_EN) == enable) + if (!!(ret & STPMIC1_USB_BOOST_EN) == enable) return 0; - ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, - enable ? STPMU1_USB_BOOST_EN : 0); + ret = pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, + STPMIC1_USB_BOOST_EN, + enable ? STPMIC1_USB_BOOST_EN : 0); if (enable) - mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); + mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS); return ret; } -static int stpmu1_boost_probe(struct udevice *dev) +static int stpmic1_boost_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; @@ -583,42 +583,42 @@ static int stpmu1_boost_probe(struct udevice *dev) return 0; } -static const struct dm_regulator_ops stpmu1_boost_ops = { - .get_enable = stpmu1_boost_get_enable, - .set_enable = stpmu1_boost_set_enable, +static const struct dm_regulator_ops stpmic1_boost_ops = { + .get_enable = stpmic1_boost_get_enable, + .set_enable = stpmic1_boost_set_enable, }; -U_BOOT_DRIVER(stpmu1_boost) = { - .name = "stpmu1_boost", +U_BOOT_DRIVER(stpmic1_boost) = { + .name = "stpmic1_boost", .id = UCLASS_REGULATOR, - .ops = &stpmu1_boost_ops, - .probe = stpmu1_boost_probe, + .ops = &stpmic1_boost_ops, + .probe = stpmic1_boost_probe, }; /* * USB power switch */ -static int stpmu1_pwr_sw_get_enable(struct udevice *dev) +static int stpmic1_pwr_sw_get_enable(struct udevice *dev) { uint mask = 1 << dev->driver_data; int ret; - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); if (ret < 0) return false; return ret & mask ? true : false; } -static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable) +static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable) { uint mask = 1 << dev->driver_data; - int delay = enable ? STPMU1_DEFAULT_START_UP_DELAY_MS : - STPMU1_DEFAULT_STOP_DELAY_MS; + int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS : + STPMIC1_DEFAULT_STOP_DELAY_MS; int ret; - ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); if (ret < 0) return ret; @@ -627,28 +627,28 @@ static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable) return 0; /* Boost management */ - if (enable && !(ret & STPMU1_USB_BOOST_EN)) { - pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, STPMU1_USB_BOOST_EN); - mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); - } else if (!enable && ret & STPMU1_USB_BOOST_EN && - (ret & STPMU1_USB_PWR_SW_EN) != STPMU1_USB_PWR_SW_EN) { - pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, - STPMU1_USB_BOOST_EN, 0); + if (enable && !(ret & STPMIC1_USB_BOOST_EN)) { + pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, + STPMIC1_USB_BOOST_EN, STPMIC1_USB_BOOST_EN); + mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS); + } else if (!enable && ret & STPMIC1_USB_BOOST_EN && + (ret & STPMIC1_USB_PWR_SW_EN) != STPMIC1_USB_PWR_SW_EN) { + pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, + STPMIC1_USB_BOOST_EN, 0); } - ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + ret = pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, mask, enable ? mask : 0); mdelay(delay); return ret; } -static int stpmu1_pwr_sw_probe(struct udevice *dev) +static int stpmic1_pwr_sw_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - if (!dev->driver_data || dev->driver_data > STPMU1_MAX_PWR_SW) + if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_PWR_SW) return -EINVAL; uc_pdata = dev_get_uclass_platdata(dev); @@ -659,14 +659,14 @@ static int stpmu1_pwr_sw_probe(struct udevice *dev) return 0; } -static const struct dm_regulator_ops stpmu1_pwr_sw_ops = { - .get_enable = stpmu1_pwr_sw_get_enable, - .set_enable = stpmu1_pwr_sw_set_enable, +static const struct dm_regulator_ops stpmic1_pwr_sw_ops = { + .get_enable = stpmic1_pwr_sw_get_enable, + .set_enable = stpmic1_pwr_sw_set_enable, }; -U_BOOT_DRIVER(stpmu1_pwr_sw) = { - .name = "stpmu1_pwr_sw", +U_BOOT_DRIVER(stpmic1_pwr_sw) = { + .name = "stpmic1_pwr_sw", .id = UCLASS_REGULATOR, - .ops = &stpmu1_pwr_sw_ops, - .probe = stpmu1_pwr_sw_probe, + .ops = &stpmic1_pwr_sw_ops, + .probe = stpmic1_pwr_sw_probe, }; diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h index 81982ebe2c..b2d6c83462 100644 --- a/include/dt-bindings/mfd/st,stpmic1.h +++ b/include/dt-bindings/mfd/st,stpmic1.h @@ -1,60 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * This file is part of stpmu1 pmic driver - * - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author: Pascal Paillet for STMicroelectronics. - * - * License type: GPLv2 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Philippe Peurichard , + * Pascal Paillet for STMicroelectronics. */ -#ifndef __DT_BINDINGS_STPMU1_H__ -#define __DT_BINDINGS_STPMU1_H__ +#ifndef __DT_BINDINGS_STPMIC1_H__ +#define __DT_BINDINGS_STPMIC1_H__ /* IRQ definitions */ -#define IT_PONKEY_F 0 -#define IT_PONKEY_R 1 -#define IT_WAKEUP_F 2 -#define IT_WAKEUP_R 3 -#define IT_VBUS_OTG_F 4 -#define IT_VBUS_OTG_R 5 -#define IT_SWOUT_F 6 -#define IT_SWOUT_R 7 +#define IT_PONKEY_F 0 +#define IT_PONKEY_R 1 +#define IT_WAKEUP_F 2 +#define IT_WAKEUP_R 3 +#define IT_VBUS_OTG_F 4 +#define IT_VBUS_OTG_R 5 +#define IT_SWOUT_F 6 +#define IT_SWOUT_R 7 -#define IT_CURLIM_BUCK1 8 -#define IT_CURLIM_BUCK2 9 -#define IT_CURLIM_BUCK3 10 -#define IT_CURLIM_BUCK4 11 -#define IT_OCP_OTG 12 -#define IT_OCP_SWOUT 13 -#define IT_OCP_BOOST 14 -#define IT_OVP_BOOST 15 +#define IT_CURLIM_BUCK1 8 +#define IT_CURLIM_BUCK2 9 +#define IT_CURLIM_BUCK3 10 +#define IT_CURLIM_BUCK4 11 +#define IT_OCP_OTG 12 +#define IT_OCP_SWOUT 13 +#define IT_OCP_BOOST 14 +#define IT_OVP_BOOST 15 -#define IT_CURLIM_LDO1 16 -#define IT_CURLIM_LDO2 17 -#define IT_CURLIM_LDO3 18 -#define IT_CURLIM_LDO4 19 -#define IT_CURLIM_LDO5 20 -#define IT_CURLIM_LDO6 21 -#define IT_SHORT_SWOTG 22 -#define IT_SHORT_SWOUT 23 +#define IT_CURLIM_LDO1 16 +#define IT_CURLIM_LDO2 17 +#define IT_CURLIM_LDO3 18 +#define IT_CURLIM_LDO4 19 +#define IT_CURLIM_LDO5 20 +#define IT_CURLIM_LDO6 21 +#define IT_SHORT_SWOTG 22 +#define IT_SHORT_SWOUT 23 -#define IT_TWARN_F 24 -#define IT_TWARN_R 25 -#define IT_VINLOW_F 26 -#define IT_VINLOW_R 27 -#define IT_SWIN_F 30 -#define IT_SWIN_R 31 +#define IT_TWARN_F 24 +#define IT_TWARN_R 25 +#define IT_VINLOW_F 26 +#define IT_VINLOW_R 27 +#define IT_SWIN_F 30 +#define IT_SWIN_R 31 -#endif /* __DT_BINDINGS_STPMU1_H__ */ +#endif /* __DT_BINDINGS_STPMIC1_H__ */ diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h index 5906fbf832..5ed67d29cf 100644 --- a/include/power/stpmic1.h +++ b/include/power/stpmic1.h @@ -3,83 +3,90 @@ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ -#ifndef __PMIC_STPMU1_H_ -#define __PMIC_STPMU1_H_ - -#define STPMU1_MASK_RESET_BUCK 0x18 -#define STPMU1_BUCKX_CTRL_REG(buck) (0x20 + (buck)) -#define STPMU1_VREF_CTRL_REG 0x24 -#define STPMU1_LDOX_CTRL_REG(ldo) (0x25 + (ldo)) -#define STPMU1_USB_CTRL_REG 0x40 -#define STPMU1_NVM_USER_STATUS_REG 0xb8 -#define STPMU1_NVM_USER_CONTROL_REG 0xb9 - -#define STPMU1_MASK_RESET_BUCK3 BIT(2) - -#define STPMU1_BUCK_EN BIT(0) -#define STPMU1_BUCK_MODE BIT(1) -#define STPMU1_BUCK_OUTPUT_MASK GENMASK(7, 2) -#define STPMU1_BUCK_OUTPUT_SHIFT 2 -#define STPMU1_BUCK2_1200000V (24 << STPMU1_BUCK_OUTPUT_SHIFT) -#define STPMU1_BUCK2_1350000V (30 << STPMU1_BUCK_OUTPUT_SHIFT) -#define STPMU1_BUCK3_1800000V (39 << STPMU1_BUCK_OUTPUT_SHIFT) - -#define STPMU1_VREF_EN BIT(0) - -#define STPMU1_LDO_EN BIT(0) -#define STPMU1_LDO12356_OUTPUT_MASK GENMASK(6, 2) -#define STPMU1_LDO12356_OUTPUT_SHIFT 2 -#define STPMU1_LDO3_MODE BIT(7) -#define STPMU1_LDO3_DDR_SEL 31 -#define STPMU1_LDO3_1800000 (9 << STPMU1_LDO12356_OUTPUT_SHIFT) -#define STPMU1_LDO4_UV 3300000 - -#define STPMU1_USB_BOOST_EN BIT(0) -#define STPMU1_USB_PWR_SW_EN GENMASK(2, 1) - -#define STPMU1_NVM_USER_CONTROL_PROGRAM BIT(0) -#define STPMU1_NVM_USER_CONTROL_READ BIT(1) - -#define STPMU1_NVM_USER_STATUS_BUSY BIT(0) -#define STPMU1_NVM_USER_STATUS_ERROR BIT(1) - -#define STPMU1_DEFAULT_START_UP_DELAY_MS 1 -#define STPMU1_DEFAULT_STOP_DELAY_MS 5 -#define STPMU1_USB_BOOST_START_UP_DELAY_MS 10 +#ifndef __PMIC_STPMIC1_H_ +#define __PMIC_STPMIC1_H_ + +#define STPMIC1_MAIN_CONTROL_REG 0x10 +#define STPMIC1_MASK_RESET_BUCK 0x18 +#define STPMIC1_MASK_RESET_LDOS 0x1a +#define STPMIC1_BUCKX_CTRL_REG(buck) (0x20 + (buck)) +#define STPMIC1_VREF_CTRL_REG 0x24 +#define STPMIC1_LDOX_CTRL_REG(ldo) (0x25 + (ldo)) +#define STPMIC1_USB_CTRL_REG 0x40 +#define STPMIC1_NVM_USER_STATUS_REG 0xb8 +#define STPMIC1_NVM_USER_CONTROL_REG 0xb9 + +/* Main PMIC Control Register (MAIN_CONTROL_REG) */ +#define STPMIC1_CTRL_SWITCH_OFF BIT(0) +#define STPMIC1_CTRL_RESTART BIT(1) + +#define STPMIC1_MASK_RESET_BUCK3 BIT(2) +#define STPMIC1_MASK_RESET_BUCK_DBG GENMASK(3, 0) +#define STPMIC1_MASK_RESET_LDOS_DBG 0x6F + +#define STPMIC1_BUCK_EN BIT(0) +#define STPMIC1_BUCK_MODE BIT(1) +#define STPMIC1_BUCK_OUTPUT_MASK GENMASK(7, 2) +#define STPMIC1_BUCK_OUTPUT_SHIFT 2 +#define STPMIC1_BUCK2_1200000V (24 << STPMIC1_BUCK_OUTPUT_SHIFT) +#define STPMIC1_BUCK2_1350000V (30 << STPMIC1_BUCK_OUTPUT_SHIFT) +#define STPMIC1_BUCK3_1800000V (39 << STPMIC1_BUCK_OUTPUT_SHIFT) + +#define STPMIC1_VREF_EN BIT(0) + +#define STPMIC1_LDO_EN BIT(0) +#define STPMIC1_LDO12356_OUTPUT_MASK GENMASK(6, 2) +#define STPMIC1_LDO12356_OUTPUT_SHIFT 2 +#define STPMIC1_LDO3_MODE BIT(7) +#define STPMIC1_LDO3_DDR_SEL 31 +#define STPMIC1_LDO3_1800000 (9 << STPMIC1_LDO12356_OUTPUT_SHIFT) +#define STPMIC1_LDO4_UV 3300000 + +#define STPMIC1_USB_BOOST_EN BIT(0) +#define STPMIC1_USB_PWR_SW_EN GENMASK(2, 1) + +#define STPMIC1_NVM_USER_CONTROL_PROGRAM BIT(0) +#define STPMIC1_NVM_USER_CONTROL_READ BIT(1) + +#define STPMIC1_NVM_USER_STATUS_BUSY BIT(0) +#define STPMIC1_NVM_USER_STATUS_ERROR BIT(1) + +#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 +#define STPMIC1_DEFAULT_STOP_DELAY_MS 5 +#define STPMIC1_USB_BOOST_START_UP_DELAY_MS 10 enum { - STPMU1_BUCK1, - STPMU1_BUCK2, - STPMU1_BUCK3, - STPMU1_BUCK4, - STPMU1_MAX_BUCK, + STPMIC1_BUCK1, + STPMIC1_BUCK2, + STPMIC1_BUCK3, + STPMIC1_BUCK4, + STPMIC1_MAX_BUCK, }; enum { - STPMU1_BUCK_MODE_HP, - STPMU1_BUCK_MODE_LP, + STPMIC1_BUCK_MODE_HP, + STPMIC1_BUCK_MODE_LP, }; enum { - STPMU1_LDO1, - STPMU1_LDO2, - STPMU1_LDO3, - STPMU1_LDO4, - STPMU1_LDO5, - STPMU1_LDO6, - STPMU1_MAX_LDO, + STPMIC1_LDO1, + STPMIC1_LDO2, + STPMIC1_LDO3, + STPMIC1_LDO4, + STPMIC1_LDO5, + STPMIC1_LDO6, + STPMIC1_MAX_LDO, }; enum { - STPMU1_LDO_MODE_NORMAL, - STPMU1_LDO_MODE_BYPASS, - STPMU1_LDO_MODE_SINK_SOURCE, + STPMIC1_LDO_MODE_NORMAL, + STPMIC1_LDO_MODE_BYPASS, + STPMIC1_LDO_MODE_SINK_SOURCE, }; enum { - STPMU1_PWR_SW1, - STPMU1_PWR_SW2, - STPMU1_MAX_PWR_SW, + STPMIC1_PWR_SW1, + STPMIC1_PWR_SW2, + STPMIC1_MAX_PWR_SW, }; - #endif -- cgit From db4ff0df656f8ca8d363df64cddc7b5f835a7ecc Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:18 +0100 Subject: stpmic1: update register names Alignment with STPMIC1 datasheet s/MAIN_CONTROL_REG/MAIN_CR/g s/MASK_RESET_BUCK/BUCKS_MRST_CR/g s/MASK_RESET_LDOS/LDOS_MRST_CR/g s/BUCKX_CTRL_REG/BUCKX_MAIN_CR/g s/VREF_CTRL_REG/REFDDR_MAIN_CR/g s/LDOX_CTRL_REG/LDOX_MAIN_CR/g s/USB_CTRL_REG/BST_SW_CR/g s/STPMIC1_NVM_USER_STATUS_REG/STPMIC1_NVM_SR/g s/STPMIC1_NVM_USER_CONTROL_REG/STPMIC1_NVM_CR/g and update all the associated defines. Signed-off-by: Patrick Delaunay --- board/st/stm32mp1/board.c | 24 ++++---- board/st/stm32mp1/spl.c | 6 +- drivers/power/regulator/stpmic1.c | 114 +++++++++++++++++++------------------- include/power/stpmic1.h | 98 +++++++++++++++++++------------- 4 files changed, 130 insertions(+), 112 deletions(-) diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 2a94f10155..5c1acca20d 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -50,39 +50,39 @@ int board_ddr_power_init(void) return 0; /* VTT = Set LDO3 to sync mode */ - ret = pmic_reg_read(dev, STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3)); + ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); if (ret < 0) return ret; ret &= ~STPMIC1_LDO3_MODE; - ret &= ~STPMIC1_LDO12356_OUTPUT_MASK; - ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_OUTPUT_SHIFT; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL); - ret = pmic_reg_write(dev, STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3), + ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), ret); if (ret < 0) return ret; /* VDD_DDR = Set BUCK2 to 1.35V */ ret = pmic_clrsetbits(dev, - STPMIC1_BUCKX_CTRL_REG(STPMIC1_BUCK2), - STPMIC1_BUCK_OUTPUT_MASK, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_VOUT_MASK, STPMIC1_BUCK2_1350000V); if (ret < 0) return ret; /* Enable VDD_DDR = BUCK2 */ ret = pmic_clrsetbits(dev, - STPMIC1_BUCKX_CTRL_REG(STPMIC1_BUCK2), - STPMIC1_BUCK_EN, STPMIC1_BUCK_EN); + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); if (ret < 0) return ret; mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); /* Enable VREF */ - ret = pmic_clrsetbits(dev, STPMIC1_VREF_CTRL_REG, - STPMIC1_VREF_EN, STPMIC1_VREF_EN); + ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); if (ret < 0) return ret; @@ -90,8 +90,8 @@ int board_ddr_power_init(void) /* Enable LDO3 */ ret = pmic_clrsetbits(dev, - STPMIC1_LDOX_CTRL_REG(STPMIC1_LDO3), - STPMIC1_LDO_EN, STPMIC1_LDO_EN); + STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); if (ret < 0) return ret; diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index 546a92325c..a7844f244b 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -25,8 +25,8 @@ void spl_board_init(void) DM_GET_DRIVER(pmic_stpmic1), &dev); if (!ret) pmic_clrsetbits(dev, - STPMIC1_MASK_RESET_BUCK, - STPMIC1_MASK_RESET_BUCK3, - STPMIC1_MASK_RESET_BUCK3); + STPMIC1_BUCKS_MRST_CR, + STPMIC1_MRST_BUCK(STPMIC1_BUCK3), + STPMIC1_MRST_BUCK(STPMIC1_BUCK3)); #endif } diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c index 860258388e..50ef2a21d1 100644 --- a/drivers/power/regulator/stpmic1.c +++ b/drivers/power/regulator/stpmic1.c @@ -132,20 +132,20 @@ static const struct stpmic1_output buck_voltage_range[] = { /* BUCK modes */ static const struct dm_regulator_mode buck_modes[] = { - STPMIC1_MODE(STPMIC1_BUCK_MODE_HP, STPMIC1_BUCK_MODE_HP, "HP"), - STPMIC1_MODE(STPMIC1_BUCK_MODE_LP, STPMIC1_BUCK_MODE_LP, "LP"), + STPMIC1_MODE(STPMIC1_PREG_MODE_HP, STPMIC1_PREG_MODE_HP, "HP"), + STPMIC1_MODE(STPMIC1_PREG_MODE_LP, STPMIC1_PREG_MODE_LP, "LP"), }; static int stpmic1_buck_get_uv(struct udevice *dev, int buck) { int sel; - sel = pmic_reg_read(dev, STPMIC1_BUCKX_CTRL_REG(buck)); + sel = pmic_reg_read(dev, STPMIC1_BUCKX_MAIN_CR(buck)); if (sel < 0) return sel; - sel &= STPMIC1_BUCK_OUTPUT_MASK; - sel >>= STPMIC1_BUCK_OUTPUT_SHIFT; + sel &= STPMIC1_BUCK_VOUT_MASK; + sel >>= STPMIC1_BUCK_VOUT_SHIFT; return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]); } @@ -164,9 +164,9 @@ static int stpmic1_buck_set_value(struct udevice *dev, int uv) return sel; return pmic_clrsetbits(dev->parent, - STPMIC1_BUCKX_CTRL_REG(buck), - STPMIC1_BUCK_OUTPUT_MASK, - sel << STPMIC1_BUCK_OUTPUT_SHIFT); + STPMIC1_BUCKX_MAIN_CR(buck), + STPMIC1_BUCK_VOUT_MASK, + sel << STPMIC1_BUCK_VOUT_SHIFT); } static int stpmic1_buck_get_enable(struct udevice *dev) @@ -174,11 +174,11 @@ static int stpmic1_buck_get_enable(struct udevice *dev) int ret; ret = pmic_reg_read(dev->parent, - STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1)); if (ret < 0) return false; - return ret & STPMIC1_BUCK_EN ? true : false; + return ret & STPMIC1_BUCK_ENA ? true : false; } static int stpmic1_buck_set_enable(struct udevice *dev, bool enable) @@ -200,8 +200,8 @@ static int stpmic1_buck_set_enable(struct udevice *dev, bool enable) } ret = pmic_clrsetbits(dev->parent, - STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMIC1_BUCK_EN, enable ? STPMIC1_BUCK_EN : 0); + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1), + STPMIC1_BUCK_ENA, enable ? STPMIC1_BUCK_ENA : 0); mdelay(delay); return ret; @@ -212,20 +212,20 @@ static int stpmic1_buck_get_mode(struct udevice *dev) int ret; ret = pmic_reg_read(dev->parent, - STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1)); if (ret < 0) return ret; - return ret & STPMIC1_BUCK_MODE ? STPMIC1_BUCK_MODE_LP : - STPMIC1_BUCK_MODE_HP; + return ret & STPMIC1_BUCK_PREG_MODE ? STPMIC1_PREG_MODE_LP : + STPMIC1_PREG_MODE_HP; } static int stpmic1_buck_set_mode(struct udevice *dev, int mode) { return pmic_clrsetbits(dev->parent, - STPMIC1_BUCKX_CTRL_REG(dev->driver_data - 1), - STPMIC1_BUCK_MODE, - mode ? STPMIC1_BUCK_MODE : 0); + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1), + STPMIC1_BUCK_PREG_MODE, + mode ? STPMIC1_BUCK_PREG_MODE : 0); } static int stpmic1_buck_probe(struct udevice *dev) @@ -312,7 +312,7 @@ static int stpmic1_ldo_get_value(struct udevice *dev) { int sel, ldo = dev->driver_data - 1; - sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); + sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo)); if (sel < 0) return sel; @@ -320,8 +320,8 @@ static int stpmic1_ldo_get_value(struct udevice *dev) if (ldo == STPMIC1_LDO4) return STPMIC1_LDO4_UV; - sel &= STPMIC1_LDO12356_OUTPUT_MASK; - sel >>= STPMIC1_LDO12356_OUTPUT_SHIFT; + sel &= STPMIC1_LDO12356_VOUT_MASK; + sel >>= STPMIC1_LDO12356_VOUT_SHIFT; /* ldo3, sel = 31 => BUCK2/2 */ if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL) @@ -343,9 +343,9 @@ static int stpmic1_ldo_set_value(struct udevice *dev, int uv) return sel; return pmic_clrsetbits(dev->parent, - STPMIC1_LDOX_CTRL_REG(ldo), - STPMIC1_LDO12356_OUTPUT_MASK, - sel << STPMIC1_LDO12356_OUTPUT_SHIFT); + STPMIC1_LDOX_MAIN_CR(ldo), + STPMIC1_LDO12356_VOUT_MASK, + sel << STPMIC1_LDO12356_VOUT_SHIFT); } static int stpmic1_ldo_get_enable(struct udevice *dev) @@ -353,11 +353,11 @@ static int stpmic1_ldo_get_enable(struct udevice *dev) int ret; ret = pmic_reg_read(dev->parent, - STPMIC1_LDOX_CTRL_REG(dev->driver_data - 1)); + STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1)); if (ret < 0) return false; - return ret & STPMIC1_LDO_EN ? true : false; + return ret & STPMIC1_LDO_ENA ? true : false; } static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable) @@ -379,8 +379,8 @@ static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable) } ret = pmic_clrsetbits(dev->parent, - STPMIC1_LDOX_CTRL_REG(dev->driver_data - 1), - STPMIC1_LDO_EN, enable ? STPMIC1_LDO_EN : 0); + STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1), + STPMIC1_LDO_ENA, enable ? STPMIC1_LDO_ENA : 0); mdelay(delay); return ret; @@ -393,15 +393,15 @@ static int stpmic1_ldo_get_mode(struct udevice *dev) if (ldo != STPMIC1_LDO3) return -EINVAL; - ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); + ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo)); if (ret < 0) return ret; if (ret & STPMIC1_LDO3_MODE) return STPMIC1_LDO_MODE_BYPASS; - ret &= STPMIC1_LDO12356_OUTPUT_MASK; - ret >>= STPMIC1_LDO12356_OUTPUT_SHIFT; + ret &= STPMIC1_LDO12356_VOUT_MASK; + ret >>= STPMIC1_LDO12356_VOUT_SHIFT; return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE : STPMIC1_LDO_MODE_NORMAL; @@ -414,14 +414,14 @@ static int stpmic1_ldo_set_mode(struct udevice *dev, int mode) if (ldo != STPMIC1_LDO3) return -EINVAL; - ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo)); + ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo)); if (ret < 0) return ret; switch (mode) { case STPMIC1_LDO_MODE_SINK_SOURCE: - ret &= ~STPMIC1_LDO12356_OUTPUT_MASK; - ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_OUTPUT_SHIFT; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT; case STPMIC1_LDO_MODE_NORMAL: ret &= ~STPMIC1_LDO3_MODE; break; @@ -430,7 +430,7 @@ static int stpmic1_ldo_set_mode(struct udevice *dev, int mode) break; } - return pmic_reg_write(dev->parent, STPMIC1_LDOX_CTRL_REG(ldo), ret); + return pmic_reg_write(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo), ret); } static int stpmic1_ldo_probe(struct udevice *dev) @@ -483,11 +483,11 @@ static int stpmic1_vref_ddr_get_enable(struct udevice *dev) { int ret; - ret = pmic_reg_read(dev->parent, STPMIC1_VREF_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_REFDDR_MAIN_CR); if (ret < 0) return false; - return ret & STPMIC1_VREF_EN ? true : false; + return ret & STPMIC1_VREF_ENA ? true : false; } static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable) @@ -500,8 +500,8 @@ static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable) if (stpmic1_vref_ddr_get_enable(dev) == enable) return 0; - ret = pmic_clrsetbits(dev->parent, STPMIC1_VREF_CTRL_REG, - STPMIC1_VREF_EN, enable ? STPMIC1_VREF_EN : 0); + ret = pmic_clrsetbits(dev->parent, STPMIC1_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, enable ? STPMIC1_VREF_ENA : 0); mdelay(delay); return ret; @@ -540,31 +540,31 @@ static int stpmic1_boost_get_enable(struct udevice *dev) { int ret; - ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); if (ret < 0) return false; - return ret & STPMIC1_USB_BOOST_EN ? true : false; + return ret & STPMIC1_BST_ON ? true : false; } static int stpmic1_boost_set_enable(struct udevice *dev, bool enable) { int ret; - ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); if (ret < 0) return ret; - if (!enable && ret & STPMIC1_USB_PWR_SW_EN) + if (!enable && ret & STPMIC1_PWR_SW_ON) return -EINVAL; /* if regulator is already in the wanted state, nothing to do */ - if (!!(ret & STPMIC1_USB_BOOST_EN) == enable) + if (!!(ret & STPMIC1_BST_ON) == enable) return 0; - ret = pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, - STPMIC1_USB_BOOST_EN, - enable ? STPMIC1_USB_BOOST_EN : 0); + ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR, + STPMIC1_BST_ON, + enable ? STPMIC1_BST_ON : 0); if (enable) mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS); @@ -604,7 +604,7 @@ static int stpmic1_pwr_sw_get_enable(struct udevice *dev) uint mask = 1 << dev->driver_data; int ret; - ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); if (ret < 0) return false; @@ -618,7 +618,7 @@ static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable) STPMIC1_DEFAULT_STOP_DELAY_MS; int ret; - ret = pmic_reg_read(dev->parent, STPMIC1_USB_CTRL_REG); + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); if (ret < 0) return ret; @@ -627,17 +627,17 @@ static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable) return 0; /* Boost management */ - if (enable && !(ret & STPMIC1_USB_BOOST_EN)) { - pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, - STPMIC1_USB_BOOST_EN, STPMIC1_USB_BOOST_EN); + if (enable && !(ret & STPMIC1_BST_ON)) { + pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR, + STPMIC1_BST_ON, STPMIC1_BST_ON); mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS); - } else if (!enable && ret & STPMIC1_USB_BOOST_EN && - (ret & STPMIC1_USB_PWR_SW_EN) != STPMIC1_USB_PWR_SW_EN) { - pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, - STPMIC1_USB_BOOST_EN, 0); + } else if (!enable && ret & STPMIC1_BST_ON && + (ret & STPMIC1_PWR_SW_ON) != STPMIC1_PWR_SW_ON) { + pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR, + STPMIC1_BST_ON, 0); } - ret = pmic_clrsetbits(dev->parent, STPMIC1_USB_CTRL_REG, + ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR, mask, enable ? mask : 0); mdelay(delay); diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h index 5ed67d29cf..ea91b75cfd 100644 --- a/include/power/stpmic1.h +++ b/include/power/stpmic1.h @@ -6,51 +6,69 @@ #ifndef __PMIC_STPMIC1_H_ #define __PMIC_STPMIC1_H_ -#define STPMIC1_MAIN_CONTROL_REG 0x10 -#define STPMIC1_MASK_RESET_BUCK 0x18 -#define STPMIC1_MASK_RESET_LDOS 0x1a -#define STPMIC1_BUCKX_CTRL_REG(buck) (0x20 + (buck)) -#define STPMIC1_VREF_CTRL_REG 0x24 -#define STPMIC1_LDOX_CTRL_REG(ldo) (0x25 + (ldo)) -#define STPMIC1_USB_CTRL_REG 0x40 -#define STPMIC1_NVM_USER_STATUS_REG 0xb8 -#define STPMIC1_NVM_USER_CONTROL_REG 0xb9 - -/* Main PMIC Control Register (MAIN_CONTROL_REG) */ -#define STPMIC1_CTRL_SWITCH_OFF BIT(0) -#define STPMIC1_CTRL_RESTART BIT(1) - -#define STPMIC1_MASK_RESET_BUCK3 BIT(2) -#define STPMIC1_MASK_RESET_BUCK_DBG GENMASK(3, 0) -#define STPMIC1_MASK_RESET_LDOS_DBG 0x6F - -#define STPMIC1_BUCK_EN BIT(0) -#define STPMIC1_BUCK_MODE BIT(1) -#define STPMIC1_BUCK_OUTPUT_MASK GENMASK(7, 2) -#define STPMIC1_BUCK_OUTPUT_SHIFT 2 -#define STPMIC1_BUCK2_1200000V (24 << STPMIC1_BUCK_OUTPUT_SHIFT) -#define STPMIC1_BUCK2_1350000V (30 << STPMIC1_BUCK_OUTPUT_SHIFT) -#define STPMIC1_BUCK3_1800000V (39 << STPMIC1_BUCK_OUTPUT_SHIFT) - -#define STPMIC1_VREF_EN BIT(0) - -#define STPMIC1_LDO_EN BIT(0) -#define STPMIC1_LDO12356_OUTPUT_MASK GENMASK(6, 2) -#define STPMIC1_LDO12356_OUTPUT_SHIFT 2 +#define STPMIC1_MAIN_CR 0x10 +#define STPMIC1_BUCKS_MRST_CR 0x18 +#define STPMIC1_LDOS_MRST_CR 0x1a +#define STPMIC1_BUCKX_MAIN_CR(buck) (0x20 + (buck)) +#define STPMIC1_REFDDR_MAIN_CR 0x24 +#define STPMIC1_LDOX_MAIN_CR(ldo) (0x25 + (ldo)) +#define STPMIC1_BST_SW_CR 0x40 +#define STPMIC1_NVM_SR 0xb8 +#define STPMIC1_NVM_CR 0xb9 + +/* Main PMIC Control Register (MAIN_CR) */ +#define STPMIC1_SWOFF BIT(0) +#define STPMIC1_RREQ_EN BIT(1) + +/* BUCKS_MRST_CR */ +#define STPMIC1_MRST_BUCK(buck) BIT(buck) +#define STPMIC1_MRST_BUCK_ALL GENMASK(3, 0) + +/* LDOS_MRST_CR */ +#define STPMIC1_MRST_LDO(ldo) BIT(ldo) +#define STPMIC1_MRST_LDO_ALL GENMASK(6, 0) + +/* BUCKx_MAIN_CR (x=1...4) */ +#define STPMIC1_BUCK_ENA BIT(0) +#define STPMIC1_BUCK_PREG_MODE BIT(1) +#define STPMIC1_BUCK_VOUT_MASK GENMASK(7, 2) +#define STPMIC1_BUCK_VOUT_SHIFT 2 +#define STPMIC1_BUCK_VOUT(sel) (sel << STPMIC1_BUCK_VOUT_SHIFT) + +#define STPMIC1_BUCK2_1200000V STPMIC1_BUCK_VOUT(24) +#define STPMIC1_BUCK2_1350000V STPMIC1_BUCK_VOUT(30) + +#define STPMIC1_BUCK3_1800000V STPMIC1_BUCK_VOUT(39) + +/* REFDDR_MAIN_CR */ +#define STPMIC1_VREF_ENA BIT(0) + +/* LDOX_MAIN_CR */ +#define STPMIC1_LDO_ENA BIT(0) +#define STPMIC1_LDO12356_VOUT_MASK GENMASK(6, 2) +#define STPMIC1_LDO12356_VOUT_SHIFT 2 +#define STPMIC1_LDO_VOUT(sel) (sel << STPMIC1_LDO12356_VOUT_SHIFT) + #define STPMIC1_LDO3_MODE BIT(7) #define STPMIC1_LDO3_DDR_SEL 31 -#define STPMIC1_LDO3_1800000 (9 << STPMIC1_LDO12356_OUTPUT_SHIFT) +#define STPMIC1_LDO3_1800000 STPMIC1_LDO_VOUT(9) + #define STPMIC1_LDO4_UV 3300000 -#define STPMIC1_USB_BOOST_EN BIT(0) -#define STPMIC1_USB_PWR_SW_EN GENMASK(2, 1) +/* BST_SW_CR */ +#define STPMIC1_BST_ON BIT(0) +#define STPMIC1_VBUSOTG_ON BIT(1) +#define STPMIC1_SWOUT_ON BIT(2) +#define STPMIC1_PWR_SW_ON (STPMIC1_VBUSOTG_ON | STPMIC1_SWOUT_ON) -#define STPMIC1_NVM_USER_CONTROL_PROGRAM BIT(0) -#define STPMIC1_NVM_USER_CONTROL_READ BIT(1) +/* NVM_SR */ +#define STPMIC1_NVM_BUSY BIT(0) -#define STPMIC1_NVM_USER_STATUS_BUSY BIT(0) -#define STPMIC1_NVM_USER_STATUS_ERROR BIT(1) +/* NVM_CR */ +#define STPMIC1_NVM_CMD_PROGRAM 1 +#define STPMIC1_NVM_CMD_READ 2 +/* Timeout */ #define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 #define STPMIC1_DEFAULT_STOP_DELAY_MS 5 #define STPMIC1_USB_BOOST_START_UP_DELAY_MS 10 @@ -64,8 +82,8 @@ enum { }; enum { - STPMIC1_BUCK_MODE_HP, - STPMIC1_BUCK_MODE_LP, + STPMIC1_PREG_MODE_HP, + STPMIC1_PREG_MODE_LP, }; enum { -- cgit From 8811583e0413c8c00116e87113c359bdc4b582b4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:19 +0100 Subject: pmic: stpmu1: add power switch off support Add sysreset support, and support power switch off request, needed by poweroff command. Signed-off-by: Patrick Delaunay --- drivers/power/pmic/stpmic1.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index 25450ebd42..c962160307 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include @@ -72,6 +75,10 @@ static int stpmic1_bind(struct udevice *dev) dev_dbg(dev, "no child found\n"); #endif /* DM_REGULATOR */ + if (CONFIG_IS_ENABLED(SYSRESET)) + return device_bind_driver(dev, "stpmic1-sysreset", + "stpmic1-sysreset", NULL); + return 0; } @@ -93,3 +100,42 @@ U_BOOT_DRIVER(pmic_stpmic1) = { .bind = stpmic1_bind, .ops = &stpmic1_ops, }; + +#ifdef CONFIG_SYSRESET +static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct udevice *pmic_dev; + int ret; + + if (type != SYSRESET_POWER) + return -EPROTONOSUPPORT; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmic1), + &pmic_dev); + + if (ret) + return -EOPNOTSUPP; + + ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR); + if (ret < 0) + return ret; + + ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, + ret | STPMIC1_SWOFF | STPMIC1_RREQ_EN); + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static struct sysreset_ops stpmic1_sysreset_ops = { + .request = stpmic1_sysreset_request, +}; + +U_BOOT_DRIVER(stpmic1_sysreset) = { + .name = "stpmic1-sysreset", + .id = UCLASS_SYSRESET, + .ops = &stpmic1_sysreset_ops, +}; +#endif -- cgit From c16cc4f689060f4ef06382b6408b86619f5efb7a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 12 Apr 2019 11:55:46 +0200 Subject: stm32mp1: add command poweroff Activate the command poweroff by default for STM32MP1: - with PCSI from TF-A for trusted boot - with PMIC sysreset request for basic boot (SYSRESET_POWER) Signed-off-by: Patrick Delaunay --- arch/arm/Kconfig | 1 + arch/arm/mach-stm32mp/Makefile | 3 +++ arch/arm/mach-stm32mp/cmd_poweroff.c | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 arch/arm/mach-stm32mp/cmd_poweroff.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 33628b86d4..28d4d35968 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1403,6 +1403,7 @@ config ARCH_STM32MP select SYSRESET select SYS_THUMB_BUILD imply CMD_DM + imply CMD_POWEROFF imply ENV_VARS_UBOOT_RUNTIME_CONFIG help Support for STM32MP SoC family developed by STMicroelectronics, diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index f59ced5ee1..1493914a11 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -11,6 +11,9 @@ ifdef CONFIG_SPL_BUILD obj-y += spl.o else obj-y += bsec.o +ifndef CONFIG_STM32MP1_TRUSTED +obj-$(CONFIG_SYSRESET) += cmd_poweroff.o +endif endif obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o diff --git a/arch/arm/mach-stm32mp/cmd_poweroff.c b/arch/arm/mach-stm32mp/cmd_poweroff.c new file mode 100644 index 0000000000..f54dd1daf2 --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_poweroff.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include + +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret; + + puts("poweroff ...\n"); + mdelay(100); + + ret = sysreset_walk(SYSRESET_POWER); + + if (ret == -EINPROGRESS) + mdelay(1000); + + /*NOTREACHED when power off*/ + return CMD_RET_FAILURE; +} -- cgit From c8a6668cbdc0644330135b7016ffa3ea74895e64 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:21 +0100 Subject: stm32mp1: dts: activate psci-1.0 Updates the stm32mp157c devicetree to bind the U-Boot PSCI driver need for power off command; TF-A for stm32mp15x supports PSCI 1.0. Signed-off-by: Patrick Delaunay --- arch/arm/dts/stm32mp157c.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 50978efc7c..d662013243 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -29,7 +29,7 @@ }; psci { - compatible = "arm,psci"; + compatible = "arm,psci-1.0"; method = "smc"; cpu_off = <0x84000002>; cpu_on = <0x84000003>; -- cgit From 31e45a1a9ea07a9c36ada6401e4631a765398c75 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:26:22 +0100 Subject: stpmic1: add NVM update support in fuse command Add functions to read/update the non volatile memory of STPMIC1 (8 bytes-register at 0xF8 address) and allow access with fuse command (bank=1, word > 0xF8). For example: STM32MP> fuse read 1 0xf8 8 Reading bank 1: Word 0x000000f8: 000000ee 00000092 000000c0 00000002 Word 0x000000fc: 000000f2 00000080 00000002 00000033 Signed-off-by: Patrick Delaunay --- drivers/misc/stm32mp_fuse.c | 28 +++++++++++ drivers/power/pmic/stpmic1.c | 114 +++++++++++++++++++++++++++++++++++++++++++ include/power/stpmic1.h | 7 +++ 3 files changed, 149 insertions(+) diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 33943a231b..8dc246b0db 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -9,8 +9,10 @@ #include #include #include +#include #define STM32MP_OTP_BANK 0 +#define STM32MP_NVM_BANK 1 /* * The 'fuse' command API @@ -34,6 +36,13 @@ int fuse_read(u32 bank, u32 word, u32 *val) ret = 0; break; +#ifdef CONFIG_PMIC_STPMIC1 + case STM32MP_NVM_BANK: + *val = 0; + ret = stpmic1_shadow_read_byte(word, (u8 *)val); + break; +#endif /* CONFIG_PMIC_STPMIC1 */ + default: printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); ret = -EINVAL; @@ -62,6 +71,12 @@ int fuse_prog(u32 bank, u32 word, u32 val) ret = 0; break; +#ifdef CONFIG_PMIC_STPMIC1 + case STM32MP_NVM_BANK: + ret = stpmic1_nvm_write_byte(word, (u8 *)&val); + break; +#endif /* CONFIG_PMIC_STPMIC1 */ + default: printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); ret = -EINVAL; @@ -89,6 +104,13 @@ int fuse_sense(u32 bank, u32 word, u32 *val) ret = 0; break; +#ifdef CONFIG_PMIC_STPMIC1 + case STM32MP_NVM_BANK: + *val = 0; + ret = stpmic1_nvm_read_byte(word, (u8 *)val); + break; +#endif /* CONFIG_PMIC_STPMIC1 */ + default: printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); ret = -EINVAL; @@ -117,6 +139,12 @@ int fuse_override(u32 bank, u32 word, u32 val) ret = 0; break; +#ifdef CONFIG_PMIC_STPMIC1 + case STM32MP_NVM_BANK: + ret = stpmic1_shadow_write_byte(word, (u8 *)&val); + break; +#endif /* CONFIG_PMIC_STPMIC1 */ + default: printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index c962160307..65296c5fc3 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -15,6 +15,17 @@ #define STPMIC1_NUM_OF_REGS 0x100 +#define STPMIC1_NVM_SIZE 8 +#define STPMIC1_NVM_POLL_TIMEOUT 100000 +#define STPMIC1_NVM_START_ADDRESS 0xf8 + +enum pmic_nvm_op { + SHADOW_READ, + SHADOW_WRITE, + NVM_READ, + NVM_WRITE, +}; + #if CONFIG_IS_ENABLED(DM_REGULATOR) static const struct pmic_child_info stpmic1_children_info[] = { { .prefix = "ldo", .driver = "stpmic1_ldo" }, @@ -101,6 +112,109 @@ U_BOOT_DRIVER(pmic_stpmic1) = { .ops = &stpmic1_ops, }; +#ifndef CONFIG_SPL_BUILD +static int stpmic1_nvm_rw(u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op) +{ + struct udevice *dev; + unsigned long timeout; + u8 cmd = STPMIC1_NVM_CMD_READ; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmic1), &dev); + if (ret) + /* No PMIC on power discrete board */ + return -EOPNOTSUPP; + + if (addr < STPMIC1_NVM_START_ADDRESS) + return -EACCES; + + if (op == SHADOW_READ) + return pmic_read(dev, addr, buf, buf_len); + + if (op == SHADOW_WRITE) + return pmic_write(dev, addr, buf, buf_len); + + if (op == NVM_WRITE) { + cmd = STPMIC1_NVM_CMD_PROGRAM; + + ret = pmic_write(dev, addr, buf, buf_len); + if (ret < 0) + return ret; + } + + ret = pmic_reg_read(dev, STPMIC1_NVM_CR); + if (ret < 0) + return ret; + + ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd); + if (ret < 0) + return ret; + + timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT; + for (;;) { + ret = pmic_reg_read(dev, STPMIC1_NVM_SR); + if (ret < 0) + return ret; + + if (!(ret & STPMIC1_NVM_BUSY)) + break; + + if (time_after(timer_get_us(), timeout)) + break; + } + + if (ret & STPMIC1_NVM_BUSY) + return -ETIMEDOUT; + + if (op == NVM_READ) { + ret = pmic_read(dev, addr, buf, buf_len); + if (ret < 0) + return ret; + } + + return 0; +} + +int stpmic1_shadow_read_byte(u8 addr, u8 *buf) +{ + return stpmic1_nvm_rw(addr, buf, 1, SHADOW_READ); +} + +int stpmic1_shadow_write_byte(u8 addr, u8 *buf) +{ + return stpmic1_nvm_rw(addr, buf, 1, SHADOW_WRITE); +} + +int stpmic1_nvm_read_byte(u8 addr, u8 *buf) +{ + return stpmic1_nvm_rw(addr, buf, 1, NVM_READ); +} + +int stpmic1_nvm_write_byte(u8 addr, u8 *buf) +{ + return stpmic1_nvm_rw(addr, buf, 1, NVM_WRITE); +} + +int stpmic1_nvm_read_all(u8 *buf, int buf_len) +{ + if (buf_len != STPMIC1_NVM_SIZE) + return -EINVAL; + + return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS, + buf, buf_len, NVM_READ); +} + +int stpmic1_nvm_write_all(u8 *buf, int buf_len) +{ + if (buf_len != STPMIC1_NVM_SIZE) + return -EINVAL; + + return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS, + buf, buf_len, NVM_WRITE); +} +#endif /* CONFIG_SPL_BUILD */ + #ifdef CONFIG_SYSRESET static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) { diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h index ea91b75cfd..0e6721d852 100644 --- a/include/power/stpmic1.h +++ b/include/power/stpmic1.h @@ -107,4 +107,11 @@ enum { STPMIC1_PWR_SW2, STPMIC1_MAX_PWR_SW, }; + +int stpmic1_shadow_read_byte(u8 addr, u8 *buf); +int stpmic1_shadow_write_byte(u8 addr, u8 *buf); +int stpmic1_nvm_read_byte(u8 addr, u8 *buf); +int stpmic1_nvm_write_byte(u8 addr, u8 *buf); +int stpmic1_nvm_read_all(u8 *buf, int buf_len); +int stpmic1_nvm_write_all(u8 *buf, int buf_len); #endif -- cgit From 2366160eb27be6923cd1630c817aac299dce23c3 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Feb 2019 16:50:38 +0100 Subject: ARM: dts: stm32: Synchronize DT with kernel one This patch synchronizes U-boot DT with kernel one This is based on https://patchwork.kernel.org/cover/10797115/ This patch adds initial support of STM32MP157 discovery boards: - Add support of stm32mp157a discovery1 board (part number: STM32MP157A-DK1). This board embeds a STM32MP157a SOC with AC package (TFBGA361, 148 ios) and 512MB of DDR3. Several connections are available on this boards: 4*USB2.0, 1*USB2.0 typeC, SDcard, RJ45, HDMI, Arduino connector, ... - Add support of stm32mp157c discovery2 board (part number: STM32MP157C-DK2). This board is a "super-set" of stm32mp157a-dk1. A display panel (otm8009a) and Murata wifi/BT combo is added. Signed-off-by: Alexandre Torgue Signed-off-by: Patrice Chotard --- arch/arm/dts/Makefile | 2 + arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 120 ++++++++++ arch/arm/dts/stm32mp157-pinctrl.dtsi | 74 +++++++ arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 178 +++++++++++++++ arch/arm/dts/stm32mp157a-dk1.dts | 262 ++++++++++++++++++++++ arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 6 + arch/arm/dts/stm32mp157c-dk2.dts | 67 ++++++ arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 35 ++- arch/arm/dts/stm32mp157c-ed1.dts | 47 ++-- arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi | 19 +- arch/arm/dts/stm32mp157c-ev1.dts | 100 +++++++++ arch/arm/dts/stm32mp157c.dtsi | 270 +++++++++++++++++++++-- 12 files changed, 1108 insertions(+), 72 deletions(-) create mode 100644 arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi create mode 100644 arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi create mode 100644 arch/arm/dts/stm32mp157a-dk1.dts create mode 100644 arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi create mode 100644 arch/arm/dts/stm32mp157c-dk2.dts diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 930b7e03db..0e81b9b6eb 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -684,6 +684,8 @@ dtb-$(CONFIG_ARCH_ASPEED) += ast2500-evb.dtb dtb-$(CONFIG_ARCH_STI) += stih410-b2260.dtb dtb-$(CONFIG_TARGET_STM32MP1) += \ + stm32mp157a-dk1.dtb \ + stm32mp157c-dk2.dtb \ stm32mp157c-ed1.dtb \ stm32mp157c-ev1.dtb diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi new file mode 100644 index 0000000000..7d9b95ccf1 --- /dev/null +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * STM32MP157C DK1/DK2 BOARD configuration + * 1x DDR3L 4Gb, 16-bit, 533MHz. + * Reference used NT5CC256M16DP-DI from NANYA + * + * DDR type / Platform DDR3/3L + * freq 533MHz + * width 16 + * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G + * DDR density 4 + * timing mode optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC + * Tc > + 85C : N + */ +#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.43" +#define DDR_MEM_SPEED 533 +#define DDR_MEM_SIZE 0x20000000 + +#define DDR_MSTR 0x00041401 +#define DDR_MRCTRL0 0x00000010 +#define DDR_MRCTRL1 0x00000000 +#define DDR_DERATEEN 0x00000000 +#define DDR_DERATEINT 0x00800000 +#define DDR_PWRCTL 0x00000000 +#define DDR_PWRTMG 0x00400010 +#define DDR_HWLPCTL 0x00000000 +#define DDR_RFSHCTL0 0x00210000 +#define DDR_RFSHCTL3 0x00000000 +#define DDR_RFSHTMG 0x0081008B +#define DDR_CRCPARCTL0 0x00000000 +#define DDR_DRAMTMG0 0x121B2414 +#define DDR_DRAMTMG1 0x000A041C +#define DDR_DRAMTMG2 0x0608090F +#define DDR_DRAMTMG3 0x0050400C +#define DDR_DRAMTMG4 0x08040608 +#define DDR_DRAMTMG5 0x06060403 +#define DDR_DRAMTMG6 0x02020002 +#define DDR_DRAMTMG7 0x00000202 +#define DDR_DRAMTMG8 0x00001005 +#define DDR_DRAMTMG14 0x000000A0 +#define DDR_ZQCTL0 0xC2000040 +#define DDR_DFITMG0 0x02060105 +#define DDR_DFITMG1 0x00000202 +#define DDR_DFILPCFG0 0x07000000 +#define DDR_DFIUPD0 0xC0400003 +#define DDR_DFIUPD1 0x00000000 +#define DDR_DFIUPD2 0x00000000 +#define DDR_DFIPHYMSTR 0x00000000 +#define DDR_ADDRMAP1 0x00070707 +#define DDR_ADDRMAP2 0x00000000 +#define DDR_ADDRMAP3 0x1F000000 +#define DDR_ADDRMAP4 0x00001F1F +#define DDR_ADDRMAP5 0x06060606 +#define DDR_ADDRMAP6 0x0F060606 +#define DDR_ADDRMAP9 0x00000000 +#define DDR_ADDRMAP10 0x00000000 +#define DDR_ADDRMAP11 0x00000000 +#define DDR_ODTCFG 0x06000600 +#define DDR_ODTMAP 0x00000001 +#define DDR_SCHED 0x00000C01 +#define DDR_SCHED1 0x00000000 +#define DDR_PERFHPR1 0x01000001 +#define DDR_PERFLPR1 0x08000200 +#define DDR_PERFWR1 0x08000400 +#define DDR_DBG0 0x00000000 +#define DDR_DBG1 0x00000000 +#define DDR_DBGCMD 0x00000000 +#define DDR_POISONCFG 0x00000000 +#define DDR_PCCFG 0x00000010 +#define DDR_PCFGR_0 0x00010000 +#define DDR_PCFGW_0 0x00000000 +#define DDR_PCFGQOS0_0 0x02100C03 +#define DDR_PCFGQOS1_0 0x00800100 +#define DDR_PCFGWQOS0_0 0x01100C03 +#define DDR_PCFGWQOS1_0 0x01000200 +#define DDR_PCFGR_1 0x00010000 +#define DDR_PCFGW_1 0x00000000 +#define DDR_PCFGQOS0_1 0x02100C03 +#define DDR_PCFGQOS1_1 0x00800040 +#define DDR_PCFGWQOS0_1 0x01100C03 +#define DDR_PCFGWQOS1_1 0x01000200 +#define DDR_PGCR 0x01442E02 +#define DDR_PTR0 0x0022AA5B +#define DDR_PTR1 0x04841104 +#define DDR_PTR2 0x042DA068 +#define DDR_ACIOCR 0x10400812 +#define DDR_DXCCR 0x00000C40 +#define DDR_DSGCR 0xF200001F +#define DDR_DCR 0x0000000B +#define DDR_DTPR0 0x38D488D0 +#define DDR_DTPR1 0x098B00D8 +#define DDR_DTPR2 0x10023600 +#define DDR_MR0 0x00000840 +#define DDR_MR1 0x00000000 +#define DDR_MR2 0x00000208 +#define DDR_MR3 0x00000000 +#define DDR_ODTCR 0x00010000 +#define DDR_ZQ0CR1 0x00000038 +#define DDR_DX0GCR 0x0000CE81 +#define DDR_DX0DLLCR 0x40000000 +#define DDR_DX0DQTR 0xFFFFFFFF +#define DDR_DX0DQSTR 0x3DB02000 +#define DDR_DX1GCR 0x0000CE81 +#define DDR_DX1DLLCR 0x40000000 +#define DDR_DX1DQTR 0xFFFFFFFF +#define DDR_DX1DQSTR 0x3DB02000 +#define DDR_DX2GCR 0x0000CE81 +#define DDR_DX2DLLCR 0x40000000 +#define DDR_DX2DQTR 0xFFFFFFFF +#define DDR_DX2DQSTR 0x3DB02000 +#define DDR_DX3GCR 0x0000CE81 +#define DDR_DX3DLLCR 0x40000000 +#define DDR_DX3DQTR 0xFFFFFFFF +#define DDR_DX3DQSTR 0x3DB02000 + +#include "stm32mp15-ddr.dtsi" diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 85da592655..4d2bf33be7 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -157,6 +157,52 @@ }; }; + ethernet0_rgmii_pins_a: rgmii-0 { + pins1 { + pinmux = , /* ETH_RGMII_CLK125 */ + , /* ETH_RGMII_GTX_CLK */ + , /* ETH_RGMII_TXD0 */ + , /* ETH_RGMII_TXD1 */ + , /* ETH_RGMII_TXD2 */ + , /* ETH_RGMII_TXD3 */ + , /* ETH_RGMII_TX_CTL */ + , /* ETH_MDIO */ + ; /* ETH_MDC */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + pins2 { + pinmux = , /* ETH_RGMII_RXD0 */ + , /* ETH_RGMII_RXD1 */ + , /* ETH_RGMII_RXD2 */ + , /* ETH_RGMII_RXD3 */ + , /* ETH_RGMII_RX_CLK */ + ; /* ETH_RGMII_RX_CTL */ + bias-disable; + }; + }; + + ethernet0_rgmii_pins_sleep_a: rgmii-sleep-0 { + pins1 { + pinmux = , /* ETH_RGMII_CLK125 */ + , /* ETH_RGMII_GTX_CLK */ + , /* ETH_RGMII_TXD0 */ + , /* ETH_RGMII_TXD1 */ + , /* ETH_RGMII_TXD2 */ + , /* ETH_RGMII_TXD3 */ + , /* ETH_RGMII_TX_CTL */ + , /* ETH_MDIO */ + , /* ETH_MDC */ + , /* ETH_RGMII_RXD0 */ + , /* ETH_RGMII_RXD1 */ + , /* ETH_RGMII_RXD2 */ + , /* ETH_RGMII_RXD3 */ + , /* ETH_RGMII_RX_CLK */ + ; /* ETH_RGMII_RX_CTL */ + }; + }; + i2c1_pins_a: i2c1-0 { pins { pinmux = , /* I2C1_SCL */ @@ -187,6 +233,19 @@ }; }; + m_can1_pins_a: m-can1-0 { + pins1 { + pinmux = ; /* CAN1_TX */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-disable; + }; + }; + pwm2_pins_a: pwm2-0 { pins { pinmux = ; /* TIM2_CH4 */ @@ -360,6 +419,21 @@ slew-rate = <0>; }; }; + + spi1_pins_a: spi1-0 { + pins1 { + pinmux = , /* SPI1_SCK */ + ; /* SPI1_MOSI */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + + pins2 { + pinmux = ; /* SPI1_MISO */ + bias-disable; + }; + }; }; }; }; diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi new file mode 100644 index 0000000000..b4cfba0a38 --- /dev/null +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright : STMicroelectronics 2018 + */ + +#include +#include "stm32mp157-u-boot.dtsi" +#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi" + +/ { + aliases { + i2c3 = &i2c4; + mmc0 = &sdmmc1; + }; + config { + u-boot,boot-led = "heartbeat"; + u-boot,error-led = "error"; + st,adc_usb_pd = <&adc1 18>, <&adc1 19>; + }; + led { + red { + label = "error"; + gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + status = "okay"; + }; + + blue { + default-state = "on"; + }; + }; +}; + +&clk_hse { + st,digbypass; +}; + +&i2c4 { + u-boot,dm-pre-reloc; +}; + +&i2c4_pins_a { + u-boot,dm-pre-reloc; + pins { + u-boot,dm-pre-reloc; + }; +}; + +&pmic { + u-boot,dm-pre-reloc; +}; + +&rcc { + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P + CLK_MCU_PLL3P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE + CLK_RTC_LSE + CLK_MCO1_DISABLED + CLK_MCO2_DISABLED + >; + + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; + + st,pkcs = < + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE + CLK_SPI2S1_PLL3Q + CLK_SPI2S23_PLL3Q + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI + CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE + CLK_I2C12_HSI + CLK_I2C35_HSI + CLK_UART1_HSI + CLK_UART24_HSI + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI + CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4Q + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q + CLK_RNG1_LSI + CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 + CLK_LPTIM45_LSE + >; + + /* VCO = 1300.0 MHz => P = 650 (CPU) */ + pll1: st,pll@0 { + cfg = < 2 80 0 0 0 PQR(1,0,0) >; + frac = < 0x800 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; + frac = < 0x1400 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { + cfg = < 1 33 1 16 36 PQR(1,1,1) >; + frac = < 0x1a04 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ + pll4: st,pll@3 { + cfg = < 3 98 5 7 7 PQR(1,1,1) >; + u-boot,dm-pre-reloc; + }; +}; + +&sdmmc1 { + u-boot,dm-spl; +}; + +&sdmmc1_b4_pins_a { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; + +&uart4 { + u-boot,dm-pre-reloc; +}; + +&uart4_pins_a { + u-boot,dm-pre-reloc; + pins1 { + u-boot,dm-pre-reloc; + }; + pins2 { + u-boot,dm-pre-reloc; + }; +}; + +&usbotg_hs { + usb1600; + hnp-srp-disable; +}; + +&v3v3 { + regulator-always-on; +}; diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts new file mode 100644 index 0000000000..0882765d0c --- /dev/null +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157-pinctrl.dtsi" +#include +#include + +/ { + model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; + compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; + + aliases { + ethernet0 = ðernet0; + serial0 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@c0000000 { + reg = <0xc0000000 0x20000000>; + }; + + led { + compatible = "gpio-leds"; + blue { + label = "heartbeat"; + gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + }; +}; + +ðernet0 { + status = "okay"; + pinctrl-0 = <ðernet0_rgmii_pins_a>; + pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; + pinctrl-names = "default", "sleep"; + phy-mode = "rgmii"; + max-speed = <1000>; + phy-handle = <&phy0>; + + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; + + pmic: stpmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; + st,usb-control-register = <0x20>; + + regulators { + compatible = "st,stpmic1-regulators"; + + ldo1-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; + ldo6-supply = <&v3v3>; + pwr_sw1-supply = <&bst_out>; + pwr_sw2-supply = <&bst_out>; + + vddcore: buck1 { + regulator-name = "vddcore"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd_ddr: buck2 { + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd: buck3 { + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask-reset; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + v3v3: buck4 { + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; + regulator-initial-mode = <0>; + }; + + v1v8_audio: ldo1 { + regulator-name = "v1v8_audio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + interrupts = ; + }; + + v3v3_hdmi: ldo2 { + regulator-name = "v3v3_hdmi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + interrupts = ; + }; + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <750000>; + regulator-always-on; + regulator-over-current-protection; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + interrupts = ; + }; + + vdda: ldo5 { + regulator-name = "vdda"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + interrupts = ; + regulator-boot-on; + }; + + v1v2_hdmi: ldo6 { + regulator-name = "v1v2_hdmi"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + interrupts = ; + + }; + + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; + regulator-over-current-protection; + }; + + bst_out: boost { + regulator-name = "bst_out"; + interrupts = ; + }; + + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; + regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; + regulator-active-discharge; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; + interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; + status = "okay"; + }; + + watchdog { + compatible = "st,stpmic1-wdt"; + status = "disabled"; + }; + }; +}; + +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +&pwr { + pwr-supply = <&vdd>; +}; + +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + broken-cd; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; + status = "okay"; +}; + +&usbh_ehci { + phys = <&usbphyc_port0>; + phy-names = "usb"; + status = "okay"; +}; + +&usbphyc { + vdd3v3-supply = <&vdd_usb>; + status = "okay"; +}; + +&vrefbuf { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + vdda-supply = <&vdd>; + status = "okay"; +}; diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi new file mode 100644 index 0000000000..06ef3a4095 --- /dev/null +++ b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright : STMicroelectronics 2018 + */ + +#include "stm32mp157a-dk1-u-boot.dtsi" diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts new file mode 100644 index 0000000000..9a81d2d472 --- /dev/null +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +/dts-v1/; + +#include "stm32mp157a-dk1.dts" + +/ { + model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; + compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; +}; + +&dsi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + phy-dsi-supply = <®18>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <<dc_ep1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + + panel@0 { + compatible = "orisetech,otm8009a"; + reg = <0>; + reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; + status = "okay"; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; +}; + +<dc { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep1_out: endpoint@1 { + reg = <1>; + remote-endpoint = <&dsi_in>; + }; + }; +}; diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index d22401c26e..55f99037b2 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -9,9 +9,9 @@ / { aliases { + i2c3 = &i2c4; mmc0 = &sdmmc1; mmc1 = &sdmmc2; - i2c3 = &i2c4; }; config { @@ -48,14 +48,8 @@ st,digbypass; }; -&uart4_pins_a { +&i2c4 { u-boot,dm-pre-reloc; - pins1 { - u-boot,dm-pre-reloc; - }; - pins2 { - u-boot,dm-pre-reloc; - }; }; &i2c4_pins_a { @@ -65,14 +59,6 @@ }; }; -&uart4 { - u-boot,dm-pre-reloc; -}; - -&i2c4 { - u-boot,dm-pre-reloc; -}; - &pmic { u-boot,dm-pre-reloc; }; @@ -170,8 +156,6 @@ }; }; -/* SPL part **************************************/ -/* MMC1 boot */ &sdmmc1_b4_pins_a { u-boot,dm-spl; pins { @@ -190,7 +174,6 @@ u-boot,dm-spl; }; -/* MMC2 boot */ &sdmmc2_b4_pins_a { u-boot,dm-spl; pins { @@ -208,3 +191,17 @@ &sdmmc2 { u-boot,dm-spl; }; + +&uart4 { + u-boot,dm-pre-reloc; +}; + +&uart4_pins_a { + u-boot,dm-pre-reloc; + pins1 { + u-boot,dm-pre-reloc; + }; + pins2 { + u-boot,dm-pre-reloc; + }; +}; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 1d0306e2f4..2664c9ce90 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -15,13 +15,17 @@ compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; chosen { - stdout-path = "serial3:115200n8"; + stdout-path = "serial0:115200n8"; }; memory@c0000000 { reg = <0xC0000000 0x40000000>; }; + aliases { + serial0 = &uart4; + }; + sd_switch: regulator-sd_switch { compatible = "regulator-gpio"; regulator-name = "sd_switch"; @@ -36,15 +40,8 @@ }; }; -&rng1 { - status = "okay"; -}; - -&timers6 { +&hwspinlock { status = "okay"; - timer@5 { - status = "okay"; - }; }; &i2c4 { @@ -321,10 +318,27 @@ }; }; +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +&pinctrl { + hwlocks = <&hwspinlock 0>; +}; + &pwr { pwr-supply = <&vdd>; }; +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + &sdmmc1 { pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; broken-cd; @@ -355,6 +369,13 @@ status = "okay"; }; +&timers6 { + status = "okay"; + timer@5 { + status = "okay"; + }; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; @@ -365,14 +386,6 @@ usb33d-supply = <&usb33>; }; -&hwspinlock { - status = "okay"; -}; - -&pinctrl { - hwlocks = <&hwspinlock 0>; -}; - &usbphyc_port0 { phy-supply = <&vdd_usb>; vdda1v1-supply = <®11>; diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi index 30b173478c..be3b152628 100644 --- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi @@ -7,29 +7,21 @@ / { aliases { - spi0 = &qspi; i2c1 = &i2c2; i2c4 = &i2c5; + spi0 = &qspi; }; }; &flash0 { compatible = "spi-flash"; + u-boot,dm-spl; }; &flash1 { compatible = "spi-flash"; }; -&v3v3 { - regulator-always-on; -}; - -&usbotg_hs { - g-tx-fifo-size = <576>; -}; - -/* SPL part **************************************/ &qspi { u-boot,dm-spl; }; @@ -61,7 +53,10 @@ }; }; -&flash0 { - u-boot,dm-spl; +&usbotg_hs { + g-tx-fifo-size = <576>; }; +&v3v3 { + regulator-always-on; +}; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 902a42bee2..e114c9b628 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -11,6 +11,21 @@ model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart4; + ethernet0 = ðernet0; + }; + + panel_backlight: panel-backlight { + compatible = "gpio-backlight"; + gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; + default-on; + status = "okay"; + }; }; &cec { @@ -19,6 +34,64 @@ status = "okay"; }; +&dsi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <<dc_ep0_out>; + }; + }; + + port@1 { + reg = <1>; + dsi_out: endpoint { + remote-endpoint = <&dsi_panel_in>; + }; + }; + }; + + panel-dsi@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; + backlight = <&panel_backlight>; + status = "okay"; + + port { + dsi_panel_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; +}; + +ðernet0 { + status = "okay"; + pinctrl-0 = <ðernet0_rgmii_pins_a>; + pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; + pinctrl-names = "default", "sleep"; + phy-mode = "rgmii"; + max-speed = <1000>; + phy-handle = <&phy0>; + + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + &i2c2 { pinctrl-names = "default"; pinctrl-0 = <&i2c2_pins_a>; @@ -35,6 +108,26 @@ status = "okay"; }; +<dc { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&dsi_in>; + }; + }; +}; + +&m_can1 { + pinctrl-names = "default"; + pinctrl-0 = <&m_can1_pins_a>; + status = "okay"; +}; + &qspi { pinctrl-names = "default"; pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; @@ -60,6 +153,12 @@ }; }; +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins_a>; + status = "disabled"; +}; + &timers2 { status = "disabled"; pwm { @@ -106,6 +205,7 @@ &usbotg_hs { pinctrl-names = "default"; pinctrl-0 = <&usbotg_hs_pins_a>; + dr_mode = "peripheral"; phys = <&usbphyc_port1 0>; phy-names = "usb2-phy"; status = "okay"; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index d662013243..7eb4bee31c 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -106,26 +106,6 @@ }; }; - pm_domain { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32mp157c-pd"; - - pd_core_ret: core-ret-power-domain@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - #power-domain-cells = <0>; - label = "CORE-RETENTION"; - - pd_core: core-power-domain@2 { - reg = <2>; - #power-domain-cells = <0>; - label = "CORE"; - }; - }; - }; - soc { compatible = "simple-bus"; #address-cells = <1>; @@ -339,6 +319,34 @@ }; }; + spi2: spi@4000b000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x4000b000 0x400>; + interrupts = ; + clocks = <&rcc SPI2_K>; + resets = <&rcc SPI2_R>; + dmas = <&dmamux1 39 0x400 0x05>, + <&dmamux1 40 0x400 0x05>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + spi3: spi@4000c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x4000c000 0x400>; + interrupts = ; + clocks = <&rcc SPI3_K>; + resets = <&rcc SPI3_R>; + dmas = <&dmamux1 61 0x400 0x05>, + <&dmamux1 62 0x400 0x05>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + usart2: serial@4000e000 { compatible = "st,stm32h7-uart"; reg = <0x4000e000 0x400>; @@ -522,6 +530,34 @@ status = "disabled"; }; + spi1: spi@44004000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x44004000 0x400>; + interrupts = ; + clocks = <&rcc SPI1_K>; + resets = <&rcc SPI1_R>; + dmas = <&dmamux1 37 0x400 0x05>, + <&dmamux1 38 0x400 0x05>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + spi4: spi@44005000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x44005000 0x400>; + interrupts = ; + clocks = <&rcc SPI4_K>; + resets = <&rcc SPI4_R>; + dmas = <&dmamux1 83 0x400 0x05>, + <&dmamux1 84 0x400 0x05>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + timers15: timer@44006000 { #address-cells = <1>; #size-cells = <0>; @@ -584,6 +620,116 @@ }; }; + spi5: spi@44009000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x44009000 0x400>; + interrupts = ; + clocks = <&rcc SPI5_K>; + resets = <&rcc SPI5_R>; + dmas = <&dmamux1 85 0x400 0x05>, + <&dmamux1 86 0x400 0x05>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + dfsdm: dfsdm@4400d000 { + compatible = "st,stm32mp1-dfsdm"; + reg = <0x4400d000 0x800>; + clocks = <&rcc DFSDM_K>; + clock-names = "dfsdm"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + dfsdm0: filter@0 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <0>; + interrupts = ; + dmas = <&dmamux1 101 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + + dfsdm1: filter@1 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <1>; + interrupts = ; + dmas = <&dmamux1 102 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + + dfsdm2: filter@2 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <2>; + interrupts = ; + dmas = <&dmamux1 103 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + + dfsdm3: filter@3 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <3>; + interrupts = ; + dmas = <&dmamux1 104 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + + dfsdm4: filter@4 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <4>; + interrupts = ; + dmas = <&dmamux1 91 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + + dfsdm5: filter@5 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <5>; + interrupts = ; + dmas = <&dmamux1 92 0x400 0x01>; + dma-names = "rx"; + status = "disabled"; + }; + }; + + m_can1: can@4400e000 { + compatible = "bosch,m_can"; + reg = <0x4400e000 0x400>, <0x44011000 0x2800>; + reg-names = "m_can", "message_ram"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; + status = "disabled"; + }; + + m_can2: can@4400f000 { + compatible = "bosch,m_can"; + reg = <0x4400f000 0x400>, <0x44011000 0x2800>; + reg-names = "m_can", "message_ram"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; + status = "disabled"; + }; + dma1: dma@48000000 { compatible = "st,stm32-dma"; reg = <0x48000000 0x400>; @@ -647,6 +793,8 @@ reg = <0x0>; interrupt-parent = <&adc>; interrupts = <0>; + dmas = <&dmamux1 9 0x400 0x01>; + dma-names = "rx"; status = "disabled"; }; @@ -656,6 +804,8 @@ reg = <0x100>; interrupt-parent = <&adc>; interrupts = <1>; + dmas = <&dmamux1 10 0x400 0x01>; + dma-names = "rx"; status = "disabled"; }; }; @@ -675,7 +825,7 @@ }; usbotg_hs: usb-otg@49000000 { - compatible = "st,stm32mp1-hsotg", "snps,dwc2"; + compatible = "snps,dwc2"; reg = <0x49000000 0x10000>; clocks = <&rcc USBO_K>; clock-names = "otg"; @@ -686,7 +836,6 @@ g-np-tx-fifo-size = <32>; g-tx-fifo-size = <128 128 64 64 64 64 32 32>; dr_mode = "otg"; - power-domains = <&pd_core>; status = "disabled"; }; @@ -753,7 +902,7 @@ reg = <0x5000d000 0x400>; }; - syscfg: system-config@50020000 { + syscfg: syscon@50020000 { compatible = "st,stm32mp157-syscfg", "syscon"; reg = <0x50020000 0x400>; }; @@ -853,6 +1002,18 @@ status = "disabled"; }; + hash1: hash@54002000 { + compatible = "st,stm32f756-hash"; + reg = <0x54002000 0x400>; + interrupts = ; + clocks = <&rcc HASH1>; + resets = <&rcc HASH1_R>; + dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0>; + dma-names = "in"; + dma-maxburst = <2>; + status = "disabled"; + }; + rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; @@ -871,7 +1032,7 @@ dma-requests = <48>; }; - qspi: qspi@58003000 { + qspi: spi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; @@ -915,6 +1076,36 @@ status = "disabled"; }; + stmmac_axi_config_0: stmmac-axi-config { + snps,wr_osr_lmt = <0x7>; + snps,rd_osr_lmt = <0x7>; + snps,blen = <0 0 0 0 16 8 4>; + }; + + ethernet0: ethernet@5800a000 { + compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; + reg = <0x5800a000 0x2000>; + reg-names = "stmmaceth"; + interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clock-names = "stmmaceth", + "mac-clk-tx", + "mac-clk-rx", + "ethstp", + "syscfg-clk"; + clocks = <&rcc ETHMAC>, + <&rcc ETHTX>, + <&rcc ETHRX>, + <&rcc ETHSTP>, + <&rcc SYSCFG>; + st,syscon = <&syscfg 0x4>; + snps,mixed-burst; + snps,pbl = <2>; + snps,axi-config = <&stmmac_axi_config_0>; + snps,tso; + status = "disabled"; + }; + usbh_ohci: usbh-ohci@5800c000 { compatible = "generic-ohci"; reg = <0x5800c000 0x1000>; @@ -955,6 +1146,14 @@ status = "disabled"; }; + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; @@ -983,6 +1182,20 @@ status = "disabled"; }; + spi6: spi@5c001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x5c001000 0x400>; + interrupts = ; + clocks = <&rcc SPI6_K>; + resets = <&rcc SPI6_R>; + dmas = <&mdma1 34 0x0 0x40008 0x0 0x0>, + <&mdma1 35 0x0 0x40002 0x0 0x0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + i2c4: i2c@5c002000 { compatible = "st,stm32f7-i2c"; reg = <0x5c002000 0x400>; @@ -996,6 +1209,15 @@ status = "disabled"; }; + rtc: rtc@5c004000 { + compatible = "st,stm32mp1-rtc"; + reg = <0x5c004000 0x400>; + clocks = <&rcc RTCAPB>, <&rcc RTC>; + clock-names = "pclk", "rtc_ck"; + interrupts = ; + status = "disabled"; + }; + bsec: nvmem@5c005000 { compatible = "st,stm32mp15-bsec"; reg = <0x5c005000 0x400>; -- cgit From 39110484577139f845bbfc42977550f9969bc712 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Feb 2019 16:50:39 +0100 Subject: board: stm32mp1: Update README file Update README with DK1 and DK2 boards related informations Signed-off-by: Patrice Chotard --- board/st/stm32mp1/README | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 72b28fabfc..1cd3534ae4 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -35,6 +35,8 @@ And the necessary drivers Currently the following boards are supported: + stm32mp157c-ev1 + stm32mp157c-ed1 ++ stm32mp157a-dk1 ++ stm32mp157c-dk2 3. Boot Sequences ================= @@ -76,6 +78,12 @@ the supported device trees for stm32mp157 are: + ed1: daughter board with pmic stpmic1 dts: stm32mp157c-ed1 ++ dk1: Discovery board + dts: stm32mp157a-dk1 + ++ dk2: Discovery board = dk1 with a BT/WiFI combo and a DSI panel + dts: stm32mp157c-dk2 + 5. Build Procedure ================== @@ -127,6 +135,11 @@ the supported device trees for stm32mp157 are: # make stm32mp15_basic_defconfig # make DEVICE_TREE=stm32mp157c-ed1 all + d) basic boot on dk2 + # export KBUILD_OUTPUT=stm32mp15_basic + # make stm32mp15_basic_defconfig + # make DEVICE_TREE=stm32mp157c-dk2 all + 6. Output files BootRom and TF-A expect binaries with STM32 image header @@ -159,6 +172,16 @@ You can select the boot mode, on the board ed1 with the switch SW1 Recovery 1 1 0 Recovery 0 0 0 +- on board DK1/DK2 with the switch SW1 : BOOT0, BOOT2 + (BOOT1 forced to 0, NOR not supported) + + -------------------------- + Boot Mode BOOT2 BOOT0 + -------------------------- + Reserved 1 0 + SD-Card 1 1 + Recovery 0 0 + Recovery is a boot from serial link (UART/USB) and it is used with STM32CubeProgrammer tool to load executable in RAM and to update the flash devices available on the board (NOR/NAND/eMMC/SDCARD). -- cgit From 395f12976c87c59ec9836027687d395990a9f961 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Feb 2019 16:50:40 +0100 Subject: Board: stm32mp1: Add supply current boot information For DK1/DK2 boards, check if power supply provides enough current to allow the board to boot correctly. ADC@0 channel 18 and 19 are connected to USB type-C CC1 and CC2 signals. The table below shows the behavior for different range of CC1 or CC2: range | power supply | red led | console message (Volts) | (Amps) | blinks | --------------|--------------|---------|----------------------------------- [2.10 - 1.23[ | 3 | NO | NO [1.23 - 0.66[ | 1.5 | 3 times | WARNING 1.5A power supply detected [0.66 - 0] | 0.5 | 2 times | WARNING 500mA power supply detected If detected current is < 3A, red led is kept ON after blinking. Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 154 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 282918089b..ff7790e310 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -2,9 +2,10 @@ /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ +#include +#include #include #include -#include #include #include #include @@ -62,6 +63,10 @@ DECLARE_GLOBAL_DATA_PTR; #define STM32MP_GGPIO 0x38 #define STM32MP_GGPIO_VBUS_SENSING BIT(21) +#define USB_WARNING_LOW_THRESHOLD_UV 660000 +#define USB_START_LOW_THRESHOLD_UV 1230000 +#define USB_START_HIGH_THRESHOLD_UV 2100000 + int checkboard(void) { int ret; @@ -294,6 +299,145 @@ clk_err: return ret; } +static int get_led(struct udevice **dev, char *led_string) +{ + char *led_name; + int ret; + + led_name = fdtdec_get_config_string(gd->fdt_blob, led_string); + if (!led_name) { + pr_debug("%s: could not find %s config string\n", + __func__, led_string); + return -ENOENT; + } + ret = led_get_by_label(led_name, dev); + if (ret) { + debug("%s: get=%d\n", __func__, ret); + return ret; + } + + return 0; +} + +static int setup_led(enum led_state_t cmd) +{ + struct udevice *dev; + int ret; + + ret = get_led(&dev, "u-boot,boot-led"); + if (ret) + return ret; + + ret = led_set_state(dev, cmd); + return ret; +} + +static int board_check_usb_power(void) +{ + struct ofnode_phandle_args adc_args; + struct udevice *adc; + struct udevice *led; + ofnode node; + unsigned int raw; + int max_uV = 0; + int ret, uV, adc_count; + u8 i, nb_blink; + + node = ofnode_path("/config"); + if (!ofnode_valid(node)) { + debug("%s: no /config node?\n", __func__); + return -ENOENT; + } + + /* + * Retrieve the ADC channels devices and get measurement + * for each of them + */ + adc_count = ofnode_count_phandle_with_args(node, "st,adc_usb_pd", + "#io-channel-cells"); + if (adc_count < 0) { + if (adc_count == -ENOENT) + return 0; + + pr_err("%s: can't find adc channel (%d)\n", __func__, + adc_count); + + return adc_count; + } + + for (i = 0; i < adc_count; i++) { + if (ofnode_parse_phandle_with_args(node, "st,adc_usb_pd", + "#io-channel-cells", 0, i, + &adc_args)) { + pr_debug("%s: can't find /config/st,adc_usb_pd\n", + __func__); + return 0; + } + + ret = uclass_get_device_by_ofnode(UCLASS_ADC, adc_args.node, + &adc); + + if (ret) { + pr_err("%s: Can't get adc device(%d)\n", __func__, + ret); + return ret; + } + + ret = adc_channel_single_shot(adc->name, adc_args.args[0], + &raw); + if (ret) { + pr_err("%s: single shot failed for %s[%d]!\n", + __func__, adc->name, adc_args.args[0]); + return ret; + } + /* Convert to uV */ + if (!adc_raw_to_uV(adc, raw, &uV)) { + if (uV > max_uV) + max_uV = uV; + pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__, + adc->name, adc_args.args[0], raw, uV); + } else { + pr_err("%s: Can't get uV value for %s[%d]\n", + __func__, adc->name, adc_args.args[0]); + } + } + + /* + * If highest value is inside 1.23 Volts and 2.10 Volts, that means + * board is plugged on an USB-C 3A power supply and boot process can + * continue. + */ + if (max_uV > USB_START_LOW_THRESHOLD_UV && + max_uV < USB_START_HIGH_THRESHOLD_UV) + return 0; + + /* Display warning message and make u-boot,error-led blinking */ + pr_err("\n*******************************************\n"); + + if (max_uV < USB_WARNING_LOW_THRESHOLD_UV) { + pr_err("* WARNING 500mA power supply detected *\n"); + nb_blink = 2; + } else { + pr_err("* WARNING 1.5A power supply detected *\n"); + nb_blink = 3; + } + + pr_err("* Current too low, use a 3A power supply! *\n"); + pr_err("*******************************************\n\n"); + + ret = get_led(&led, "u-boot,error-led"); + if (ret) + return ret; + + for (i = 0; i < nb_blink * 2; i++) { + led_set_state(led, LEDST_TOGGLE); + mdelay(125); + } + led_set_state(led, LEDST_ON); + + return 0; +} + int board_usb_cleanup(int index, enum usb_init_type init) { /* Reset usbotg */ @@ -428,5 +572,13 @@ int board_late_init(void) } #endif + /* for DK1/DK2 boards */ + board_check_usb_power(); + return 0; } + +void board_quiesce_devices(void) +{ + setup_led(LEDST_OFF); +} -- cgit From 77457fa94ebcf60f95a08d3ea7574035bff3bc93 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Feb 2019 16:50:41 +0100 Subject: ARM: dts: stm32mp1: Add adc nodes Add adc related nodes. These nodes are used to detect the current supplied by USB type-C power in port on DK1 and DK2 boards. Signed-off-by: Patrice Chotard --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 7 +++++++ arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 4d2bf33be7..c069875486 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -148,6 +148,13 @@ gpio-ranges = <&pinctrl 0 160 8>; }; + adc12_usb_pwr_pins_a: adc12-usb-pwr-pins-0 { + pins { + pinmux = , /* ADC12 in18 */ + ; /* ADC12 in19 */ + }; + }; + cec_pins_a: cec-0 { pins { pinmux = ; diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index b4cfba0a38..af7acfa037 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -31,6 +31,27 @@ }; }; +&adc { + pinctrl-names = "default"; + pinctrl-0 = <&adc12_usb_pwr_pins_a>; + vdd-supply = <&vdd>; + vdda-supply = <&vdd>; + vref-supply = <&vrefbuf>; + status = "okay"; + adc1: adc@0 { + /* + * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in18 & in19. + * Use at least 5 * RC time, e.g. 5 * (Rp + Rd) * C: + * 5 * (56 + 47kOhms) * 5pF => 2.5us. + * Use arbitrary margin here (e.g. 5µs). + */ + st,min-sample-time-nsecs = <5000>; + /* ANA0, ANA1, USB Type-C CC1 & CC2 */ + st,adc-channels = <0 1 18 19>; + status = "okay"; + }; +}; + &clk_hse { st,digbypass; }; -- cgit From 8262435dd2995539e616981206efc3e3ac72d7a0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 11 Mar 2019 11:13:15 +0100 Subject: pinctrl: Add STMFX GPIO expander Pinctrl/GPIO driver This patch adds pinctrl/GPIO driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander. STMFX is an I2C slave controller, offering up to 24 GPIOs. The driver relies on UCLASS_PINCTRL and UCLASS_GPIO. Signed-off-by: Patrick Delaunay Signed-off-by: Patrice Chotard --- drivers/pinctrl/Kconfig | 19 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-stmfx.c | 431 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-stmfx.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index be709f73d7..a0ac167d14 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -209,6 +209,25 @@ config PINCTRL_STM32 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_STMFX + bool "STMicroelectronics STMFX I2C GPIO expander pinctrl driver" + depends on DM && PINCTRL_FULL + help + I2C driver for STMicroelectronics Multi-Function eXpander (STMFX) + GPIO expander. + Supports pin multiplexing control on stm32 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + +config SPL_PINCTRL_STMFX + bool "STMicroelectronics STMFX I2C GPIO expander pinctrl driver in SPL" + depends on SPL_PINCTRL_FULL + help + This option is an SPL-variant of the SPL_PINCTRL_STMFX option. + See the help of PINCTRL_STMFX for details. + config ASPEED_AST2500_PINCTRL bool "Aspeed AST2500 pin control driver" depends on DM && PINCTRL_GENERIC && ASPEED_AST2500 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index e2c2b159d8..4b080b74dc 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_ARCH_MVEBU) += mvebu/ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o +obj-$(CONFIG_$(SPL_)PINCTRL_STMFX) += pinctrl-stmfx.o obj-y += broadcom/ diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c new file mode 100644 index 0000000000..5431df9813 --- /dev/null +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander + * based on Linux driver : pinctrl/pinctrl-stmfx.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* STMFX pins = GPIO[15:0] + aGPIO[7:0] */ +#define STMFX_MAX_GPIO 16 +#define STMFX_MAX_AGPIO 8 + +/* General */ +#define STMFX_REG_CHIP_ID 0x00 /* R */ +#define STMFX_REG_FW_VERSION_MSB 0x01 /* R */ +#define STMFX_REG_FW_VERSION_LSB 0x02 /* R */ +#define STMFX_REG_SYS_CTRL 0x40 /* RW */ + +/* MFX boot time is around 10ms, so after reset, we have to wait this delay */ +#define STMFX_BOOT_TIME_MS 10 + +/* GPIOs expander */ +/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */ +#define STMFX_REG_GPIO_STATE 0x10 /* R */ +/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */ +#define STMFX_REG_GPIO_DIR 0x60 /* RW */ +/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */ +#define STMFX_REG_GPIO_TYPE 0x64 /* RW */ +/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */ +#define STMFX_REG_GPIO_PUPD 0x68 /* RW */ +/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */ +#define STMFX_REG_GPO_SET 0x6C /* RW */ +/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */ +#define STMFX_REG_GPO_CLR 0x70 /* RW */ + +/* STMFX_REG_CHIP_ID bitfields */ +#define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0) + +/* STMFX_REG_SYS_CTRL bitfields */ +#define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0) +#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3) +#define STMFX_REG_SYS_CTRL_SWRST BIT(7) + +#define NR_GPIO_REGS 3 +#define NR_GPIOS_PER_REG 8 +#define get_reg(offset) ((offset) / NR_GPIOS_PER_REG) +#define get_shift(offset) ((offset) % NR_GPIOS_PER_REG) +#define get_mask(offset) (BIT(get_shift(offset))) + +struct stmfx_pinctrl { + struct udevice *gpio; +}; + +static int stmfx_read(struct udevice *dev, uint offset) +{ + return dm_i2c_reg_read(dev_get_parent(dev), offset); +} + +static int stmfx_write(struct udevice *dev, uint offset, unsigned int val) +{ + return dm_i2c_reg_write(dev_get_parent(dev), offset, val); +} + +static int stmfx_gpio_get(struct udevice *dev, unsigned int offset) +{ + u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset); + u32 mask = get_mask(offset); + int ret; + + ret = stmfx_read(dev, reg); + + return ret < 0 ? ret : !!(ret & mask); +} + +static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value) +{ + u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR; + u32 mask = get_mask(offset); + + return stmfx_write(dev, reg + get_reg(offset), mask); +} + +static int stmfx_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); + u32 mask = get_mask(offset); + int ret; + + ret = stmfx_read(dev, reg); + + if (ret < 0) + return ret; + /* On stmfx, gpio pins direction is (0)input, (1)output. */ + + return ret & mask ? GPIOF_OUTPUT : GPIOF_INPUT; +} + +static int stmfx_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); + u32 mask = get_mask(offset); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + + ret &= ~mask; + + return stmfx_write(dev, reg, ret & ~mask); +} + +static int stmfx_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); + u32 mask = get_mask(offset); + int ret; + + ret = stmfx_gpio_set(dev, offset, value); + if (ret < 0) + return ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + + return stmfx_write(dev, reg, ret | mask); +} + +static int stmfx_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct ofnode_phandle_args args; + u8 sys_ctrl; + + uc_priv->bank_name = "stmfx"; + uc_priv->gpio_count = STMFX_MAX_GPIO + STMFX_MAX_AGPIO; + if (!dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, 0, &args)) { + uc_priv->gpio_count = args.args[2]; + } + + /* enable GPIO function */ + sys_ctrl = STMFX_REG_SYS_CTRL_GPIO_EN; + if (uc_priv->gpio_count > STMFX_MAX_GPIO) + sys_ctrl |= STMFX_REG_SYS_CTRL_ALTGPIO_EN; + stmfx_write(dev, STMFX_REG_SYS_CTRL, sys_ctrl); + + return 0; +} + +static const struct dm_gpio_ops stmfx_gpio_ops = { + .set_value = stmfx_gpio_set, + .get_value = stmfx_gpio_get, + .get_function = stmfx_gpio_get_function, + .direction_input = stmfx_gpio_direction_input, + .direction_output = stmfx_gpio_direction_output, +}; + +U_BOOT_DRIVER(stmfx_gpio) = { + .name = "stmfx-gpio", + .id = UCLASS_GPIO, + .probe = stmfx_gpio_probe, + .ops = &stmfx_gpio_ops, +}; + +#if CONFIG_IS_ENABLED(PINCONF) +static const struct pinconf_param stmfx_pinctrl_conf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 }, + { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "output-high", PIN_CONFIG_OUTPUT, 1 }, + { "output-low", PIN_CONFIG_OUTPUT, 0 }, +}; + +static int stmfx_pinctrl_set_pupd(struct udevice *dev, + unsigned int pin, u32 pupd) +{ + u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin); + u32 mask = get_mask(pin); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + ret = (ret & ~mask) | (pupd ? mask : 0); + + return stmfx_write(dev, reg, ret); +} + +static int stmfx_pinctrl_set_type(struct udevice *dev, + unsigned int pin, u32 type) +{ + u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin); + u32 mask = get_mask(pin); + int ret; + + ret = stmfx_read(dev, reg); + if (ret < 0) + return ret; + ret = (ret & ~mask) | (type ? mask : 0); + + return stmfx_write(dev, reg, ret); +} + +static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, + unsigned int param, unsigned int arg) +{ + int ret, dir; + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + + dir = stmfx_gpio_get_function(plat->gpio, pin); + + if (dir < 0) + return dir; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = stmfx_pinctrl_set_pupd(dev, pin, 0); + break; + case PIN_CONFIG_BIAS_PULL_UP: + ret = stmfx_pinctrl_set_pupd(dev, pin, 1); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (dir == GPIOF_OUTPUT) + ret = stmfx_pinctrl_set_type(dev, pin, 1); + else + ret = stmfx_pinctrl_set_type(dev, pin, 0); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (dir == GPIOF_OUTPUT) + ret = stmfx_pinctrl_set_type(dev, pin, 0); + else + ret = stmfx_pinctrl_set_type(dev, pin, 1); + break; + case PIN_CONFIG_OUTPUT: + ret = stmfx_gpio_direction_output(plat->gpio, pin, arg); + break; + default: + return -ENOTSUPP; + } + + return ret; +} +#endif + +static int stmfx_pinctrl_get_pins_count(struct udevice *dev) +{ + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(plat->gpio); + + return uc_priv->gpio_count; +} + +/* + * STMFX pins[15:0] are called "gpio[15:0]" + * and STMFX pins[23:16] are called "agpio[7:0]" + */ +#define MAX_PIN_NAME_LEN 7 +static char pin_name[MAX_PIN_NAME_LEN]; +static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector < STMFX_MAX_GPIO) + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "agpio%u", selector - 16); + return pin_name; +} + +static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + int func; + + func = stmfx_gpio_get_function(plat->gpio, selector); + if (func < 0) + return func; + + snprintf(buf, size, "%s", func == GPIOF_INPUT ? "input" : "output"); + + return 0; +} + +static int stmfx_pinctrl_bind(struct udevice *dev) +{ + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + + return device_bind_driver_to_node(dev->parent, + "stmfx-gpio", "stmfx-gpio", + dev_ofnode(dev), &plat->gpio); +}; + +static int stmfx_pinctrl_probe(struct udevice *dev) +{ + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + + return device_probe(plat->gpio); +}; + +const struct pinctrl_ops stmfx_pinctrl_ops = { + .get_pins_count = stmfx_pinctrl_get_pins_count, + .get_pin_name = stmfx_pinctrl_get_pin_name, + .set_state = pinctrl_generic_set_state, + .get_pin_muxing = stmfx_pinctrl_get_pin_muxing, +#if CONFIG_IS_ENABLED(PINCONF) + .pinconf_set = stmfx_pinctrl_conf_set, + .pinconf_num_params = ARRAY_SIZE(stmfx_pinctrl_conf_params), + .pinconf_params = stmfx_pinctrl_conf_params, +#endif +}; + +static const struct udevice_id stmfx_pinctrl_match[] = { + { .compatible = "st,stmfx-0300-pinctrl", }, +}; + +U_BOOT_DRIVER(stmfx_pinctrl) = { + .name = "stmfx-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(stmfx_pinctrl_match), + .bind = stmfx_pinctrl_bind, + .probe = stmfx_pinctrl_probe, + .ops = &stmfx_pinctrl_ops, + .platdata_auto_alloc_size = sizeof(struct stmfx_pinctrl), +}; + +static int stmfx_chip_init(struct udevice *dev) +{ + u8 id; + u8 version[2]; + int ret; + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + + id = dm_i2c_reg_read(dev, STMFX_REG_CHIP_ID); + if (id < 0) { + dev_err(dev, "error reading chip id: %d\n", id); + return ret; + } + /* + * Check that ID is the complement of the I2C address: + * STMFX I2C address follows the 7-bit format (MSB), that's why + * client->addr is shifted. + * + * STMFX_I2C_ADDR| STMFX | Linux + * input pin | I2C device address | I2C device address + *--------------------------------------------------------- + * 0 | b: 1000 010x h:0x84 | 0x42 + * 1 | b: 1000 011x h:0x86 | 0x43 + */ + if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (chip->chip_addr << 1)) { + dev_err(dev, "unknown chip id: %#x\n", id); + return -EINVAL; + } + + ret = dm_i2c_read(dev, STMFX_REG_FW_VERSION_MSB, + version, sizeof(version)); + if (ret) { + dev_err(dev, "error reading fw version: %d\n", ret); + return ret; + } + + dev_info(dev, "STMFX id: %#x, fw version: %x.%02x\n", + id, version[0], version[1]); + + ret = dm_i2c_reg_read(dev, STMFX_REG_SYS_CTRL); + + if (ret < 0) + return ret; + + ret = dm_i2c_reg_write(dev, STMFX_REG_SYS_CTRL, + ret | STMFX_REG_SYS_CTRL_SWRST); + if (ret) + return ret; + + mdelay(STMFX_BOOT_TIME_MS); + + return ret; +} + +static int stmfx_probe(struct udevice *dev) +{ + struct udevice *vdd; + int ret; + + ret = device_get_supply_regulator(dev, "vdd-supply", &vdd); + if (ret && ret != -ENOENT) { + dev_err(dev, "vdd regulator error:%d\n", ret); + return ret; + } + if (!ret) { + ret = regulator_set_enable(vdd, true); + if (ret) { + dev_err(dev, "vdd enable failed: %d\n", ret); + return ret; + } + } + + return stmfx_chip_init(dev); +} + +static const struct udevice_id stmfx_match[] = { + { .compatible = "st,stmfx-0300", }, +}; + +U_BOOT_DRIVER(stmfx) = { + .name = "stmfx", + .id = UCLASS_I2C_GENERIC, + .of_match = of_match_ptr(stmfx_match), + .probe = stmfx_probe, + .bind = dm_scan_fdt_dev, +}; -- cgit From 8c3ff9ba02bb71e405b936913707ec147c4bb6d1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 11 Mar 2019 11:13:16 +0100 Subject: config: stm32mp15: Enable STMFX support Activate PINCTRL_STMFX and needed part for generic pincontrol PINCTRL_FULL, PINCONF. Increase pre-reloc memory for MALLOC (needed for each DM pinconfig node). Signed-off-by: Patrick Delaunay Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 5 +++-- configs/stm32mp15_trusted_defconfig | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index ac52155699..6781adb81e 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -1,6 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_STM32MP=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x3000 CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL=y CONFIG_TARGET_STM32MP1=y @@ -55,8 +55,9 @@ CONFIG_DM_MMC=y CONFIG_STM32_SDMMC2=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y -# CONFIG_PINCTRL_FULL is not set +CONFIG_PINCONF=y # CONFIG_SPL_PINCTRL_FULL is not set +CONFIG_PINCTRL_STMFX=y CONFIG_DM_PMIC=y # CONFIG_SPL_PMIC_CHILDREN is not set CONFIG_PMIC_STPMIC1=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 0ffea5bfb3..a050cee691 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -1,6 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_STM32MP=y -CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_MALLOC_F_LEN=0x3000 CONFIG_TARGET_STM32MP1=y CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=y @@ -48,7 +48,8 @@ CONFIG_DM_MMC=y CONFIG_STM32_SDMMC2=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y -# CONFIG_PINCTRL_FULL is not set +CONFIG_PINCONF=y +CONFIG_PINCTRL_STMFX=y CONFIG_DM_PMIC=y CONFIG_PMIC_STPMIC1=y CONFIG_DM_REGULATOR_FIXED=y -- cgit From 8b4afe8070ebc0aed60210c16449385e34481e1b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 11 Mar 2019 11:13:17 +0100 Subject: board: stm32mp1: Force pinctrl driver probe in board_init() In order to insure that hog GPIOs are configured early during the boot process, force all pinctrl driver probing in board_init(). Signed-off-by: Patrick Delaunay Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index ff7790e310..24d299ac33 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -543,9 +543,18 @@ static void sysconf_init(void) /* board dependent setup after realloc */ int board_init(void) { + struct udevice *dev; + /* address of boot parameters */ gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100; + /* probe all PINCTRL for hog */ + for (uclass_first_device(UCLASS_PINCTRL, &dev); + dev; + uclass_next_device(&dev)) { + pr_debug("probe pincontrol = %s\n", dev->name); + } + board_key_check(); sysconf_init(); -- cgit From 1258e4667a1d3db067158091828b64babf13d069 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 12 Apr 2019 14:38:28 +0200 Subject: ARM: dts: Add STMFX gpio expander support for stm32mp157c-ev1 Adds alias to set the pincontrol seq id. For STMFX gpio expander, force sequence number after the last bank (GPIOZ) to avoid conflict between STM32MP and STMFX gpio bank sequence number. Signed-off-by: Patrick Delaunay Signed-off-by: Patrice Chotard --- arch/arm/dts/stm32mp157-u-boot.dtsi | 2 ++ arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi | 2 ++ arch/arm/dts/stm32mp157c-ev1.dts | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 2594702c92..ab6f673ea2 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -17,6 +17,8 @@ gpio9 = &gpioj; gpio10 = &gpiok; gpio25 = &gpioz; + pinctrl0 = &pinctrl; + pinctrl1 = &pinctrl_z; }; config { diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi index be3b152628..6a18d032ae 100644 --- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi @@ -7,8 +7,10 @@ / { aliases { + gpio26 = &stmfx_pinctrl; i2c1 = &i2c2; i2c4 = &i2c5; + pinctrl2 = &stmfx_pinctrl; spi0 = &qspi; }; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index e114c9b628..a6ee37924f 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -98,6 +98,24 @@ i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; + + stmfx: stmfx@42 { + compatible = "st,stmfx-0300"; + reg = <0x42>; + interrupts = <8 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpioi>; + vdd-supply = <&v3v3>; + + stmfx_pinctrl: stmfx-pin-controller { + compatible = "st,stmfx-0300-pinctrl"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&stmfx_pinctrl 0 0 24>; + status = "disabled"; + }; + }; }; &i2c5 { -- cgit From 321d15323856f3f3b8f021abe98178c4285054d6 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 5 Apr 2019 11:46:50 +0200 Subject: spi: stm32_qspi: move to exec_op We are facing issues in the driver since SPI NOR framework has moved on SPI MEM framework, and SPI NAND framework is not running properly with the current driver. To be able to solve issues met on SPI NOR Flashes and to be able to support SPI NAND Flashes, the driver has been reworked. We are now using exec_op ops instead of using xfer ops. Thanks to this rework, the driver has been successfully tested with: - mx66l51235l SPI NOR Flash on stm32f746 SOC - n25q128a SPI NOR Flash on stm32f769 SOC - mx66l51235l SPI NOR Flash on stm32mp1 SOC - mt29f2g01abagd SPI NAND Flash on stm32mp1 SOC Signed-off-by: Christophe Kerello Tested-by: Patrick DELAUNAY Reviewed-by: Patrick DELAUNAY --- drivers/spi/Kconfig | 3 +- drivers/spi/stm32_qspi.c | 625 ++++++++++++++++++----------------------------- 2 files changed, 245 insertions(+), 383 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 098372e093..a700f240ad 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -222,8 +222,7 @@ config SPI_SUNXI config STM32_QSPI bool "STM32F7 QSPI driver" - depends on STM32F7 - imply SPI_FLASH_BAR + depends on STM32F7 || ARCH_STM32MP help Enable the STM32F7 Quad-SPI (QSPI) driver. This driver can be used to access the SPI NOR flash chips on platforms embedding diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 8b60d7c3b2..bb1067ff4a 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -9,15 +9,11 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include +#include +#include #include +#include struct stm32_qspi_regs { u32 cr; /* 0x00 */ @@ -45,8 +41,7 @@ struct stm32_qspi_regs { #define STM32_QSPI_CR_SSHIFT BIT(4) #define STM32_QSPI_CR_DFM BIT(6) #define STM32_QSPI_CR_FSEL BIT(7) -#define STM32_QSPI_CR_FTHRES_MASK GENMASK(4, 0) -#define STM32_QSPI_CR_FTHRES_SHIFT (8) +#define STM32_QSPI_CR_FTHRES_SHIFT 8 #define STM32_QSPI_CR_TEIE BIT(16) #define STM32_QSPI_CR_TCIE BIT(17) #define STM32_QSPI_CR_FTIE BIT(18) @@ -55,16 +50,16 @@ struct stm32_qspi_regs { #define STM32_QSPI_CR_APMS BIT(22) #define STM32_QSPI_CR_PMM BIT(23) #define STM32_QSPI_CR_PRESCALER_MASK GENMASK(7, 0) -#define STM32_QSPI_CR_PRESCALER_SHIFT (24) +#define STM32_QSPI_CR_PRESCALER_SHIFT 24 /* * QUADSPI device configuration register */ #define STM32_QSPI_DCR_CKMODE BIT(0) #define STM32_QSPI_DCR_CSHT_MASK GENMASK(2, 0) -#define STM32_QSPI_DCR_CSHT_SHIFT (8) +#define STM32_QSPI_DCR_CSHT_SHIFT 8 #define STM32_QSPI_DCR_FSIZE_MASK GENMASK(4, 0) -#define STM32_QSPI_DCR_FSIZE_SHIFT (16) +#define STM32_QSPI_DCR_FSIZE_SHIFT 16 /* * QUADSPI status register @@ -75,8 +70,6 @@ struct stm32_qspi_regs { #define STM32_QSPI_SR_SMF BIT(3) #define STM32_QSPI_SR_TOF BIT(4) #define STM32_QSPI_SR_BUSY BIT(5) -#define STM32_QSPI_SR_FLEVEL_MASK GENMASK(5, 0) -#define STM32_QSPI_SR_FLEVEL_SHIFT (8) /* * QUADSPI flag clear register @@ -92,388 +85,276 @@ struct stm32_qspi_regs { #define STM32_QSPI_CCR_DDRM BIT(31) #define STM32_QSPI_CCR_DHHC BIT(30) #define STM32_QSPI_CCR_SIOO BIT(28) -#define STM32_QSPI_CCR_FMODE_SHIFT (26) -#define STM32_QSPI_CCR_DMODE_SHIFT (24) -#define STM32_QSPI_CCR_DCYC_SHIFT (18) -#define STM32_QSPI_CCR_DCYC_MASK GENMASK(4, 0) -#define STM32_QSPI_CCR_ABSIZE_SHIFT (16) -#define STM32_QSPI_CCR_ABMODE_SHIFT (14) -#define STM32_QSPI_CCR_ADSIZE_SHIFT (12) -#define STM32_QSPI_CCR_ADMODE_SHIFT (10) -#define STM32_QSPI_CCR_IMODE_SHIFT (8) -#define STM32_QSPI_CCR_INSTRUCTION_MASK GENMASK(7, 0) - -enum STM32_QSPI_CCR_IMODE { - STM32_QSPI_CCR_IMODE_NONE = 0, - STM32_QSPI_CCR_IMODE_ONE_LINE = 1, - STM32_QSPI_CCR_IMODE_TWO_LINE = 2, - STM32_QSPI_CCR_IMODE_FOUR_LINE = 3, -}; - -enum STM32_QSPI_CCR_ADMODE { - STM32_QSPI_CCR_ADMODE_NONE = 0, - STM32_QSPI_CCR_ADMODE_ONE_LINE = 1, - STM32_QSPI_CCR_ADMODE_TWO_LINE = 2, - STM32_QSPI_CCR_ADMODE_FOUR_LINE = 3, -}; - -enum STM32_QSPI_CCR_ADSIZE { - STM32_QSPI_CCR_ADSIZE_8BIT = 0, - STM32_QSPI_CCR_ADSIZE_16BIT = 1, - STM32_QSPI_CCR_ADSIZE_24BIT = 2, - STM32_QSPI_CCR_ADSIZE_32BIT = 3, -}; - -enum STM32_QSPI_CCR_ABMODE { - STM32_QSPI_CCR_ABMODE_NONE = 0, - STM32_QSPI_CCR_ABMODE_ONE_LINE = 1, - STM32_QSPI_CCR_ABMODE_TWO_LINE = 2, - STM32_QSPI_CCR_ABMODE_FOUR_LINE = 3, -}; - -enum STM32_QSPI_CCR_ABSIZE { - STM32_QSPI_CCR_ABSIZE_8BIT = 0, - STM32_QSPI_CCR_ABSIZE_16BIT = 1, - STM32_QSPI_CCR_ABSIZE_24BIT = 2, - STM32_QSPI_CCR_ABSIZE_32BIT = 3, -}; - -enum STM32_QSPI_CCR_DMODE { - STM32_QSPI_CCR_DMODE_NONE = 0, - STM32_QSPI_CCR_DMODE_ONE_LINE = 1, - STM32_QSPI_CCR_DMODE_TWO_LINE = 2, - STM32_QSPI_CCR_DMODE_FOUR_LINE = 3, -}; - -enum STM32_QSPI_CCR_FMODE { - STM32_QSPI_CCR_IND_WRITE = 0, - STM32_QSPI_CCR_IND_READ = 1, - STM32_QSPI_CCR_AUTO_POLL = 2, - STM32_QSPI_CCR_MEM_MAP = 3, -}; - -/* default SCK frequency, unit: HZ */ -#define STM32_QSPI_DEFAULT_SCK_FREQ 108000000 - -#define STM32_MAX_NORCHIP 2 - -struct stm32_qspi_platdata { - u32 base; - u32 memory_map; - u32 max_hz; +#define STM32_QSPI_CCR_FMODE_SHIFT 26 +#define STM32_QSPI_CCR_DMODE_SHIFT 24 +#define STM32_QSPI_CCR_DCYC_SHIFT 18 +#define STM32_QSPI_CCR_ABSIZE_SHIFT 16 +#define STM32_QSPI_CCR_ABMODE_SHIFT 14 +#define STM32_QSPI_CCR_ADSIZE_SHIFT 12 +#define STM32_QSPI_CCR_ADMODE_SHIFT 10 +#define STM32_QSPI_CCR_IMODE_SHIFT 8 + +#define STM32_QSPI_CCR_IND_WRITE 0 +#define STM32_QSPI_CCR_IND_READ 1 +#define STM32_QSPI_CCR_MEM_MAP 3 + +#define STM32_QSPI_MAX_MMAP_SZ SZ_256M +#define STM32_QSPI_MAX_CHIP 2 + +#define STM32_QSPI_FIFO_TIMEOUT_US 30000 +#define STM32_QSPI_CMD_TIMEOUT_US 1000000 +#define STM32_BUSY_TIMEOUT_US 100000 +#define STM32_ABT_TIMEOUT_US 100000 + +struct stm32_qspi_flash { + u32 cr; + u32 dcr; + bool initialized; }; struct stm32_qspi_priv { struct stm32_qspi_regs *regs; + struct stm32_qspi_flash flash[STM32_QSPI_MAX_CHIP]; + void __iomem *mm_base; + resource_size_t mm_size; ulong clock_rate; - u32 max_hz; - u32 mode; - - u32 command; - u32 address; - u32 dummycycles; -#define CMD_HAS_ADR BIT(24) -#define CMD_HAS_DUMMY BIT(25) -#define CMD_HAS_DATA BIT(26) + int cs_used; }; -static void _stm32_qspi_disable(struct stm32_qspi_priv *priv) +static int _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) { - clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} + u32 sr; + int ret; -static void _stm32_qspi_enable(struct stm32_qspi_priv *priv) -{ - setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} + ret = readl_poll_timeout(&priv->regs->sr, sr, + !(sr & STM32_QSPI_SR_BUSY), + STM32_BUSY_TIMEOUT_US); + if (ret) + pr_err("busy timeout (stat:%#x)\n", sr); -static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) -{ - while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) - ; + return ret; } -static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) +static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op) { - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF)) - ; -} + u32 sr; + int ret; -static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) -{ - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF)) - ; -} + if (!op->data.nbytes) + return _stm32_qspi_wait_for_not_busy(priv); -static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size) -{ - u32 fsize = fls(size) - 1; + ret = readl_poll_timeout(&priv->regs->sr, sr, + sr & STM32_QSPI_SR_TCF, + STM32_QSPI_CMD_TIMEOUT_US); + if (ret) { + pr_err("cmd timeout (stat:%#x)\n", sr); + } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { + pr_err("transfer error (stat:%#x)\n", sr); + ret = -EIO; + } - clrsetbits_le32(&priv->regs->dcr, - STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT, - fsize << STM32_QSPI_DCR_FSIZE_SHIFT); + /* clear flags */ + writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + + return ret; } -static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs) +static void _stm32_qspi_read_fifo(u8 *val, void __iomem *addr) { - clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, - cs ? STM32_QSPI_CR_FSEL : 0); + *val = readb(addr); } -static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) +static void _stm32_qspi_write_fifo(u8 *val, void __iomem *addr) { - unsigned int ccr_reg = 0; - u8 imode, admode, dmode; - u32 mode = priv->mode; - u32 cmd = (priv->command & STM32_QSPI_CCR_INSTRUCTION_MASK); - - imode = STM32_QSPI_CCR_IMODE_ONE_LINE; - admode = STM32_QSPI_CCR_ADMODE_ONE_LINE; - dmode = STM32_QSPI_CCR_DMODE_ONE_LINE; - - if ((priv->command & CMD_HAS_ADR) && (priv->command & CMD_HAS_DATA)) { - if (fmode == STM32_QSPI_CCR_IND_WRITE) { - if (mode & SPI_TX_QUAD) - dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE; - else if (mode & SPI_TX_DUAL) - dmode = STM32_QSPI_CCR_DMODE_TWO_LINE; - } else if ((fmode == STM32_QSPI_CCR_MEM_MAP) || - (fmode == STM32_QSPI_CCR_IND_READ)) { - if (mode & SPI_RX_QUAD) - dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE; - else if (mode & SPI_RX_DUAL) - dmode = STM32_QSPI_CCR_DMODE_TWO_LINE; - } - } - - if (priv->command & CMD_HAS_DATA) - ccr_reg |= (dmode << STM32_QSPI_CCR_DMODE_SHIFT); - - if (priv->command & CMD_HAS_DUMMY) - ccr_reg |= ((priv->dummycycles & STM32_QSPI_CCR_DCYC_MASK) - << STM32_QSPI_CCR_DCYC_SHIFT); - - if (priv->command & CMD_HAS_ADR) { - ccr_reg |= (STM32_QSPI_CCR_ADSIZE_24BIT - << STM32_QSPI_CCR_ADSIZE_SHIFT); - ccr_reg |= (admode << STM32_QSPI_CCR_ADMODE_SHIFT); - } - - ccr_reg |= (fmode << STM32_QSPI_CCR_FMODE_SHIFT); - ccr_reg |= (imode << STM32_QSPI_CCR_IMODE_SHIFT); - ccr_reg |= cmd; - - return ccr_reg; + writeb(*val, addr); } -static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv, - struct spi_flash *flash) +static int _stm32_qspi_poll(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op) { - unsigned int ccr_reg; + void (*fifo)(u8 *val, void __iomem *addr); + u32 len = op->data.nbytes, sr; + u8 *buf; + int ret; - priv->command = flash->read_opcode | CMD_HAS_ADR | CMD_HAS_DATA - | CMD_HAS_DUMMY; - priv->dummycycles = flash->read_dummy; + if (op->data.dir == SPI_MEM_DATA_IN) { + fifo = _stm32_qspi_read_fifo; + buf = op->data.buf.in; - ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_MEM_MAP); + } else { + fifo = _stm32_qspi_write_fifo; + buf = (u8 *)op->data.buf.out; + } - _stm32_qspi_wait_for_not_busy(priv); + while (len--) { + ret = readl_poll_timeout(&priv->regs->sr, sr, + sr & STM32_QSPI_SR_FTF, + STM32_QSPI_FIFO_TIMEOUT_US); + if (ret) { + pr_err("fifo timeout (len:%d stat:%#x)\n", len, sr); + return ret; + } - writel(ccr_reg, &priv->regs->ccr); + fifo(buf++, &priv->regs->dr); + } - priv->dummycycles = 0; + return 0; } -static void _stm32_qspi_disable_mmap(struct stm32_qspi_priv *priv) +static int stm32_qspi_mm(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op) { - setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); -} + memcpy_fromio(op->data.buf.in, priv->mm_base + op->addr.val, + op->data.nbytes); -static void _stm32_qspi_set_xfer_length(struct stm32_qspi_priv *priv, - u32 length) -{ - writel(length - 1, &priv->regs->dlr); + return 0; } -static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) +static int _stm32_qspi_tx(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op, + u8 mode) { - writel(cr_reg, &priv->regs->ccr); + if (!op->data.nbytes) + return 0; + + if (mode == STM32_QSPI_CCR_MEM_MAP) + return stm32_qspi_mm(priv, op); - if (priv->command & CMD_HAS_ADR) - writel(priv->address, &priv->regs->ar); + return _stm32_qspi_poll(priv, op); } -static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, - struct spi_flash *flash, unsigned int bitlen, - const u8 *dout, u8 *din, unsigned long flags) +static int _stm32_qspi_get_mode(u8 buswidth) { - unsigned int words = bitlen / 8; - u32 ccr_reg; - int i; + if (buswidth == 4) + return 3; - if (flags & SPI_XFER_MMAP) { - _stm32_qspi_enable_mmap(priv, flash); - return 0; - } else if (flags & SPI_XFER_MMAP_END) { - _stm32_qspi_disable_mmap(priv); - return 0; - } - - if (bitlen == 0) - return -1; + return buswidth; +} - if (bitlen % 8) { - debug("spi_xfer: Non byte aligned SPI transfer\n"); - return -1; - } +static int stm32_qspi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct stm32_qspi_priv *priv = dev_get_priv(slave->dev->parent); + u32 cr, ccr, addr_max; + u8 mode = STM32_QSPI_CCR_IND_WRITE; + int timeout, ret; + + debug("%s: cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", + __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + op->dummy.buswidth, op->data.buswidth, + op->addr.val, op->data.nbytes); + + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; - if (dout && din) { - debug("spi_xfer: QSPI cannot have data in and data out set\n"); - return -1; - } + addr_max = op->addr.val + op->data.nbytes + 1; - if (!dout && (flags & SPI_XFER_BEGIN)) { - debug("spi_xfer: QSPI transfer must begin with command\n"); - return -1; + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) { + if (addr_max < priv->mm_size && op->addr.buswidth) + mode = STM32_QSPI_CCR_MEM_MAP; + else + mode = STM32_QSPI_CCR_IND_READ; } - if (dout) { - if (flags & SPI_XFER_BEGIN) { - /* data is command */ - priv->command = dout[0] | CMD_HAS_DATA; - if (words >= 4) { - /* address is here too */ - priv->address = (dout[1] << 16) | - (dout[2] << 8) | dout[3]; - priv->command |= CMD_HAS_ADR; - } - - if (words > 4) { - /* rest is dummy bytes */ - priv->dummycycles = (words - 4) * 8; - priv->command |= CMD_HAS_DUMMY; - } - - if (flags & SPI_XFER_END) { - /* command without data */ - priv->command &= ~(CMD_HAS_DATA); - } - } - - if (flags & SPI_XFER_END) { - ccr_reg = _stm32_qspi_gen_ccr(priv, - STM32_QSPI_CCR_IND_WRITE); - - _stm32_qspi_wait_for_not_busy(priv); - - if (priv->command & CMD_HAS_DATA) - _stm32_qspi_set_xfer_length(priv, words); - - _stm32_qspi_start_xfer(priv, ccr_reg); - - debug("%s: write: ccr:0x%08x adr:0x%08x\n", - __func__, priv->regs->ccr, priv->regs->ar); - - if (priv->command & CMD_HAS_DATA) { - _stm32_qspi_wait_for_ftf(priv); - - debug("%s: words:%d data:", __func__, words); + if (op->data.nbytes) + writel(op->data.nbytes - 1, &priv->regs->dlr); - i = 0; - while (words > i) { - writeb(dout[i], &priv->regs->dr); - debug("%02x ", dout[i]); - i++; - } - debug("\n"); + ccr = (mode << STM32_QSPI_CCR_FMODE_SHIFT); + ccr |= op->cmd.opcode; + ccr |= (_stm32_qspi_get_mode(op->cmd.buswidth) + << STM32_QSPI_CCR_IMODE_SHIFT); - _stm32_qspi_wait_for_complete(priv); - } else { - _stm32_qspi_wait_for_not_busy(priv); - } - } - } else if (din) { - ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ); + if (op->addr.nbytes) { + ccr |= ((op->addr.nbytes - 1) << STM32_QSPI_CCR_ADSIZE_SHIFT); + ccr |= (_stm32_qspi_get_mode(op->addr.buswidth) + << STM32_QSPI_CCR_ADMODE_SHIFT); + } - _stm32_qspi_wait_for_not_busy(priv); + if (op->dummy.buswidth && op->dummy.nbytes) + ccr |= (op->dummy.nbytes * 8 / op->dummy.buswidth + << STM32_QSPI_CCR_DCYC_SHIFT); - _stm32_qspi_set_xfer_length(priv, words); + if (op->data.nbytes) + ccr |= (_stm32_qspi_get_mode(op->data.buswidth) + << STM32_QSPI_CCR_DMODE_SHIFT); - _stm32_qspi_start_xfer(priv, ccr_reg); + writel(ccr, &priv->regs->ccr); - debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, - priv->regs->ccr, priv->regs->ar, priv->regs->dlr); + if (op->addr.nbytes && mode != STM32_QSPI_CCR_MEM_MAP) + writel(op->addr.val, &priv->regs->ar); - debug("%s: data:", __func__); + ret = _stm32_qspi_tx(priv, op, mode); + /* + * Abort in: + * -error case + * -read memory map: prefetching must be stopped if we read the last + * byte of device (device size - fifo size). like device size is not + * knows, the prefetching is always stop. + */ + if (ret || mode == STM32_QSPI_CCR_MEM_MAP) + goto abort; - i = 0; - while (words > i) { - din[i] = readb(&priv->regs->dr); - debug("%02x ", din[i]); - i++; - } - debug("\n"); - } + /* Wait end of tx in indirect mode */ + ret = _stm32_qspi_wait_cmd(priv, op); + if (ret) + goto abort; return 0; -} - -static int stm32_qspi_ofdata_to_platdata(struct udevice *bus) -{ - struct resource res_regs, res_mem; - struct stm32_qspi_platdata *plat = bus->platdata; - int ret; - ret = dev_read_resource_byname(bus, "qspi", &res_regs); - if (ret) { - debug("Error: can't get regs base addresses(ret = %d)!\n", ret); - return -ENOMEM; - } - ret = dev_read_resource_byname(bus, "qspi_mm", &res_mem); - if (ret) { - debug("Error: can't get mmap base address(ret = %d)!\n", ret); - return -ENOMEM; - } +abort: + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); - plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency", - STM32_QSPI_DEFAULT_SCK_FREQ); + /* Wait clear of abort bit by hw */ + timeout = readl_poll_timeout(&priv->regs->cr, cr, + !(cr & STM32_QSPI_CR_ABORT), + STM32_ABT_TIMEOUT_US); - plat->base = res_regs.start; - plat->memory_map = res_mem.start; + writel(STM32_QSPI_FCR_CTCF, &priv->regs->fcr); - debug("%s: regs=<0x%x> mapped=<0x%x>, max-frequency=%d\n", - __func__, - plat->base, - plat->memory_map, - plat->max_hz - ); + if (ret || timeout) + pr_err("%s ret:%d abort timeout:%d\n", __func__, ret, timeout); - return 0; + return ret; } static int stm32_qspi_probe(struct udevice *bus) { - struct stm32_qspi_platdata *plat = dev_get_platdata(bus); struct stm32_qspi_priv *priv = dev_get_priv(bus); - struct dm_spi_bus *dm_spi_bus; + struct resource res; struct clk clk; struct reset_ctl reset_ctl; int ret; - dm_spi_bus = bus->uclass_priv; + ret = dev_read_resource_byname(bus, "qspi", &res); + if (ret) { + dev_err(bus, "can't get regs base addresses(ret = %d)!\n", ret); + return ret; + } - dm_spi_bus->max_hz = plat->max_hz; + priv->regs = (struct stm32_qspi_regs *)res.start; - priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; + ret = dev_read_resource_byname(bus, "qspi_mm", &res); + if (ret) { + dev_err(bus, "can't get mmap base address(ret = %d)!\n", ret); + return ret; + } - priv->max_hz = plat->max_hz; + priv->mm_base = (void __iomem *)res.start; + + priv->mm_size = resource_size(&res); + if (priv->mm_size > STM32_QSPI_MAX_MMAP_SZ) + return -EINVAL; + + debug("%s: regs=<0x%p> mapped=<0x%p> mapped_size=<0x%lx>\n", + __func__, priv->regs, priv->mm_base, priv->mm_size); ret = clk_get_by_index(bus, 0, &clk); if (ret < 0) return ret; ret = clk_enable(&clk); - if (ret) { dev_err(bus, "failed to enable clock\n"); return ret; @@ -499,78 +380,68 @@ static int stm32_qspi_probe(struct udevice *bus) reset_deassert(&reset_ctl); } + priv->cs_used = -1; + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); - return 0; -} + /* Set dcr fsize to max address */ + setbits_le32(&priv->regs->dcr, + STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT); -static int stm32_qspi_remove(struct udevice *bus) -{ return 0; } static int stm32_qspi_claim_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct spi_flash *flash; - struct dm_spi_slave_platdata *slave_plat; + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - bus = dev->parent; - priv = dev_get_priv(bus); - flash = dev_get_uclass_priv(dev); - slave_plat = dev_get_parent_platdata(dev); - - if (slave_plat->cs >= STM32_MAX_NORCHIP) + if (slave_plat->cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; - _stm32_qspi_set_cs(priv, slave_plat->cs); - - _stm32_qspi_set_flash_size(priv, flash->size); + if (priv->cs_used != slave_plat->cs) { + struct stm32_qspi_flash *flash = &priv->flash[slave_plat->cs]; - _stm32_qspi_enable(priv); + priv->cs_used = slave_plat->cs; - return 0; -} + if (flash->initialized) { + /* Set the configuration: speed + cs */ + writel(flash->cr, &priv->regs->cr); + writel(flash->dcr, &priv->regs->dcr); + } else { + /* Set chip select */ + clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, + priv->cs_used ? STM32_QSPI_CR_FSEL : 0); -static int stm32_qspi_release_bus(struct udevice *dev) -{ - struct stm32_qspi_priv *priv; - struct udevice *bus; + /* Save the configuration: speed + cs */ + flash->cr = readl(&priv->regs->cr); + flash->dcr = readl(&priv->regs->dcr); - bus = dev->parent; - priv = dev_get_priv(bus); + flash->initialized = true; + } + } - _stm32_qspi_disable(priv); + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); return 0; } -static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int stm32_qspi_release_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct spi_flash *flash; + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); - bus = dev->parent; - priv = dev_get_priv(bus); - flash = dev_get_uclass_priv(dev); + clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); - return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout, - (u8 *)din, flags); + return 0; } static int stm32_qspi_set_speed(struct udevice *bus, uint speed) { - struct stm32_qspi_platdata *plat = bus->platdata; struct stm32_qspi_priv *priv = dev_get_priv(bus); u32 qspi_clk = priv->clock_rate; u32 prescaler = 255; u32 csht; - - if (speed > plat->max_hz) - speed = plat->max_hz; + int ret; if (speed > 0) { prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; @@ -583,7 +454,9 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK; - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_PRESCALER_MASK << @@ -603,8 +476,11 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) static int stm32_qspi_set_mode(struct udevice *bus, uint mode) { struct stm32_qspi_priv *priv = dev_get_priv(bus); + int ret; - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); @@ -616,20 +492,6 @@ static int stm32_qspi_set_mode(struct udevice *bus, uint mode) if (mode & SPI_CS_HIGH) return -ENODEV; - if (mode & SPI_RX_QUAD) - priv->mode |= SPI_RX_QUAD; - else if (mode & SPI_RX_DUAL) - priv->mode |= SPI_RX_DUAL; - else - priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL); - - if (mode & SPI_TX_QUAD) - priv->mode |= SPI_TX_QUAD; - else if (mode & SPI_TX_DUAL) - priv->mode |= SPI_TX_DUAL; - else - priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL); - debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode); if (mode & SPI_RX_QUAD) @@ -649,12 +511,16 @@ static int stm32_qspi_set_mode(struct udevice *bus, uint mode) return 0; } +static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { + .exec_op = stm32_qspi_exec_op, +}; + static const struct dm_spi_ops stm32_qspi_ops = { .claim_bus = stm32_qspi_claim_bus, .release_bus = stm32_qspi_release_bus, - .xfer = stm32_qspi_xfer, .set_speed = stm32_qspi_set_speed, .set_mode = stm32_qspi_set_mode, + .mem_ops = &stm32_qspi_mem_ops, }; static const struct udevice_id stm32_qspi_ids[] = { @@ -664,13 +530,10 @@ static const struct udevice_id stm32_qspi_ids[] = { }; U_BOOT_DRIVER(stm32_qspi) = { - .name = "stm32_qspi", - .id = UCLASS_SPI, + .name = "stm32_qspi", + .id = UCLASS_SPI, .of_match = stm32_qspi_ids, - .ops = &stm32_qspi_ops, - .ofdata_to_platdata = stm32_qspi_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct stm32_qspi_platdata), + .ops = &stm32_qspi_ops, .priv_auto_alloc_size = sizeof(struct stm32_qspi_priv), - .probe = stm32_qspi_probe, - .remove = stm32_qspi_remove, + .probe = stm32_qspi_probe, }; -- cgit From 6899385f41ee43170c82dddc814323d2e2901a22 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 5 Apr 2019 11:41:49 +0200 Subject: dt-bindings: mtd: stm32_fmc2: add STM32 FMC2 NAND controller documentation This patch adds the documentation of the device tree bindings for the STM32 FMC2 NAND controller. Signed-off-by: Christophe Kerello Reviewed-by: Patrick DELAUNAY --- doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt diff --git a/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt b/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt new file mode 100644 index 0000000000..70e76be2a3 --- /dev/null +++ b/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt @@ -0,0 +1,59 @@ +STMicroelectronics Flexible Memory Controller 2 (FMC2) +NAND Interface + +Required properties: +- compatible: Should be one of: + * st,stm32mp15-fmc2 +- reg: NAND flash controller memory areas. + First region contains the register location. + Regions 2 to 4 respectively contain the data, command, + and address space for CS0. + Regions 5 to 7 contain the same areas for CS1. +- interrupts: The interrupt number +- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt) +- clocks: The clock needed by the NAND flash controller + +Optional properties: +- resets: Reference to a reset controller asserting the FMC controller +- dmas: DMA specifiers (see: dma/stm32-mdma.txt) +- dma-names: Must be "tx", "rx" and "ecc" + +Optional children nodes: +Children nodes represent the available NAND chips. + +Optional properties: +- nand-on-flash-bbt: see nand.txt +- nand-ecc-strength: see nand.txt +- nand-ecc-step-size: see nand.txt + +The following ECC strength and step size are currently supported: + - nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming) + - nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4) + - nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default) + +Example: + + fmc: nand-controller@58002000 { + compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, + <0x80000000 0x1000>, + <0x88010000 0x1000>, + <0x88020000 0x1000>, + <0x81000000 0x1000>, + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + pinctrl-names = "default"; + pinctrl-0 = <&fmc_pins_a>; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; + }; -- cgit From 7bb75023a720432a32840c6df543aae92653b23d Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 5 Apr 2019 11:41:50 +0200 Subject: mtd: rawnand: stm32_fmc2: add STM32 FMC2 NAND flash controller driver The driver adds the support for the STMicroelectronics FMC2 NAND Controller found on STM32MP SOCs. This patch adds the polling mode, a basic mode that do not need any DMA channels. Only NAND_ECC_HW mode is actually supported. The driver supports a maximum 8k page size. The following ECC strength and step size are currently supported: - nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) - nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4) - nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Extended ECC based on Hamming) This patch has been tested on Micron MT29F8G08ABACAH4. Signed-off-by: Christophe Kerello --- drivers/mtd/nand/raw/Kconfig | 11 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 1092 ++++++++++++++++++++++++++++++++ 3 files changed, 1104 insertions(+) create mode 100644 drivers/mtd/nand/raw/stm32_fmc2_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 7f76e5ecef..dc087ab641 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -256,6 +256,17 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS This flag prevent U-boot reconfigure NAND flash controller and reuse the NAND timing from 1st stage bootloader. +config NAND_STM32_FMC2 + bool "Support for NAND controller on STM32MP SoCs" + depends on ARCH_STM32MP + select SYS_NAND_SELF_INIT + imply CMD_NAND + help + Enables support for NAND Flash chips on SoCs containing the FMC2 + NAND controller. This controller is found on STM32MP SoCs. + The controller supports a maximum 8k page size and supports + a maximum 8-bit correction error per sector of 512 bytes. + comment "Generic NAND options" config SYS_NAND_BLOCK_SIZE diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index c61e3f3839..b10e718d15 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_PLAT) += nand_plat.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o +obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o else # minimal SPL drivers diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c new file mode 100644 index 0000000000..2bb749d7f7 --- /dev/null +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) STMicroelectronics 2019 + * Author: Christophe Kerello + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Bad block marker length */ +#define FMC2_BBM_LEN 2 + +/* ECC step size */ +#define FMC2_ECC_STEP_SIZE 512 + +/* Command delay */ +#define FMC2_RB_DELAY_US 30 + +/* Max chip enable */ +#define FMC2_MAX_CE 2 + +/* Timings */ +#define FMC2_THIZ 1 +#define FMC2_TIO 8000 +#define FMC2_TSYNC 3000 +#define FMC2_PCR_TIMING_MASK 0xf +#define FMC2_PMEM_PATT_TIMING_MASK 0xff + +/* FMC2 Controller Registers */ +#define FMC2_BCR1 0x0 +#define FMC2_PCR 0x80 +#define FMC2_SR 0x84 +#define FMC2_PMEM 0x88 +#define FMC2_PATT 0x8c +#define FMC2_HECCR 0x94 +#define FMC2_BCHISR 0x254 +#define FMC2_BCHICR 0x258 +#define FMC2_BCHPBR1 0x260 +#define FMC2_BCHPBR2 0x264 +#define FMC2_BCHPBR3 0x268 +#define FMC2_BCHPBR4 0x26c +#define FMC2_BCHDSR0 0x27c +#define FMC2_BCHDSR1 0x280 +#define FMC2_BCHDSR2 0x284 +#define FMC2_BCHDSR3 0x288 +#define FMC2_BCHDSR4 0x28c + +/* Register: FMC2_BCR1 */ +#define FMC2_BCR1_FMC2EN BIT(31) + +/* Register: FMC2_PCR */ +#define FMC2_PCR_PWAITEN BIT(1) +#define FMC2_PCR_PBKEN BIT(2) +#define FMC2_PCR_PWID_MASK GENMASK(5, 4) +#define FMC2_PCR_PWID(x) (((x) & 0x3) << 4) +#define FMC2_PCR_PWID_BUSWIDTH_8 0 +#define FMC2_PCR_PWID_BUSWIDTH_16 1 +#define FMC2_PCR_ECCEN BIT(6) +#define FMC2_PCR_ECCALG BIT(8) +#define FMC2_PCR_TCLR_MASK GENMASK(12, 9) +#define FMC2_PCR_TCLR(x) (((x) & 0xf) << 9) +#define FMC2_PCR_TCLR_DEFAULT 0xf +#define FMC2_PCR_TAR_MASK GENMASK(16, 13) +#define FMC2_PCR_TAR(x) (((x) & 0xf) << 13) +#define FMC2_PCR_TAR_DEFAULT 0xf +#define FMC2_PCR_ECCSS_MASK GENMASK(19, 17) +#define FMC2_PCR_ECCSS(x) (((x) & 0x7) << 17) +#define FMC2_PCR_ECCSS_512 1 +#define FMC2_PCR_ECCSS_2048 3 +#define FMC2_PCR_BCHECC BIT(24) +#define FMC2_PCR_WEN BIT(25) + +/* Register: FMC2_SR */ +#define FMC2_SR_NWRF BIT(6) + +/* Register: FMC2_PMEM */ +#define FMC2_PMEM_MEMSET(x) (((x) & 0xff) << 0) +#define FMC2_PMEM_MEMWAIT(x) (((x) & 0xff) << 8) +#define FMC2_PMEM_MEMHOLD(x) (((x) & 0xff) << 16) +#define FMC2_PMEM_MEMHIZ(x) (((x) & 0xff) << 24) +#define FMC2_PMEM_DEFAULT 0x0a0a0a0a + +/* Register: FMC2_PATT */ +#define FMC2_PATT_ATTSET(x) (((x) & 0xff) << 0) +#define FMC2_PATT_ATTWAIT(x) (((x) & 0xff) << 8) +#define FMC2_PATT_ATTHOLD(x) (((x) & 0xff) << 16) +#define FMC2_PATT_ATTHIZ(x) (((x) & 0xff) << 24) +#define FMC2_PATT_DEFAULT 0x0a0a0a0a + +/* Register: FMC2_BCHISR */ +#define FMC2_BCHISR_DERF BIT(1) +#define FMC2_BCHISR_EPBRF BIT(4) + +/* Register: FMC2_BCHICR */ +#define FMC2_BCHICR_CLEAR_IRQ GENMASK(4, 0) + +/* Register: FMC2_BCHDSR0 */ +#define FMC2_BCHDSR0_DUE BIT(0) +#define FMC2_BCHDSR0_DEF BIT(1) +#define FMC2_BCHDSR0_DEN_MASK GENMASK(7, 4) +#define FMC2_BCHDSR0_DEN_SHIFT 4 + +/* Register: FMC2_BCHDSR1 */ +#define FMC2_BCHDSR1_EBP1_MASK GENMASK(12, 0) +#define FMC2_BCHDSR1_EBP2_MASK GENMASK(28, 16) +#define FMC2_BCHDSR1_EBP2_SHIFT 16 + +/* Register: FMC2_BCHDSR2 */ +#define FMC2_BCHDSR2_EBP3_MASK GENMASK(12, 0) +#define FMC2_BCHDSR2_EBP4_MASK GENMASK(28, 16) +#define FMC2_BCHDSR2_EBP4_SHIFT 16 + +/* Register: FMC2_BCHDSR3 */ +#define FMC2_BCHDSR3_EBP5_MASK GENMASK(12, 0) +#define FMC2_BCHDSR3_EBP6_MASK GENMASK(28, 16) +#define FMC2_BCHDSR3_EBP6_SHIFT 16 + +/* Register: FMC2_BCHDSR4 */ +#define FMC2_BCHDSR4_EBP7_MASK GENMASK(12, 0) +#define FMC2_BCHDSR4_EBP8_MASK GENMASK(28, 16) +#define FMC2_BCHDSR4_EBP8_SHIFT 16 + +#define FMC2_NSEC_PER_SEC 1000000000L + +enum stm32_fmc2_ecc { + FMC2_ECC_HAM = 1, + FMC2_ECC_BCH4 = 4, + FMC2_ECC_BCH8 = 8 +}; + +struct stm32_fmc2_timings { + u8 tclr; + u8 tar; + u8 thiz; + u8 twait; + u8 thold_mem; + u8 tset_mem; + u8 thold_att; + u8 tset_att; +}; + +struct stm32_fmc2_nand { + struct nand_chip chip; + struct stm32_fmc2_timings timings; + int ncs; + int cs_used[FMC2_MAX_CE]; +}; + +static inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip) +{ + return container_of(chip, struct stm32_fmc2_nand, chip); +} + +struct stm32_fmc2_nfc { + struct nand_hw_control base; + struct stm32_fmc2_nand nand; + struct nand_ecclayout ecclayout; + void __iomem *io_base; + void __iomem *data_base[FMC2_MAX_CE]; + void __iomem *cmd_base[FMC2_MAX_CE]; + void __iomem *addr_base[FMC2_MAX_CE]; + struct clk clk; + + u8 cs_assigned; + int cs_sel; +}; + +static inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_hw_control *base) +{ + return container_of(base, struct stm32_fmc2_nfc, base); +} + +/* Timings configuration */ +static void stm32_fmc2_timings_init(struct nand_chip *chip) +{ + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct stm32_fmc2_timings *timings = &nand->timings; + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + u32 pmem, patt; + + /* Set tclr/tar timings */ + pcr &= ~FMC2_PCR_TCLR_MASK; + pcr |= FMC2_PCR_TCLR(timings->tclr); + pcr &= ~FMC2_PCR_TAR_MASK; + pcr |= FMC2_PCR_TAR(timings->tar); + + /* Set tset/twait/thold/thiz timings in common bank */ + pmem = FMC2_PMEM_MEMSET(timings->tset_mem); + pmem |= FMC2_PMEM_MEMWAIT(timings->twait); + pmem |= FMC2_PMEM_MEMHOLD(timings->thold_mem); + pmem |= FMC2_PMEM_MEMHIZ(timings->thiz); + + /* Set tset/twait/thold/thiz timings in attribut bank */ + patt = FMC2_PATT_ATTSET(timings->tset_att); + patt |= FMC2_PATT_ATTWAIT(timings->twait); + patt |= FMC2_PATT_ATTHOLD(timings->thold_att); + patt |= FMC2_PATT_ATTHIZ(timings->thiz); + + writel(pcr, fmc2->io_base + FMC2_PCR); + writel(pmem, fmc2->io_base + FMC2_PMEM); + writel(patt, fmc2->io_base + FMC2_PATT); +} + +/* Controller configuration */ +static void stm32_fmc2_setup(struct nand_chip *chip) +{ + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + + /* Configure ECC algorithm (default configuration is Hamming) */ + pcr &= ~FMC2_PCR_ECCALG; + pcr &= ~FMC2_PCR_BCHECC; + if (chip->ecc.strength == FMC2_ECC_BCH8) { + pcr |= FMC2_PCR_ECCALG; + pcr |= FMC2_PCR_BCHECC; + } else if (chip->ecc.strength == FMC2_ECC_BCH4) { + pcr |= FMC2_PCR_ECCALG; + } + + /* Set buswidth */ + pcr &= ~FMC2_PCR_PWID_MASK; + if (chip->options & NAND_BUSWIDTH_16) + pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); + + /* Set ECC sector size */ + pcr &= ~FMC2_PCR_ECCSS_MASK; + pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512); + + writel(pcr, fmc2->io_base + FMC2_PCR); +} + +/* Select target */ +static void stm32_fmc2_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + + if (chipnr < 0 || chipnr >= nand->ncs) + return; + + if (nand->cs_used[chipnr] == fmc2->cs_sel) + return; + + fmc2->cs_sel = nand->cs_used[chipnr]; + chip->IO_ADDR_R = fmc2->data_base[fmc2->cs_sel]; + chip->IO_ADDR_W = fmc2->data_base[fmc2->cs_sel]; + + /* FMC2 setup routine */ + stm32_fmc2_setup(chip); + + /* Apply timings */ + stm32_fmc2_timings_init(chip); +} + +/* Set bus width to 16-bit or 8-bit */ +static void stm32_fmc2_set_buswidth_16(struct stm32_fmc2_nfc *fmc2, bool set) +{ + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + + pcr &= ~FMC2_PCR_PWID_MASK; + if (set) + pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); + writel(pcr, fmc2->io_base + FMC2_PCR); +} + +/* Enable/disable ECC */ +static void stm32_fmc2_set_ecc(struct stm32_fmc2_nfc *fmc2, bool enable) +{ + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + + pcr &= ~FMC2_PCR_ECCEN; + if (enable) + pcr |= FMC2_PCR_ECCEN; + writel(pcr, fmc2->io_base + FMC2_PCR); +} + +/* Clear irq sources in case of bch is used */ +static inline void stm32_fmc2_clear_bch_irq(struct stm32_fmc2_nfc *fmc2) +{ + writel(FMC2_BCHICR_CLEAR_IRQ, fmc2->io_base + FMC2_BCHICR); +} + +/* Send command and address cycles */ +static void stm32_fmc2_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) { + writeb(cmd, fmc2->cmd_base[fmc2->cs_sel]); + return; + } + + writeb(cmd, fmc2->addr_base[fmc2->cs_sel]); +} + +/* + * Enable ECC logic and reset syndrome/parity bits previously calculated + * Syndrome/parity bits is cleared by setting the ECCEN bit to 0 + */ +static void stm32_fmc2_hwctl(struct mtd_info *mtd, int mode) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + + stm32_fmc2_set_ecc(fmc2, false); + + if (chip->ecc.strength != FMC2_ECC_HAM) { + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + + if (mode == NAND_ECC_WRITE) + pcr |= FMC2_PCR_WEN; + else + pcr &= ~FMC2_PCR_WEN; + writel(pcr, fmc2->io_base + FMC2_PCR); + + stm32_fmc2_clear_bch_irq(fmc2); + } + + stm32_fmc2_set_ecc(fmc2, true); +} + +/* + * ECC Hamming calculation + * ECC is 3 bytes for 512 bytes of data (supports error correction up to + * max of 1-bit) + */ +static int stm32_fmc2_ham_calculate(struct mtd_info *mtd, const u8 *data, + u8 *ecc) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + u32 heccr, sr; + int ret; + + ret = readl_poll_timeout(fmc2->io_base + FMC2_SR, sr, + sr & FMC2_SR_NWRF, 10000); + if (ret < 0) { + pr_err("Ham timeout\n"); + return ret; + } + + heccr = readl(fmc2->io_base + FMC2_HECCR); + + ecc[0] = heccr; + ecc[1] = heccr >> 8; + ecc[2] = heccr >> 16; + + /* Disable ecc */ + stm32_fmc2_set_ecc(fmc2, false); + + return 0; +} + +static int stm32_fmc2_ham_correct(struct mtd_info *mtd, u8 *dat, + u8 *read_ecc, u8 *calc_ecc) +{ + u8 bit_position = 0, b0, b1, b2; + u32 byte_addr = 0, b; + u32 i, shifting = 1; + + /* Indicate which bit and byte is faulty (if any) */ + b0 = read_ecc[0] ^ calc_ecc[0]; + b1 = read_ecc[1] ^ calc_ecc[1]; + b2 = read_ecc[2] ^ calc_ecc[2]; + b = b0 | (b1 << 8) | (b2 << 16); + + /* No errors */ + if (likely(!b)) + return 0; + + /* Calculate bit position */ + for (i = 0; i < 3; i++) { + switch (b % 4) { + case 2: + bit_position += shifting; + case 1: + break; + default: + return -EBADMSG; + } + shifting <<= 1; + b >>= 2; + } + + /* Calculate byte position */ + shifting = 1; + for (i = 0; i < 9; i++) { + switch (b % 4) { + case 2: + byte_addr += shifting; + case 1: + break; + default: + return -EBADMSG; + } + shifting <<= 1; + b >>= 2; + } + + /* Flip the bit */ + dat[byte_addr] ^= (1 << bit_position); + + return 1; +} + +/* + * ECC BCH calculation and correction + * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to + * max of 4-bit/8-bit) + */ + +static int stm32_fmc2_bch_calculate(struct mtd_info *mtd, const u8 *data, + u8 *ecc) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + u32 bchpbr, bchisr; + int ret; + + /* Wait until the BCH code is ready */ + ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr, + bchisr & FMC2_BCHISR_EPBRF, 10000); + if (ret < 0) { + pr_err("Bch timeout\n"); + return ret; + } + + /* Read parity bits */ + bchpbr = readl(fmc2->io_base + FMC2_BCHPBR1); + ecc[0] = bchpbr; + ecc[1] = bchpbr >> 8; + ecc[2] = bchpbr >> 16; + ecc[3] = bchpbr >> 24; + + bchpbr = readl(fmc2->io_base + FMC2_BCHPBR2); + ecc[4] = bchpbr; + ecc[5] = bchpbr >> 8; + ecc[6] = bchpbr >> 16; + + if (chip->ecc.strength == FMC2_ECC_BCH8) { + ecc[7] = bchpbr >> 24; + + bchpbr = readl(fmc2->io_base + FMC2_BCHPBR3); + ecc[8] = bchpbr; + ecc[9] = bchpbr >> 8; + ecc[10] = bchpbr >> 16; + ecc[11] = bchpbr >> 24; + + bchpbr = readl(fmc2->io_base + FMC2_BCHPBR4); + ecc[12] = bchpbr; + } + + /* Disable ecc */ + stm32_fmc2_set_ecc(fmc2, false); + + return 0; +} + +/* BCH algorithm correction */ +static int stm32_fmc2_bch_correct(struct mtd_info *mtd, u8 *dat, + u8 *read_ecc, u8 *calc_ecc) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + u32 bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4, bchisr; + u16 pos[8]; + int i, ret, den, eccsize = chip->ecc.size; + unsigned int nb_errs = 0; + + /* Wait until the decoding error is ready */ + ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr, + bchisr & FMC2_BCHISR_DERF, 10000); + if (ret < 0) { + pr_err("Bch timeout\n"); + return ret; + } + + bchdsr0 = readl(fmc2->io_base + FMC2_BCHDSR0); + bchdsr1 = readl(fmc2->io_base + FMC2_BCHDSR1); + bchdsr2 = readl(fmc2->io_base + FMC2_BCHDSR2); + bchdsr3 = readl(fmc2->io_base + FMC2_BCHDSR3); + bchdsr4 = readl(fmc2->io_base + FMC2_BCHDSR4); + + /* Disable ECC */ + stm32_fmc2_set_ecc(fmc2, false); + + /* No errors found */ + if (likely(!(bchdsr0 & FMC2_BCHDSR0_DEF))) + return 0; + + /* Too many errors detected */ + if (unlikely(bchdsr0 & FMC2_BCHDSR0_DUE)) + return -EBADMSG; + + pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK; + pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT; + pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK; + pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT; + pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK; + pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT; + pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK; + pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT; + + den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT; + for (i = 0; i < den; i++) { + if (pos[i] < eccsize * 8) { + __change_bit(pos[i], (unsigned long *)dat); + nb_errs++; + } + } + + return nb_errs; +} + +static int stm32_fmc2_read_page(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + int i, s, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + int eccstrength = chip->ecc.strength; + u8 *p = buf; + u8 *ecc_calc = chip->buffers->ecccalc; + u8 *ecc_code = chip->buffers->ecccode; + unsigned int max_bitflips = 0; + + for (i = mtd->writesize + FMC2_BBM_LEN, s = 0; s < eccsteps; + s++, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(mtd, NAND_ECC_READ); + + /* Read the nand page sector (512 bytes) */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, s * eccsize, -1); + chip->read_buf(mtd, p, eccsize); + + /* Read the corresponding ECC bytes */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i, -1); + chip->read_buf(mtd, ecc_code, eccbytes); + + /* Correct the data */ + stat = chip->ecc.correct(mtd, p, ecc_code, ecc_calc); + if (stat == -EBADMSG) + /* Check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + ecc_code, eccbytes, + NULL, 0, + eccstrength); + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + + /* Read oob */ + if (oob_required) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + } + + return max_bitflips; +} + +/* Controller initialization */ +static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2) +{ + u32 pcr = readl(fmc2->io_base + FMC2_PCR); + u32 bcr1 = readl(fmc2->io_base + FMC2_BCR1); + + /* Set CS used to undefined */ + fmc2->cs_sel = -1; + + /* Enable wait feature and nand flash memory bank */ + pcr |= FMC2_PCR_PWAITEN; + pcr |= FMC2_PCR_PBKEN; + + /* Set buswidth to 8 bits mode for identification */ + pcr &= ~FMC2_PCR_PWID_MASK; + + /* ECC logic is disabled */ + pcr &= ~FMC2_PCR_ECCEN; + + /* Default mode */ + pcr &= ~FMC2_PCR_ECCALG; + pcr &= ~FMC2_PCR_BCHECC; + pcr &= ~FMC2_PCR_WEN; + + /* Set default ECC sector size */ + pcr &= ~FMC2_PCR_ECCSS_MASK; + pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048); + + /* Set default tclr/tar timings */ + pcr &= ~FMC2_PCR_TCLR_MASK; + pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT); + pcr &= ~FMC2_PCR_TAR_MASK; + pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT); + + /* Enable FMC2 controller */ + bcr1 |= FMC2_BCR1_FMC2EN; + + writel(bcr1, fmc2->io_base + FMC2_BCR1); + writel(pcr, fmc2->io_base + FMC2_PCR); + writel(FMC2_PMEM_DEFAULT, fmc2->io_base + FMC2_PMEM); + writel(FMC2_PATT_DEFAULT, fmc2->io_base + FMC2_PATT); +} + +/* Controller timings */ +static void stm32_fmc2_calc_timings(struct nand_chip *chip, + const struct nand_sdr_timings *sdrt) +{ + struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct stm32_fmc2_timings *tims = &nand->timings; + unsigned long hclk = clk_get_rate(&fmc2->clk); + unsigned long hclkp = FMC2_NSEC_PER_SEC / (hclk / 1000); + int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; + + tar = hclkp; + if (tar < sdrt->tAR_min) + tar = sdrt->tAR_min; + tims->tar = DIV_ROUND_UP(tar, hclkp) - 1; + if (tims->tar > FMC2_PCR_TIMING_MASK) + tims->tar = FMC2_PCR_TIMING_MASK; + + tclr = hclkp; + if (tclr < sdrt->tCLR_min) + tclr = sdrt->tCLR_min; + tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1; + if (tims->tclr > FMC2_PCR_TIMING_MASK) + tims->tclr = FMC2_PCR_TIMING_MASK; + + tims->thiz = FMC2_THIZ; + thiz = (tims->thiz + 1) * hclkp; + + /* + * tWAIT > tRP + * tWAIT > tWP + * tWAIT > tREA + tIO + */ + twait = hclkp; + if (twait < sdrt->tRP_min) + twait = sdrt->tRP_min; + if (twait < sdrt->tWP_min) + twait = sdrt->tWP_min; + if (twait < sdrt->tREA_max + FMC2_TIO) + twait = sdrt->tREA_max + FMC2_TIO; + tims->twait = DIV_ROUND_UP(twait, hclkp); + if (tims->twait == 0) + tims->twait = 1; + else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK) + tims->twait = FMC2_PMEM_PATT_TIMING_MASK; + + /* + * tSETUP_MEM > tCS - tWAIT + * tSETUP_MEM > tALS - tWAIT + * tSETUP_MEM > tDS - (tWAIT - tHIZ) + */ + tset_mem = hclkp; + if (sdrt->tCS_min > twait && (tset_mem < sdrt->tCS_min - twait)) + tset_mem = sdrt->tCS_min - twait; + if (sdrt->tALS_min > twait && (tset_mem < sdrt->tALS_min - twait)) + tset_mem = sdrt->tALS_min - twait; + if (twait > thiz && (sdrt->tDS_min > twait - thiz) && + (tset_mem < sdrt->tDS_min - (twait - thiz))) + tset_mem = sdrt->tDS_min - (twait - thiz); + tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp); + if (tims->tset_mem == 0) + tims->tset_mem = 1; + else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK) + tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK; + + /* + * tHOLD_MEM > tCH + * tHOLD_MEM > tREH - tSETUP_MEM + * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) + */ + thold_mem = hclkp; + if (thold_mem < sdrt->tCH_min) + thold_mem = sdrt->tCH_min; + if (sdrt->tREH_min > tset_mem && + (thold_mem < sdrt->tREH_min - tset_mem)) + thold_mem = sdrt->tREH_min - tset_mem; + if ((sdrt->tRC_min > tset_mem + twait) && + (thold_mem < sdrt->tRC_min - (tset_mem + twait))) + thold_mem = sdrt->tRC_min - (tset_mem + twait); + if ((sdrt->tWC_min > tset_mem + twait) && + (thold_mem < sdrt->tWC_min - (tset_mem + twait))) + thold_mem = sdrt->tWC_min - (tset_mem + twait); + tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp); + if (tims->thold_mem == 0) + tims->thold_mem = 1; + else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK) + tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK; + + /* + * tSETUP_ATT > tCS - tWAIT + * tSETUP_ATT > tCLS - tWAIT + * tSETUP_ATT > tALS - tWAIT + * tSETUP_ATT > tRHW - tHOLD_MEM + * tSETUP_ATT > tDS - (tWAIT - tHIZ) + */ + tset_att = hclkp; + if (sdrt->tCS_min > twait && (tset_att < sdrt->tCS_min - twait)) + tset_att = sdrt->tCS_min - twait; + if (sdrt->tCLS_min > twait && (tset_att < sdrt->tCLS_min - twait)) + tset_att = sdrt->tCLS_min - twait; + if (sdrt->tALS_min > twait && (tset_att < sdrt->tALS_min - twait)) + tset_att = sdrt->tALS_min - twait; + if (sdrt->tRHW_min > thold_mem && + (tset_att < sdrt->tRHW_min - thold_mem)) + tset_att = sdrt->tRHW_min - thold_mem; + if (twait > thiz && (sdrt->tDS_min > twait - thiz) && + (tset_att < sdrt->tDS_min - (twait - thiz))) + tset_att = sdrt->tDS_min - (twait - thiz); + tims->tset_att = DIV_ROUND_UP(tset_att, hclkp); + if (tims->tset_att == 0) + tims->tset_att = 1; + else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK) + tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK; + + /* + * tHOLD_ATT > tALH + * tHOLD_ATT > tCH + * tHOLD_ATT > tCLH + * tHOLD_ATT > tCOH + * tHOLD_ATT > tDH + * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM + * tHOLD_ATT > tADL - tSETUP_MEM + * tHOLD_ATT > tWH - tSETUP_MEM + * tHOLD_ATT > tWHR - tSETUP_MEM + * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) + * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) + */ + thold_att = hclkp; + if (thold_att < sdrt->tALH_min) + thold_att = sdrt->tALH_min; + if (thold_att < sdrt->tCH_min) + thold_att = sdrt->tCH_min; + if (thold_att < sdrt->tCLH_min) + thold_att = sdrt->tCLH_min; + if (thold_att < sdrt->tCOH_min) + thold_att = sdrt->tCOH_min; + if (thold_att < sdrt->tDH_min) + thold_att = sdrt->tDH_min; + if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && + (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) + thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; + if (sdrt->tADL_min > tset_mem && + (thold_att < sdrt->tADL_min - tset_mem)) + thold_att = sdrt->tADL_min - tset_mem; + if (sdrt->tWH_min > tset_mem && + (thold_att < sdrt->tWH_min - tset_mem)) + thold_att = sdrt->tWH_min - tset_mem; + if (sdrt->tWHR_min > tset_mem && + (thold_att < sdrt->tWHR_min - tset_mem)) + thold_att = sdrt->tWHR_min - tset_mem; + if ((sdrt->tRC_min > tset_att + twait) && + (thold_att < sdrt->tRC_min - (tset_att + twait))) + thold_att = sdrt->tRC_min - (tset_att + twait); + if ((sdrt->tWC_min > tset_att + twait) && + (thold_att < sdrt->tWC_min - (tset_att + twait))) + thold_att = sdrt->tWC_min - (tset_att + twait); + tims->thold_att = DIV_ROUND_UP(thold_att, hclkp); + if (tims->thold_att == 0) + tims->thold_att = 1; + else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK) + tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK; +} + +static int stm32_fmc2_setup_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + const struct nand_sdr_timings *sdrt; + + sdrt = nand_get_sdr_timings(conf); + if (IS_ERR(sdrt)) + return PTR_ERR(sdrt); + + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + + stm32_fmc2_calc_timings(chip, sdrt); + + /* Apply timings */ + stm32_fmc2_timings_init(chip); + + return 0; +} + +/* NAND callbacks setup */ +static void stm32_fmc2_nand_callbacks_setup(struct nand_chip *chip) +{ + chip->ecc.hwctl = stm32_fmc2_hwctl; + + /* + * Specific callbacks to read/write a page depending on + * the algo used (Hamming, BCH). + */ + if (chip->ecc.strength == FMC2_ECC_HAM) { + /* Hamming is used */ + chip->ecc.calculate = stm32_fmc2_ham_calculate; + chip->ecc.correct = stm32_fmc2_ham_correct; + chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3; + chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK; + return; + } + + /* BCH is used */ + chip->ecc.read_page = stm32_fmc2_read_page; + chip->ecc.calculate = stm32_fmc2_bch_calculate; + chip->ecc.correct = stm32_fmc2_bch_correct; + + if (chip->ecc.strength == FMC2_ECC_BCH8) + chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 14 : 13; + else + chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7; +} + +/* FMC2 caps */ +static int stm32_fmc2_calc_ecc_bytes(int step_size, int strength) +{ + /* Hamming */ + if (strength == FMC2_ECC_HAM) + return 4; + + /* BCH8 */ + if (strength == FMC2_ECC_BCH8) + return 14; + + /* BCH4 */ + return 8; +} + +NAND_ECC_CAPS_SINGLE(stm32_fmc2_ecc_caps, stm32_fmc2_calc_ecc_bytes, + FMC2_ECC_STEP_SIZE, + FMC2_ECC_HAM, FMC2_ECC_BCH4, FMC2_ECC_BCH8); + +/* FMC2 probe */ +static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2, + ofnode node) +{ + struct stm32_fmc2_nand *nand = &fmc2->nand; + u32 cs[FMC2_MAX_CE]; + int ret, i; + + if (!ofnode_get_property(node, "reg", &nand->ncs)) + return -EINVAL; + + nand->ncs /= sizeof(u32); + if (!nand->ncs) { + pr_err("Invalid reg property size\n"); + return -EINVAL; + } + + ret = ofnode_read_u32_array(node, "reg", cs, nand->ncs); + if (ret < 0) { + pr_err("Could not retrieve reg property\n"); + return -EINVAL; + } + + for (i = 0; i < nand->ncs; i++) { + if (cs[i] > FMC2_MAX_CE) { + pr_err("Invalid reg value: %d\n", + nand->cs_used[i]); + return -EINVAL; + } + + if (fmc2->cs_assigned & BIT(cs[i])) { + pr_err("Cs already assigned: %d\n", + nand->cs_used[i]); + return -EINVAL; + } + + fmc2->cs_assigned |= BIT(cs[i]); + nand->cs_used[i] = cs[i]; + } + + nand->chip.flash_node = ofnode_to_offset(node); + + return 0; +} + +static int stm32_fmc2_parse_dt(struct udevice *dev, + struct stm32_fmc2_nfc *fmc2) +{ + ofnode child; + int ret, nchips = 0; + + dev_for_each_subnode(child, dev) + nchips++; + + if (!nchips) { + pr_err("NAND chip not defined\n"); + return -EINVAL; + } + + if (nchips > 1) { + pr_err("Too many NAND chips defined\n"); + return -EINVAL; + } + + dev_for_each_subnode(child, dev) { + ret = stm32_fmc2_parse_child(fmc2, child); + if (ret) + return ret; + } + + return 0; +} + +static int stm32_fmc2_probe(struct udevice *dev) +{ + struct stm32_fmc2_nfc *fmc2 = dev_get_priv(dev); + struct stm32_fmc2_nand *nand = &fmc2->nand; + struct nand_chip *chip = &nand->chip; + struct mtd_info *mtd = &chip->mtd; + struct nand_ecclayout *ecclayout; + struct resource resource; + struct reset_ctl reset; + int oob_index, chip_cs, mem_region, ret, i; + + spin_lock_init(&fmc2->controller.lock); + init_waitqueue_head(&fmc2->controller.wq); + + ret = stm32_fmc2_parse_dt(dev, fmc2); + if (ret) + return ret; + + /* Get resources */ + ret = dev_read_resource(dev, 0, &resource); + if (ret) { + pr_err("Resource io_base not found"); + return ret; + } + fmc2->io_base = (void __iomem *)resource.start; + + for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE; + chip_cs++, mem_region += 3) { + if (!(fmc2->cs_assigned & BIT(chip_cs))) + continue; + + ret = dev_read_resource(dev, mem_region, &resource); + if (ret) { + pr_err("Resource data_base not found for cs%d", + chip_cs); + return ret; + } + fmc2->data_base[chip_cs] = (void __iomem *)resource.start; + + ret = dev_read_resource(dev, mem_region + 1, &resource); + if (ret) { + pr_err("Resource cmd_base not found for cs%d", + chip_cs); + return ret; + } + fmc2->cmd_base[chip_cs] = (void __iomem *)resource.start; + + ret = dev_read_resource(dev, mem_region + 2, &resource); + if (ret) { + pr_err("Resource addr_base not found for cs%d", + chip_cs); + return ret; + } + fmc2->addr_base[chip_cs] = (void __iomem *)resource.start; + } + + /* Enable the clock */ + ret = clk_get_by_index(dev, 0, &fmc2->clk); + if (ret) + return ret; + + ret = clk_enable(&fmc2->clk); + if (ret) + return ret; + + /* Reset */ + ret = reset_get_by_index(dev, 0, &reset); + if (!ret) { + reset_assert(&reset); + udelay(2); + reset_deassert(&reset); + } + + /* FMC2 init routine */ + stm32_fmc2_init(fmc2); + + chip->controller = &fmc2->base; + chip->select_chip = stm32_fmc2_select_chip; + chip->setup_data_interface = stm32_fmc2_setup_interface; + chip->cmd_ctrl = stm32_fmc2_cmd_ctrl; + chip->chip_delay = FMC2_RB_DELAY_US; + chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE | + NAND_USE_BOUNCE_BUFFER; + + /* Default ECC settings */ + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = FMC2_ECC_STEP_SIZE; + chip->ecc.strength = FMC2_ECC_BCH8; + + /* Scan to find existence of the device */ + ret = nand_scan_ident(mtd, nand->ncs, NULL); + if (ret) + return ret; + + /* + * Only NAND_ECC_HW mode is actually supported + * Hamming => ecc.strength = 1 + * BCH4 => ecc.strength = 4 + * BCH8 => ecc.strength = 8 + * ECC sector size = 512 + */ + if (chip->ecc.mode != NAND_ECC_HW) { + pr_err("Nand_ecc_mode is not well defined in the DT\n"); + return -EINVAL; + } + + ret = nand_check_ecc_caps(chip, &stm32_fmc2_ecc_caps, + mtd->oobsize - FMC2_BBM_LEN); + if (ret) { + pr_err("No valid ECC settings set\n"); + return ret; + } + + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->bbt_options |= NAND_BBT_NO_OOB; + + /* NAND callbacks setup */ + stm32_fmc2_nand_callbacks_setup(chip); + + /* Define ECC layout */ + ecclayout = &fmc2->ecclayout; + ecclayout->eccbytes = chip->ecc.bytes * + (mtd->writesize / chip->ecc.size); + oob_index = FMC2_BBM_LEN; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + ecclayout->oobfree->offset = oob_index; + ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; + chip->ecc.layout = ecclayout; + + /* Configure bus width to 16-bit */ + if (chip->options & NAND_BUSWIDTH_16) + stm32_fmc2_set_buswidth_16(fmc2, true); + + /* Scan the device to fill MTD data-structures */ + ret = nand_scan_tail(mtd); + if (ret) + return ret; + + return nand_register(0, mtd); +} + +static const struct udevice_id stm32_fmc2_match[] = { + { .compatible = "st,stm32mp15-fmc2" }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(stm32_fmc2_nand) = { + .name = "stm32_fmc2_nand", + .id = UCLASS_MTD, + .of_match = stm32_fmc2_match, + .probe = stm32_fmc2_probe, + .priv_auto_alloc_size = sizeof(struct stm32_fmc2_nfc), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(stm32_fmc2_nand), + &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize STM32 FMC2 NAND controller. (error %d)\n", + ret); +} -- cgit