From 7ce4f1fad28e538d216065b5042f6f20a5f50a90 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 22 Feb 2022 17:38:49 +0100 Subject: [PATCH 01/11] mtd: rawnand: stm32_fmc2: add NAND Write Protect support This patch adds the support of the WP# signal. WP will be disabled before the first access to the NAND flash. Signed-off-by: Christophe Kerello Reviewed-by: Patrice Chotard --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index eee65949d7..fb3279b405 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -149,6 +150,7 @@ struct stm32_fmc2_timings { struct stm32_fmc2_nand { struct nand_chip chip; struct stm32_fmc2_timings timings; + struct gpio_desc wp_gpio; int ncs; int cs_used[FMC2_MAX_CE]; }; @@ -824,6 +826,9 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, ofnode node) nand->cs_used[i] = cs[i]; } + gpio_request_by_name_nodev(node, "wp-gpios", 0, &nand->wp_gpio, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + nand->chip.flash_node = node; return 0; @@ -972,6 +977,10 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev) chip->ecc.size = FMC2_ECC_STEP_SIZE; chip->ecc.strength = FMC2_ECC_BCH8; + /* Disable Write Protect */ + if (dm_gpio_is_valid(&nand->wp_gpio)) + dm_gpio_set_value(&nand->wp_gpio, 0); + ret = nand_scan_ident(mtd, nand->ncs, NULL); if (ret) return ret; From 0c20f53b3ff93d261a546601ad7190edf62f534b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 15 Feb 2022 16:08:50 +0100 Subject: [PATCH 02/11] stm32mp: bsec: add permanent lock write support Add support of the permanent lock support in U-Boot proper when BSEC is not managed by secure monitor (TF-A SP_MIN or OP-TEE). This patch avoid issue with stm32key command and fuse command on basic boot for this missing feature of U-Boot BSEC driver. Reported-by: Johann Neuhauser Signed-off-by: Patrick Delaunay Tested-by: Johann Neuhauser Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 90 +++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 27d1829501..fd6e1a3957 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -18,6 +18,7 @@ #include #define BSEC_OTP_MAX_VALUE 95 +#define BSEC_OTP_UPPER_START 32 #define BSEC_TIMEOUT_US 10000 /* BSEC REGISTER OFFSET (base relative) */ @@ -41,6 +42,7 @@ /* BSEC_CONTROL Register */ #define BSEC_READ 0x000 #define BSEC_WRITE 0x100 +#define BSEC_LOCK 0x200 /* LOCK Register */ #define OTP_LOCK_MASK 0x1F @@ -61,6 +63,11 @@ */ #define BSEC_LOCK_PROGRAM 0x04 +/* + * OTP status: bit 0 permanent lock + */ +#define BSEC_LOCK_PERM BIT(0) + /** * bsec_lock() - manage lock for each type SR/SP/SW * @address: address of bsec IP register @@ -284,6 +291,65 @@ static int bsec_program_otp(struct udevice *dev, long base, u32 val, u32 otp) return ret; } +/** + * bsec_permanent_lock_otp() - permanent lock of OTP in SAFMEM + * @dev: bsec IP device + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_permanent_lock_otp(struct udevice *dev, long base, uint32_t otp) +{ + int ret; + bool power_up = false; + u32 val, addr; + + /* check if safemem is power up */ + if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + + power_up = true; + } + + /* + * low OTPs = 2 bits word for low OTPs, 1 bits per word for upper OTP + * and only 16 bits used in WRDATA + */ + if (otp < BSEC_OTP_UPPER_START) { + addr = otp / 8; + val = 0x03 << ((otp * 2) & 0xF); + } else { + addr = BSEC_OTP_UPPER_START / 8 + + ((otp - BSEC_OTP_UPPER_START) / 16); + val = 0x01 << (otp & 0xF); + } + + /* set value in write register*/ + writel(val, base + BSEC_OTP_WRDATA_OFF); + + /* set BSEC_OTP_CTRL_OFF with the otp addr and lock request*/ + writel(addr | BSEC_WRITE | BSEC_LOCK, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + if (val & BSEC_MODE_PROGFAIL_MASK) + ret = -EACCES; + else + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + /* BSEC MISC driver *******************************************************/ struct stm32mp_bsec_plat { u32 base; @@ -339,9 +405,14 @@ static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp) { struct stm32mp_bsec_plat *plat = dev_get_plat(dev); + u32 wrlock; /* return OTP permanent write lock status */ - *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp); + wrlock = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp); + + *val = 0; + if (wrlock) + *val = BSEC_LOCK_PERM; return 0; } @@ -377,15 +448,22 @@ static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp) static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp) { - if (!IS_ENABLED(CONFIG_ARM_SMCCC) || IS_ENABLED(CONFIG_SPL_BUILD)) - return -ENOTSUPP; + struct stm32mp_bsec_plat *plat; - if (val == 1) + /* only permanent write lock is supported in U-Boot */ + if (!(val & BSEC_LOCK_PERM)) { + dev_dbg(dev, "lock option without BSEC_LOCK_PERM: %x\n", val); + return 0; /* nothing to do */ + } + + if (IS_ENABLED(CONFIG_ARM_SMCCC) && !IS_ENABLED(CONFIG_SPL_BUILD)) return stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_WRLOCK_OTP, otp, 0); - if (val == 0) - return 0; /* nothing to do */ + + plat = dev_get_plat(dev); + + return bsec_permanent_lock_otp(dev, plat->base, otp); return -EINVAL; } From 2d48d99c4a90750b80438314bae20499b4ce6705 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 15 Feb 2022 16:08:51 +0100 Subject: [PATCH 03/11] stm32mp1: bsec: add missing dev in function comment Add the missing @dev reference in some function description. Fixes: b66bfdf238b9 ("arm: stm32mp: bsec: migrate trace to log macro") Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/bsec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index fd6e1a3957..506caa0a31 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -167,6 +167,7 @@ static int bsec_power_safmem(u32 base, bool power) /** * bsec_shadow_register() - copy safmen otp to bsec data + * @dev: bsec IP device * @base: base address of bsec IP * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) * Return: 0 if no error @@ -210,6 +211,7 @@ static int bsec_shadow_register(struct udevice *dev, u32 base, u32 otp) /** * bsec_read_shadow() - read an otp data value from shadow + * @dev: bsec IP device * @base: base address of bsec IP * @val: read value * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) @@ -224,6 +226,7 @@ static int bsec_read_shadow(struct udevice *dev, u32 base, u32 *val, u32 otp) /** * bsec_write_shadow() - write value in BSEC data register in shadow + * @dev: bsec IP device * @base: base address of bsec IP * @val: value to write * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) @@ -242,6 +245,7 @@ static int bsec_write_shadow(struct udevice *dev, u32 base, u32 val, u32 otp) /** * bsec_program_otp() - program a bit in SAFMEM + * @dev: bsec IP device * @base: base address of bsec IP * @val: value to program * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) From 6ed21f3d704370d5b1a5db8ee953fd7c5cea08d6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 1 Feb 2022 14:37:19 +0100 Subject: [PATCH 04/11] board: st: common: update test on misc_read result in command stboard Update management of misc_read/misc_write, which now returns length of data after the commit 8729b1ae2cbd ("misc: Update read() and write() methods to return bytes xfered"): raise a error when the result is not the expected length. Fixes: 658fde8a36ff ("board: stm32mp1: stboard: lock the OTP after programming") Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/st/common/cmd_stboard.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/board/st/common/cmd_stboard.c b/board/st/common/cmd_stboard.c index 2fba383168..c1ecd643b0 100644 --- a/board/st/common/cmd_stboard.c +++ b/board/st/common/cmd_stboard.c @@ -91,14 +91,14 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc, ret = misc_read(dev, STM32_BSEC_OTP(BSEC_OTP_BOARD), &otp, sizeof(otp)); - if (ret < 0) { + if (ret != sizeof(otp)) { puts("OTP read error"); return CMD_RET_FAILURE; } ret = misc_read(dev, STM32_BSEC_LOCK(BSEC_OTP_BOARD), &lock, sizeof(lock)); - if (ret < 0) { + if (ret != sizeof(lock)) { puts("LOCK read error"); return CMD_RET_FAILURE; } @@ -172,7 +172,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc, ret = misc_write(dev, STM32_BSEC_OTP(BSEC_OTP_BOARD), &otp, sizeof(otp)); - if (ret < 0) { + if (ret != sizeof(otp)) { puts("BOARD programming error\n"); return CMD_RET_FAILURE; } @@ -181,7 +181,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc, otp = 1; ret = misc_write(dev, STM32_BSEC_LOCK(BSEC_OTP_BOARD), &otp, sizeof(otp)); - if (ret < 0) { + if (ret != sizeof(otp)) { puts("BOARD lock error\n"); return CMD_RET_FAILURE; } From 310ef93028014914efd9c5a210443b378670f5e3 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Tue, 1 Feb 2022 14:02:14 +0100 Subject: [PATCH 05/11] video: stm32: stm32_ltdc: fix the check of return value of clk_set_rate() The clk_set_rate() function returns rate as an 'ulong' not an 'int' and rate > 0 by default. This patch avoids to display the associated warning when the set rate function returns the new frequency. Fixes: aeaf330649e8 ("video: stm32: stm32_ltdc: add bridge to display controller") Signed-off-by: Gabriel Fernandez Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/video/stm32/stm32_ltdc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 87e5fd54d9..e741e74739 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -338,6 +338,7 @@ static int stm32_ltdc_probe(struct udevice *dev) struct display_timing timings; struct clk pclk; struct reset_ctl rst; + ulong rate; int ret; priv->regs = (void *)dev_read_addr(dev); @@ -375,13 +376,13 @@ static int stm32_ltdc_probe(struct udevice *dev) } } - ret = clk_set_rate(&pclk, timings.pixelclock.typ); - if (ret) - dev_warn(dev, "fail to set pixel clock %d hz\n", - timings.pixelclock.typ); + rate = clk_set_rate(&pclk, timings.pixelclock.typ); + if (IS_ERR_VALUE(rate)) + dev_warn(dev, "fail to set pixel clock %d hz, ret=%ld\n", + timings.pixelclock.typ, rate); dev_dbg(dev, "Set pixel clock req %d hz get %ld hz\n", - timings.pixelclock.typ, clk_get_rate(&pclk)); + timings.pixelclock.typ, rate); ret = reset_get_by_index(dev, 0, &rst); if (ret) { From 182738fe2f65b6b7faab70d883ad1ab435c6a8b5 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 31 Jan 2022 16:07:54 +0100 Subject: [PATCH 06/11] arm: dts: stm32mp15: alignment with v5.17 Device tree alignment with Linux kernel v5.17-rc1 - ARM: dts: stm32: add pull-up to USART3 and UART7 RX pins on STM32MP15 DKx boards - ARM: dts: stm32: clean uart4_idle_pins_a node for stm32mp15 - ARM: dts: stm32: tune the HS USB PHYs on stm32mp15xx-dkx - ARM: dts: stm32: tune the HS USB PHYs on stm32mp157c-ev1 - ARM: dts: stm32: fix stusb1600 pinctrl used on stm32mp157c-dk Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15-pinctrl.dtsi | 32 ++++++++++++++--------------- arch/arm/dts/stm32mp157c-ev1.dts | 22 ++++++++++++++++++++ arch/arm/dts/stm32mp15xx-dkx.dtsi | 16 +++++++++++++++ 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/arch/arm/dts/stm32mp15-pinctrl.dtsi b/arch/arm/dts/stm32mp15-pinctrl.dtsi index d3553e0f01..6161f5906e 100644 --- a/arch/arm/dts/stm32mp15-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp15-pinctrl.dtsi @@ -1718,7 +1718,7 @@ stusb1600_pins_a: stusb1600-0 { pins { - pinmux = ; + pinmux = ; bias-pull-up; }; }; @@ -1737,20 +1737,20 @@ }; uart4_idle_pins_a: uart4-idle-0 { - pins1 { - pinmux = ; /* UART4_TX */ - }; - pins2 { - pinmux = ; /* UART4_RX */ - bias-disable; - }; + pins1 { + pinmux = ; /* UART4_TX */ + }; + pins2 { + pinmux = ; /* UART4_RX */ + bias-disable; + }; }; uart4_sleep_pins_a: uart4-sleep-0 { - pins { + pins { pinmux = , /* UART4_TX */ ; /* UART4_RX */ - }; + }; }; uart4_pins_b: uart4-1 { @@ -1816,7 +1816,7 @@ }; pins2 { pinmux = ; /* UART7_RX */ - bias-disable; + bias-pull-up; }; }; @@ -1826,7 +1826,7 @@ }; pins2 { pinmux = ; /* UART7_RX */ - bias-disable; + bias-pull-up; }; }; @@ -1971,7 +1971,7 @@ pins2 { pinmux = , /* USART3_RX */ ; /* USART3_CTS_NSS */ - bias-disable; + bias-pull-up; }; }; @@ -1988,7 +1988,7 @@ }; pins3 { pinmux = ; /* USART3_RX */ - bias-disable; + bias-pull-up; }; }; @@ -2012,7 +2012,7 @@ pins2 { pinmux = , /* USART3_RX */ ; /* USART3_CTS_NSS */ - bias-disable; + bias-pull-up; }; }; @@ -2029,7 +2029,7 @@ }; pins3 { pinmux = ; /* USART3_RX */ - bias-disable; + bias-pull-up; }; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 5c5b1ddf7b..e222d2d2cb 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -375,3 +375,25 @@ &usbphyc { status = "okay"; }; + +&usbphyc_port0 { + st,tune-hs-dc-level = <2>; + st,enable-fs-rftime-tuning; + st,enable-hs-rftime-reduction; + st,trim-hs-current = <15>; + st,trim-hs-impedance = <1>; + st,tune-squelch-level = <3>; + st,tune-hs-rx-offset = <2>; + st,no-lsfs-sc; +}; + +&usbphyc_port1 { + st,tune-hs-dc-level = <2>; + st,enable-fs-rftime-tuning; + st,enable-hs-rftime-reduction; + st,trim-hs-current = <15>; + st,trim-hs-impedance = <1>; + st,tune-squelch-level = <3>; + st,tune-hs-rx-offset = <2>; + st,no-lsfs-sc; +}; diff --git a/arch/arm/dts/stm32mp15xx-dkx.dtsi b/arch/arm/dts/stm32mp15xx-dkx.dtsi index 5502eec94b..f8130bf445 100644 --- a/arch/arm/dts/stm32mp15xx-dkx.dtsi +++ b/arch/arm/dts/stm32mp15xx-dkx.dtsi @@ -702,10 +702,26 @@ &usbphyc_port0 { phy-supply = <&vdd_usb>; + st,tune-hs-dc-level = <2>; + st,enable-fs-rftime-tuning; + st,enable-hs-rftime-reduction; + st,trim-hs-current = <15>; + st,trim-hs-impedance = <1>; + st,tune-squelch-level = <3>; + st,tune-hs-rx-offset = <2>; + st,no-lsfs-sc; }; &usbphyc_port1 { phy-supply = <&vdd_usb>; + st,tune-hs-dc-level = <2>; + st,enable-fs-rftime-tuning; + st,enable-hs-rftime-reduction; + st,trim-hs-current = <15>; + st,trim-hs-impedance = <1>; + st,tune-squelch-level = <3>; + st,tune-hs-rx-offset = <2>; + st,no-lsfs-sc; }; &vrefbuf { From 27f6c653ae30ee60fe777a37098c8ffa714d8a49 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 28 Jan 2022 19:35:20 +0100 Subject: [PATCH 07/11] ARM: dts: stm32: Add USB OTG pinctrl and regulator nodes into SPL DT on DHCOR Fix the following warning in SPL and make sure that even DTs which enforce Vbus detection using u-boot,force-vbus-detection;, the DFU in SPL will work. dwc2-udc-otg usb-otg@49000000: prop pinctrl-0 index 0 invalid phandle Signed-off-by: Marek Vasut Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi index 338b674368..cd3190cca6 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi @@ -179,6 +179,14 @@ u-boot,dm-spl; }; +&usb33 { + u-boot,dm-spl; +}; + +&usbotg_hs_pins_a { + u-boot,dm-spl; +}; + &usbotg_hs { u-boot,dm-spl; }; From 9a8996df050dc20ef6954df077186400cb62622e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 3 Feb 2022 02:49:29 +0100 Subject: [PATCH 08/11] ARM: dts: stm32: Move vdd_io extras into Avenger96 extras The vdd_io regulator is present only on DHCOR SoM configured for 1V8 IO, as populated on Avenger96, but not present on 3V3 DHCOR SoM. Move these extras to Avenger96 u-boot DT extras. Fixes: 3919aa1722a ("ARM: dts: stm32: Add DFU support for DHCOR recovery") Signed-off-by: Marek Vasut Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay --- arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi | 4 ++++ arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi index 6e6543b5e4..5bed53e3fd 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcor-avenger96-u-boot.dtsi @@ -101,3 +101,7 @@ u-boot,force-b-session-valid; hnp-srp-disable; }; + +&vdd_io { + u-boot,dm-spl; +}; diff --git a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi index cd3190cca6..19f4221f87 100644 --- a/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcor-u-boot.dtsi @@ -203,10 +203,6 @@ u-boot,dm-spl; }; -&vdd_io { - u-boot,dm-spl; -}; - &vdd_usb { u-boot,dm-spl; }; From 0d44ad8bb4ee2e03f8e6b6f1cdd9f49c79d3dd65 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 25 Feb 2022 02:15:58 +0100 Subject: [PATCH 09/11] ram: stm32mp1: Unconditionally enable ASR Enable DRAM ASR, auto self-refresh, unconditionally. This saves non-trivial amount of power both at runtime and in suspend (on 2x W632GU6NB-15 ~150mW). Reviewed-by: Patrice Chotard Signed-off-by: Marek Vasut Cc: Patrick Delaunay Cc: Patrice Chotard --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 25 ++++++++++++++++++++++++ drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index 4d78aa5cb1..528a171b45 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -27,6 +27,8 @@ #define RCC_DDRITFCR_DPHYAPBRST (BIT(17)) #define RCC_DDRITFCR_DPHYRST (BIT(18)) #define RCC_DDRITFCR_DPHYCTLRST (BIT(19)) +#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) +#define RCC_DDRITFCR_DDRCKMOD_ASR BIT(20) struct reg_desc { const char *name; @@ -651,6 +653,26 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, wait_sw_done_ack(ctl); } +static void stm32mp1_asr_enable(struct ddr_info *priv) +{ + struct stm32mp1_ddrctl *ctl = priv->ctl; + + clrsetbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, + RCC_DDRITFCR_DDRCKMOD_ASR); + + start_sw_done(ctl); + + setbits_le32(&ctl->hwlpctl, DDRCTRL_HWLPCTL_HW_LP_EN); + writel(DDRCTRL_PWRTMG_POWERDOWN_TO_X32(0x10) | + DDRCTRL_PWRTMG_SELFREF_TO_X32(0x01), + &ctl->pwrtmg); + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); + + setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + wait_sw_done_ack(ctl); +} + /* board-specific DDR power initializations. */ __weak int board_ddr_power_init(enum ddr_type ddr_type) { @@ -822,6 +844,9 @@ start: stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3, config->c_reg.pwrctl); +/* Enable auto-self-refresh, which saves a bit of power at runtime. */ + stm32mp1_asr_enable(priv); + /* enable uMCTL2 AXI port 0 and 1 */ setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h index f1a26e31f6..42be1ba57c 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h @@ -265,8 +265,14 @@ struct stm32mp1_ddrphy { #define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) +#define DDRCTRL_PWRTMG_SELFREF_TO_X32(n) (((n) & 0xff) << 16) +#define DDRCTRL_PWRTMG_POWERDOWN_TO_X32(n) ((n) & 0x1f) + +#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) + #define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0) #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16) From b49105320a5b1e6c5f88dd90766d65a79f9f4e65 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 25 Feb 2022 02:15:59 +0100 Subject: [PATCH 10/11] stm32mp: psci: Implement PSCI system suspend and DRAM SSR Implement PSCI system suspend and placement of DRAM into SSR while the CPUs are in suspend. This saves non-trivial amount of power in suspend, on 2x W632GU6NB-15 ~710mW. Reviewed-by: Patrice Chotard Signed-off-by: Marek Vasut Cc: Patrick Delaunay Cc: Patrice Chotard --- arch/arm/mach-stm32mp/include/mach/stm32.h | 3 + arch/arm/mach-stm32mp/psci.c | 521 ++++++++++++++++++++- 2 files changed, 516 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index c11a9903f2..47e88fc3dc 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -16,8 +16,11 @@ */ #define STM32_RCC_BASE 0x50000000 #define STM32_PWR_BASE 0x50001000 +#define STM32_SYSCFG_BASE 0x50020000 #define STM32_DBGMCU_BASE 0x50081000 #define STM32_FMC2_BASE 0x58002000 +#define STM32_DDRCTRL_BASE 0x5A003000 +#define STM32_DDRPHYC_BASE 0x5A004000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_STGEN_BASE 0x5C008000 diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 155aa79cd5..86c160987a 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -11,19 +11,152 @@ #include #include #include +#include #include -#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0 -#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1 +/* PWR */ +#define PWR_CR3 0x0c +#define PWR_MPUCR 0x10 -#define MPIDR_AFF0 GENMASK(7, 0) +#define PWR_CR3_DDRSREN BIT(10) +#define PWR_CR3_DDRRETEN BIT(12) -#define RCC_MP_GRSTCSETR (STM32_RCC_BASE + 0x0404) -#define RCC_MP_GRSTCSETR_MPUP1RST BIT(5) -#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) -#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0) +#define PWR_MPUCR_PDDS BIT(0) +#define PWR_MPUCR_CSTDBYDIS BIT(3) +#define PWR_MPUCR_CSSF BIT(9) -#define STM32MP1_PSCI_NR_CPUS 2 +/* RCC */ +#define RCC_DDRITFCR 0xd8 + +#define RCC_DDRITFCR_DDRC1EN BIT(0) +#define RCC_DDRITFCR_DDRC1LPEN BIT(1) +#define RCC_DDRITFCR_DDRC2EN BIT(2) +#define RCC_DDRITFCR_DDRC2LPEN BIT(3) +#define RCC_DDRITFCR_DDRPHYCEN BIT(4) +#define RCC_DDRITFCR_DDRPHYCLPEN BIT(5) +#define RCC_DDRITFCR_DDRCAPBEN BIT(6) +#define RCC_DDRITFCR_DDRCAPBLPEN BIT(7) +#define RCC_DDRITFCR_AXIDCGEN BIT(8) +#define RCC_DDRITFCR_DDRPHYCAPBEN BIT(9) +#define RCC_DDRITFCR_DDRPHYCAPBLPEN BIT(10) +#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) +#define RCC_DDRITFCR_GSKPCTRL BIT(24) + +#define RCC_MP_SREQSETR 0x104 +#define RCC_MP_SREQCLRR 0x108 + +#define RCC_MP_CIER 0x414 +#define RCC_MP_CIFR 0x418 +#define RCC_MP_CIFR_WKUPF BIT(20) + +/* SYSCFG */ +#define SYSCFG_CMPCR 0x20 +#define SYSCFG_CMPCR_SW_CTRL BIT(2) +#define SYSCFG_CMPENSETR 0x24 +#define SYSCFG_CMPENCLRR 0x28 +#define SYSCFG_CMPENR_MPUEN BIT(0) + +/* DDR Controller registers offsets */ +#define DDRCTRL_STAT 0x004 +#define DDRCTRL_PWRCTL 0x030 +#define DDRCTRL_PWRTMG 0x034 +#define DDRCTRL_HWLPCTL 0x038 +#define DDRCTRL_DFIMISC 0x1b0 +#define DDRCTRL_SWCTL 0x320 +#define DDRCTRL_SWSTAT 0x324 +#define DDRCTRL_PSTAT 0x3fc +#define DDRCTRL_PCTRL_0 0x490 +#define DDRCTRL_PCTRL_1 0x540 + +/* DDR Controller Register fields */ +#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0) +#define DDRCTRL_STAT_OPERATING_MODE_NORMAL 0x1 +#define DDRCTRL_STAT_OPERATING_MODE_SR 0x3 +#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4) +#define DDRCTRL_STAT_SELFREF_TYPE_ASR (0x3 << 4) +#define DDRCTRL_STAT_SELFREF_TYPE_SR (0x2 << 4) + +#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) +#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) + +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK(23, 16) +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) + +#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) + +#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) + +#define DDRCTRL_SWCTL_SW_DONE BIT(0) + +#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0) + +#define DDRCTRL_PSTAT_RD_PORT_BUSY_0 BIT(0) +#define DDRCTRL_PSTAT_RD_PORT_BUSY_1 BIT(1) +#define DDRCTRL_PSTAT_WR_PORT_BUSY_0 BIT(16) +#define DDRCTRL_PSTAT_WR_PORT_BUSY_1 BIT(17) + +#define DDRCTRL_PCTRL_N_PORT_EN BIT(0) + +/* DDR PHY registers offsets */ +#define DDRPHYC_PIR 0x004 +#define DDRPHYC_PGSR 0x00c +#define DDRPHYC_ACDLLCR 0x014 +#define DDRPHYC_ACIOCR 0x024 +#define DDRPHYC_DXCCR 0x028 +#define DDRPHYC_DSGCR 0x02c +#define DDRPHYC_ZQ0CR0 0x180 +#define DDRPHYC_DX0DLLCR 0x1cc +#define DDRPHYC_DX1DLLCR 0x20c +#define DDRPHYC_DX2DLLCR 0x24c +#define DDRPHYC_DX3DLLCR 0x28c + +/* DDR PHY Register fields */ +#define DDRPHYC_PIR_INIT BIT(0) +#define DDRPHYC_PIR_DLLSRST BIT(1) +#define DDRPHYC_PIR_DLLLOCK BIT(2) +#define DDRPHYC_PIR_ITMSRST BIT(4) + +#define DDRPHYC_PGSR_IDONE BIT(0) + +#define DDRPHYC_ACDLLCR_DLLSRST BIT(30) +#define DDRPHYC_ACDLLCR_DLLDIS BIT(31) + +#define DDRPHYC_ACIOCR_ACOE BIT(1) +#define DDRPHYC_ACIOCR_ACPDD BIT(3) +#define DDRPHYC_ACIOCR_ACPDR BIT(4) +#define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK(10, 8) +#define DDRPHYC_ACIOCR_CKPDD_0 BIT(8) +#define DDRPHYC_ACIOCR_CKPDR_MASK GENMASK(13, 11) +#define DDRPHYC_ACIOCR_CKPDR_0 BIT(11) +#define DDRPHYC_ACIOCR_CSPDD_MASK GENMASK(20, 18) +#define DDRPHYC_ACIOCR_CSPDD_0 BIT(18) + +#define DDRPHYC_DXCCR_DXPDD BIT(2) +#define DDRPHYC_DXCCR_DXPDR BIT(3) + +#define DDRPHYC_DSGCR_CKEPDD_MASK GENMASK(19, 16) +#define DDRPHYC_DSGCR_CKEPDD_0 BIT(16) +#define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK(23, 20) +#define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) +#define DDRPHYC_DSGCR_NL2PD BIT(24) +#define DDRPHYC_DSGCR_CKOE BIT(28) + +#define DDRPHYC_ZQ0CRN_ZQPD BIT(31) + +#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) + +#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xca7face0 +#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xca7face1 + +#define MPIDR_AFF0 GENMASK(7, 0) + +#define RCC_MP_GRSTCSETR (STM32_RCC_BASE + 0x0404) +#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0) +#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) +#define RCC_MP_GRSTCSETR_MPUP1RST BIT(5) + +#define STM32MP1_PSCI_NR_CPUS 2 #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" #endif @@ -98,6 +231,7 @@ s32 __secure psci_features(u32 function_id, u32 psci_fid) case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE: case ARM_PSCI_0_2_FN_SYSTEM_OFF: case ARM_PSCI_0_2_FN_SYSTEM_RESET: + case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND: return 0x0; } return ARM_PSCI_RET_NI; @@ -222,3 +356,374 @@ void __secure psci_system_off(void) while (1) wfi(); } + +static void __secure secure_udelay(unsigned int delay) +{ + u32 freq = cp15_read_cntfrq() / 1000000; + u64 start, end; + + delay *= freq; + + asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start)); + for (;;) { + asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end)); + if ((end - start) > delay) + break; + } +} + +static int __secure secure_waitbits(u32 reg, u32 mask, u32 val) +{ + u32 freq = cp15_read_cntfrq() / 1000000; + u32 delay = 500 * freq; /* 500 us */ + u64 start, end; + u32 tmp; + + asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start)); + for (;;) { + tmp = readl(reg); + tmp &= mask; + if ((tmp & val) == val) + return 0; + asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end)); + if ((end - start) > delay) + return -ETIMEDOUT; + } +} + +static void __secure ddr_sr_mode_ssr(u32 *saved_pwrctl) +{ + setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1LPEN | RCC_DDRITFCR_DDRC1EN | + RCC_DDRITFCR_DDRC2LPEN | RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRCAPBLPEN | RCC_DDRITFCR_DDRPHYCAPBLPEN | + RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN | + RCC_DDRITFCR_DDRPHYCEN); + + clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, + RCC_DDRITFCR_AXIDCGEN | RCC_DDRITFCR_DDRCKMOD_MASK); + + /* Disable HW LP interface of uMCTL2 */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_HWLPCTL, + DDRCTRL_HWLPCTL_HW_LP_EN); + + /* Configure Automatic LP modes of uMCTL2 */ + clrsetbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRTMG, + DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, + DDRCTRL_PWRTMG_SELFREF_TO_X32_0); + + /* Save PWRCTL register to restart ASR after suspend (if applicable) */ + *saved_pwrctl = readl(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL); + + /* + * Disable Clock disable with LP modes + * (used in RUN mode for LPDDR2 with specific timing). + */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); + + /* Disable automatic Self-Refresh mode */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_SELFREF_EN); +} + +static void __secure ddr_sr_mode_restore(u32 saved_pwrctl) +{ + saved_pwrctl &= DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | + DDRCTRL_PWRCTL_SELFREF_EN; + + /* Restore ASR mode in case it was enabled before suspend. */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, saved_pwrctl); +} + +static int __secure ddr_sw_self_refresh_in(void) +{ + int ret; + + clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + + /* Blocks AXI ports from taking anymore transactions */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, + DDRCTRL_PCTRL_N_PORT_EN); + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, + DDRCTRL_PCTRL_N_PORT_EN); + + /* + * Waits unit all AXI ports are idle + * Poll PSTAT.rd_port_busy_n = 0 + * Poll PSTAT.wr_port_busy_n = 0 + */ + ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_PSTAT, + DDRCTRL_PSTAT_RD_PORT_BUSY_0 | + DDRCTRL_PSTAT_RD_PORT_BUSY_1 | + DDRCTRL_PSTAT_WR_PORT_BUSY_0 | + DDRCTRL_PSTAT_WR_PORT_BUSY_1, 0); + if (ret) + goto pstat_failed; + + /* SW Self-Refresh entry */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); + + /* + * Wait operating mode change in self-refresh mode + * with STAT.operating_mode[1:0]==11. + * Ensure transition to self-refresh was due to software + * by checking also that STAT.selfref_type[1:0]=2. + */ + ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT, + DDRCTRL_STAT_OPERATING_MODE_MASK | + DDRCTRL_STAT_SELFREF_TYPE_MASK, + DDRCTRL_STAT_OPERATING_MODE_SR | + DDRCTRL_STAT_SELFREF_TYPE_SR); + if (ret) + goto selfref_sw_failed; + + /* IOs powering down (PUBL registers) */ + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR); + + clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CKPDD_MASK, + DDRPHYC_ACIOCR_CKPDD_0); + + clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CKPDR_MASK, + DDRPHYC_ACIOCR_CKPDR_0); + + clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CSPDD_MASK, + DDRPHYC_ACIOCR_CSPDD_0); + + /* Disable command/address output driver */ + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); + + clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, + DDRPHYC_DSGCR_ODTPDD_MASK, + DDRPHYC_DSGCR_ODTPDD_0); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); + + clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, + DDRPHYC_DSGCR_CKEPDD_MASK, + DDRPHYC_DSGCR_CKEPDD_0); + + /* Disable PZQ cell (PUBL register) */ + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); + + /* Set latch */ + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); + + /* Additional delay to avoid early latch */ + secure_udelay(10); + + /* Activate sw retention in PWRCTRL */ + setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Disable all DLLs: GLITCH window */ + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLDIS); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */ + clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Deactivate all DDR clocks */ + clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN); + + return 0; + +selfref_sw_failed: + /* This bit should be cleared to restore DDR in its previous state */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_SELFREF_SW); + +pstat_failed: + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, + DDRCTRL_PCTRL_N_PORT_EN); + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, + DDRCTRL_PCTRL_N_PORT_EN); + + return -EINVAL; +}; + +static void __secure ddr_sw_self_refresh_exit(void) +{ + int ret; + + /* Enable all clocks */ + setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRPHYCEN | RCC_DDRITFCR_DDRPHYCAPBEN | + RCC_DDRITFCR_DDRCAPBEN); + + /* Handshake */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); + + /* Mask dfi_init_complete_en */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + + /* Ack */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); + ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT, + DDRCTRL_SWSTAT_SW_DONE_ACK, + DDRCTRL_SWSTAT_SW_DONE_ACK); + if (ret) + hang(); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Enable all DLLs: GLITCH window */ + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, + DDRPHYC_ACDLLCR_DLLDIS); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + /* Additional delay to avoid early DLL clock switch */ + secure_udelay(50); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); + + secure_udelay(10); + + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); + + /* PHY partial init: (DLL lock and ITM reset) */ + writel(DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | + DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT, + STM32_DDRPHYC_BASE + DDRPHYC_PIR); + + /* Need to wait at least 10 clock cycles before accessing PGSR */ + secure_udelay(1); + + /* Pool end of init */ + ret = secure_waitbits(STM32_DDRPHYC_BASE + DDRPHYC_PGSR, + DDRPHYC_PGSR_IDONE, DDRPHYC_PGSR_IDONE); + if (ret) + hang(); + + /* Handshake */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); + + /* Unmask dfi_init_complete_en to uMCTL2 */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + + /* Ack */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); + ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT, + DDRCTRL_SWSTAT_SW_DONE_ACK, + DDRCTRL_SWSTAT_SW_DONE_ACK); + if (ret) + hang(); + + /* Deactivate sw retention in PWR */ + clrbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN); + + /* Enable PZQ cell (PUBL register) */ + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); + + /* Enable pad drivers */ + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); + + /* Enable command/address output driver */ + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CKPDD_MASK); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CSPDD_MASK); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); + + /* Release latch */ + setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_ODTPDD_MASK); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); + + clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKEPDD_MASK); + + /* Remove selfrefresh */ + clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); + + /* Wait operating_mode == normal */ + ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT, + DDRCTRL_STAT_OPERATING_MODE_MASK, + DDRCTRL_STAT_OPERATING_MODE_NORMAL); + if (ret) + hang(); + + /* AXI ports are no longer blocked from taking transactions */ + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN); + setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN); + + setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); +} + +void __secure psci_system_suspend(u32 __always_unused function_id, + u32 ep, u32 context_id) +{ + u32 saved_pwrctl, reg; + + /* Disable IO compensation */ + + /* Place current APSRC/ANSRC into RAPSRC/RANSRC */ + reg = readl(STM32_SYSCFG_BASE + SYSCFG_CMPCR); + reg >>= 8; + reg &= 0xff << 16; + reg |= SYSCFG_CMPCR_SW_CTRL; + writel(reg, STM32_SYSCFG_BASE + SYSCFG_CMPCR); + writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENCLRR); + + writel(RCC_MP_CIFR_WKUPF, STM32_RCC_BASE + RCC_MP_CIFR); + setbits_le32(STM32_RCC_BASE + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); + + setbits_le32(STM32_PWR_BASE + PWR_MPUCR, + PWR_MPUCR_CSSF | PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_PDDS); + + psci_v7_flush_dcache_all(); + ddr_sr_mode_ssr(&saved_pwrctl); + ddr_sw_self_refresh_in(); + setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN); + writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR); + + /* Zzz, enter stop mode */ + asm volatile( + "isb\n" + "dsb\n" + "wfi\n"); + + writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); + ddr_sw_self_refresh_exit(); + ddr_sr_mode_restore(saved_pwrctl); + + writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENSETR); + clrbits_le32(STM32_SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); +} From 19fbe102b2e21db949a66d9020da097769bbdb3c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 14 Mar 2022 13:35:54 +0100 Subject: [PATCH 11/11] ARM: dts: stm32: Add DFU support for DHCOM recovery This patch configures U-Boot SPL for DHCOM SoM to permit DFU upload of SPL and subsequent u-boot.itb for recovery or commissioning purposes. The DFU usage procedure is identical to STM32MP1 DHCOR SoM, see commit 3919aa1722a ("ARM: dts: stm32: Add DFU support for DHCOR recovery") , except for switching the SoM into DFU mode. By default, the DHCOM SoM has no dedicated mechanism for setting BOOTn straps into UART/USB mode, therefore to enter DFU mode, the SoC must fail to boot from boot media which can be selected by the BOOTn strap override mechanism first and then fall back to DFU mode. In case of a SoM with pre-populated BOOTn strap override button, power the system off, remove microSD card (if applicable), hold down the BOOTn strap override button located between eMMC and SoM edge connector, power on the SoM. The SoC will fail to boot from SD card and fall back into DFU mode. Signed-off-by: Marek Vasut Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi | 42 ++++++++++++++++++++++ configs/stm32mp15_dhcom_basic_defconfig | 15 ++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi b/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi index f09f4290f6..d73967ac1b 100644 --- a/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi +++ b/arch/arm/dts/stm32mp15xx-dhcom-u-boot.dtsi @@ -58,6 +58,7 @@ &i2c4 { u-boot,dm-pre-reloc; + u-boot,dm-spl; eeprom0: eeprom@50 { }; @@ -98,6 +99,11 @@ &pmic { u-boot,dm-pre-reloc; + u-boot,dm-spl; + + regulators { + u-boot,dm-spl; + }; }; &flash0 { @@ -288,3 +294,39 @@ bias-pull-up; }; }; + +®11 { + u-boot,dm-spl; +}; + +®18 { + u-boot,dm-spl; +}; + +&usb33 { + u-boot,dm-spl; +}; + +&usbotg_hs_pins_a { + u-boot,dm-spl; +}; + +&usbotg_hs { + u-boot,dm-spl; +}; + +&usbphyc { + u-boot,dm-spl; +}; + +&usbphyc_port0 { + u-boot,dm-spl; +}; + +&usbphyc_port1 { + u-boot,dm-spl; +}; + +&vdd_usb { + u-boot,dm-spl; +}; diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig index c422c47775..438bba37de 100644 --- a/configs/stm32mp15_dhcom_basic_defconfig +++ b/configs/stm32mp15_dhcom_basic_defconfig @@ -18,6 +18,7 @@ CONFIG_DISTRO_DEFAULTS=y CONFIG_SYS_LOAD_ADDR=0xc2000000 CONFIG_FIT=y CONFIG_SPL_LOAD_FIT=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0xc1000000 CONFIG_SPL_FIT_SOURCE="board/dhelectronics/dh_stm32mp1/u-boot-dhcom.its" # CONFIG_USE_SPL_FIT_GENERATOR is not set CONFIG_BOOTDELAY=1 @@ -27,12 +28,17 @@ CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SPL_LEGACY_IMAGE_SUPPORT=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 +CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C=y CONFIG_SPL_MTD_SUPPORT=y CONFIG_SPL_DM_SPI_FLASH=y CONFIG_SPL_POWER=y +CONFIG_SPL_RAM_SUPPORT=y +CONFIG_SPL_RAM_DEVICE=y CONFIG_SPL_SPI_FLASH_MTD=y CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 +CONFIG_SPL_USB_GADGET=y +CONFIG_SPL_DFU=y CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_ELF is not set # CONFIG_CMD_EXPORTENV is not set @@ -71,6 +77,7 @@ CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-names interrupts-extended inter CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_SPL_ENV_IS_NOWHERE=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_IP_DEFRAG=y CONFIG_TFTP_BLOCKSIZE=1536 @@ -79,8 +86,6 @@ CONFIG_SPL_BLOCK_CACHE=y CONFIG_DFU_MMC=y CONFIG_DFU_MTD=y CONFIG_DFU_RAM=y -CONFIG_DFU_VIRT=y -CONFIG_SET_DFU_ALT_INFO=y CONFIG_GPIO_HOG=y CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y @@ -106,18 +111,20 @@ CONFIG_DM_ETH=y CONFIG_DWC_ETH_QOS=y CONFIG_KS8851_MLL=y CONFIG_PHY=y +CONFIG_SPL_PHY=y CONFIG_PHY_STM32_USBPHYC=y 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 CONFIG_DM_REGULATOR=y +CONFIG_SPL_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y +CONFIG_SPL_DM_REGULATOR_STPMIC1=y CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y @@ -129,8 +136,10 @@ CONFIG_STM32_SPI=y CONFIG_SYSRESET_SYSCON=y CONFIG_USB=y CONFIG_DM_USB_GADGET=y +CONFIG_SPL_DM_USB_GADGET=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_DWC2=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y