From a012f551a8e0524ec009f25d6367081c1acea327 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 3 Jan 2019 17:22:38 +0100 Subject: [PATCH 001/244] Prepare v2018.11-stm32mp-r1 Change-Id: I326f076790155b197ada21d8733139166ac9a874 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115142 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- .gitignore | 3 + MAINTAINERS | 2 + Makefile | 2 +- arch/arm/Kconfig | 10 +- arch/arm/cpu/armv7/arch_timer.c | 3 + arch/arm/dts/Makefile | 2 + arch/arm/dts/stm32h743i-eval.dts | 2 +- arch/arm/dts/stm32mp15-ddr.dtsi | 2 +- .../dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi | 120 ++ .../dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 121 ++ .../dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi | 120 ++ .../dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 21 +- arch/arm/dts/stm32mp157-pinctrl.dtsi | 1474 +++++++++++++-- arch/arm/dts/stm32mp157-u-boot.dtsi | 73 +- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 190 ++ arch/arm/dts/stm32mp157a-dk1.dts | 700 +++++++ arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 6 + arch/arm/dts/stm32mp157c-dk2.dts | 144 ++ arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 109 +- arch/arm/dts/stm32mp157c-ed1.dts | 396 ++-- arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi | 19 +- arch/arm/dts/stm32mp157c-ev1.dts | 657 ++++++- arch/arm/dts/stm32mp157c.dtsi | 1125 ++++++++++- arch/arm/dts/stm32mp157caa-pinctrl.dtsi | 90 + arch/arm/dts/stm32mp157cab-pinctrl.dtsi | 62 + arch/arm/dts/stm32mp157cac-pinctrl.dtsi | 78 + arch/arm/dts/stm32mp157cad-pinctrl.dtsi | 62 + arch/arm/include/asm/arch-stm32/gpio.h | 5 + arch/arm/mach-stm32mp/Kconfig | 108 +- arch/arm/mach-stm32mp/Makefile | 8 +- arch/arm/mach-stm32mp/bsec.c | 64 +- arch/arm/mach-stm32mp/cmd_poweroff.c | 24 + arch/arm/mach-stm32mp/cmd_stm32key.c | 100 + arch/arm/mach-stm32mp/cmd_stm32prog/Makefile | 9 + .../cmd_stm32prog/cmd_stm32prog.c | 80 + .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 1647 +++++++++++++++++ .../mach-stm32mp/cmd_stm32prog/stm32prog.h | 202 ++ .../cmd_stm32prog/stm32prog_serial.c | 972 ++++++++++ .../cmd_stm32prog/stm32prog_usb.c | 278 +++ arch/arm/mach-stm32mp/config.mk | 16 +- arch/arm/mach-stm32mp/cpu.c | 236 ++- arch/arm/mach-stm32mp/include/mach/ddr.h | 9 +- arch/arm/mach-stm32mp/include/mach/gpio.h | 6 + arch/arm/mach-stm32mp/include/mach/stm32.h | 37 +- .../mach-stm32mp/include/mach/stm32mp1_smc.h | 75 + .../arm/mach-stm32mp/include/mach/sys_proto.h | 10 +- arch/arm/mach-stm32mp/psci.c | 8 +- arch/arm/mach-stm32mp/pwr_regulator.c | 8 + arch/arm/mach-stm32mp/spl.c | 47 +- arch/arm/mach-stm32mp/stm32-etzpc.c | 199 ++ arch/arm/mach-stm32mp/syscon.c | 9 +- arch/sandbox/dts/test.dts | 8 + arch/sandbox/include/asm/state.h | 1 + board/st/stm32mp1/Kconfig | 7 + board/st/stm32mp1/MAINTAINERS | 7 +- board/st/stm32mp1/Makefile | 1 + board/st/stm32mp1/README | 118 +- board/st/stm32mp1/board.c | 178 +- board/st/stm32mp1/cmd_stboard.c | 145 ++ board/st/stm32mp1/extlinux.conf | 20 + board/st/stm32mp1/fit_copro_kernel_dtb.its | 103 ++ board/st/stm32mp1/fit_kernel_dtb.its | 82 + board/st/stm32mp1/spl.c | 27 +- board/st/stm32mp1/stm32mp1.c | 909 ++++++++- cmd/Kconfig | 8 + cmd/Makefile | 1 + cmd/adc.c | 70 +- cmd/bmp.c | 18 +- cmd/pinmux.c | 146 ++ cmd/pxe.c | 24 + cmd/remoteproc.c | 62 +- cmd/usb_mass_storage.c | 3 + common/Makefile | 1 + common/board_f.c | 3 +- common/image.c | 1 + common/spl/spl_spi.c | 9 +- common/usb.c | 2 + configs/sandbox_defconfig | 2 + configs/stm32mp15_basic_defconfig | 71 +- configs/stm32mp15_optee_defconfig | 105 ++ configs/stm32mp15_trusted_defconfig | 104 ++ doc/device-tree-bindings/arm/stm32.txt | 17 + .../clock/st,stm32-rcc.txt | 37 + .../clock/st,stm32mp1-rcc.txt | 60 + doc/device-tree-bindings/i2c/i2c-stm32.txt | 98 +- doc/device-tree-bindings/mfd/stpmic1.txt | 138 ++ .../mtd/stm32-fmc2-nand.txt | 59 + .../mtd/stm32-quadspi.txt | 43 + .../net/snps,dwc-qos-ethernet.txt | 3 + doc/device-tree-bindings/net/stm32-dwmac.txt | 62 + .../phy/phy-stm32-usbphyc.txt | 65 +- .../pinctrl/st,stm32-pinctrl.txt | 101 +- .../power/st,stm32mp1-pwr.txt | 52 + .../ram/st,stm32mp1-ddr.txt | 4 +- .../regulator/st,stm32mp1-pwr-reg.txt | 31 + .../serial/st,stm32-usart.txt | 88 + .../watchdog/st,stm32-iwdg.txt | 26 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/adc-uclass.c | 54 +- drivers/clk/clk_stm32mp1.c | 271 ++- drivers/core/syscon-uclass.c | 61 +- drivers/core/uclass.c | 13 + drivers/dfu/Kconfig | 5 + drivers/dfu/Makefile | 1 + drivers/dfu/dfu.c | 84 +- drivers/dfu/dfu_sf.c | 54 +- drivers/dfu/dfu_virt.c | 47 + drivers/gpio/stm32f7_gpio.c | 120 +- drivers/hwspinlock/Kconfig | 24 + drivers/hwspinlock/Makefile | 7 + drivers/hwspinlock/hwspinlock-uclass.c | 144 ++ drivers/hwspinlock/sandbox_hwspinlock.c | 56 + drivers/hwspinlock/stm32_hwspinlock.c | 90 + drivers/i2c/stm32f7_i2c.c | 41 +- drivers/mailbox/Kconfig | 7 + drivers/mailbox/Makefile | 1 + drivers/mailbox/stm32-ipcc.c | 187 ++ drivers/misc/stm32mp_fuse.c | 28 + drivers/mmc/mmc_write.c | 2 +- drivers/mmc/stm32_sdmmc2.c | 67 +- drivers/mtd/nand/raw/Kconfig | 11 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/nand_ids.c | 4 + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 1092 +++++++++++ drivers/mtd/spi/spi_flash.c | 9 + drivers/net/dwc_eth_qos.c | 451 ++++- drivers/phy/phy-stm32-usbphyc.c | 201 +- drivers/pinctrl/Kconfig | 19 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-sandbox.c | 18 + drivers/pinctrl/pinctrl-stmfx.c | 414 +++++ drivers/pinctrl/pinctrl-uclass.c | 39 +- drivers/pinctrl/pinctrl_stm32.c | 252 ++- drivers/power/pmic/Kconfig | 6 +- drivers/power/pmic/Makefile | 2 +- drivers/power/pmic/stpmic1.c | 258 +++ drivers/power/pmic/stpmu1.c | 95 - drivers/power/regulator/Kconfig | 14 +- drivers/power/regulator/Makefile | 2 +- drivers/power/regulator/fixed.c | 4 +- drivers/power/regulator/regulator-uclass.c | 5 + drivers/power/regulator/stpmic1.c | 672 +++++++ drivers/power/regulator/stpmu1.c | 671 ------- drivers/ram/stm32mp1/Kconfig | 29 + drivers/ram/stm32mp1/Makefile | 7 + drivers/ram/stm32mp1/stm32mp1_ddr.c | 522 +++++- drivers/ram/stm32mp1/stm32mp1_ddr.h | 10 +- drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 3 + drivers/ram/stm32mp1/stm32mp1_interactive.c | 467 +++++ drivers/ram/stm32mp1/stm32mp1_ram.c | 30 +- drivers/ram/stm32mp1/stm32mp1_tests.c | 1360 ++++++++++++++ drivers/ram/stm32mp1/stm32mp1_tests.h | 34 + drivers/ram/stm32mp1/stm32mp1_tuning.c | 1504 +++++++++++++++ drivers/ram/stm32mp1/stm32mp1_tuning.h | 54 + drivers/remoteproc/Kconfig | 9 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/rproc-uclass.c | 333 +++- drivers/remoteproc/stm32_copro.c | 272 +++ drivers/reset/stm32-reset.c | 33 +- drivers/serial/serial_stm32.c | 18 +- drivers/spi/Kconfig | 2 +- drivers/spi/soft_spi.c | 4 +- drivers/sysreset/sysreset_syscon.c | 18 +- drivers/usb/gadget/Kconfig | 9 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/dwc2_udc_otg.c | 3 + drivers/usb/gadget/g_dnl.c | 5 + drivers/usb/gadget/gen_udc_otg_phy.c | 66 + drivers/usb/host/dwc2.c | 118 +- drivers/video/Kconfig | 33 + drivers/video/Makefile | 4 + drivers/video/dw_mipi_dsi.c | 826 +++++++++ drivers/video/mipi_display.c | 817 ++++++++ drivers/video/orisetech_otm8009a.c | 339 ++++ drivers/video/raydium-rm68200.c | 338 ++++ drivers/video/stm32/Kconfig | 9 + drivers/video/stm32/Makefile | 1 + drivers/video/stm32/stm32_dsi.c | 446 +++++ drivers/video/stm32/stm32_ltdc.c | 155 +- drivers/video/video-uclass.c | 14 + drivers/watchdog/Kconfig | 15 + drivers/watchdog/Makefile | 1 + drivers/watchdog/stm32mp_wdt.c | 119 ++ include/adc.h | 21 + include/configs/stm32mp1.h | 117 +- include/dfu.h | 29 + include/dm/pinctrl.h | 59 + include/dm/uclass-id.h | 1 + include/dm/uclass.h | 28 + include/dt-bindings/clock/stm32mp1-clks.h | 3 - include/dt-bindings/mfd/st,stpmic1.h | 46 + include/dt-bindings/mfd/st,stpmu1.h | 60 - include/dt-bindings/pinctrl/stm32-pinfunc.h | 6 + include/dt-bindings/rtc/rtc-stm32.h | 13 + include/dt-bindings/soc/stm32-hdp.h | 108 ++ include/dw_mipi_dsi.h | 32 + include/g_dnl.h | 1 + include/hwspinlock.h | 140 ++ include/image.h | 1 + include/mipi_display.h | 257 ++- include/power/stpmic1.h | 118 ++ include/power/stpmu1.h | 85 - include/remoteproc.h | 20 +- include/syscon.h | 9 + include/usb/dwc2_udc.h | 1 + test/dm/Makefile | 1 + test/dm/hwspinlock.c | 40 + test/py/tests/test_pinmux.py | 62 + tools/stm32image.c | 8 +- 210 files changed, 25602 insertions(+), 2171 deletions(-) create mode 100644 arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi create mode 100644 arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi create mode 100644 arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.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 create mode 100644 arch/arm/dts/stm32mp157caa-pinctrl.dtsi create mode 100644 arch/arm/dts/stm32mp157cab-pinctrl.dtsi create mode 100644 arch/arm/dts/stm32mp157cac-pinctrl.dtsi create mode 100644 arch/arm/dts/stm32mp157cad-pinctrl.dtsi create mode 100644 arch/arm/mach-stm32mp/cmd_poweroff.c create mode 100644 arch/arm/mach-stm32mp/cmd_stm32key.c create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h create mode 100644 arch/arm/mach-stm32mp/stm32-etzpc.c create mode 100644 board/st/stm32mp1/cmd_stboard.c create mode 100644 board/st/stm32mp1/extlinux.conf create mode 100644 board/st/stm32mp1/fit_copro_kernel_dtb.its create mode 100644 board/st/stm32mp1/fit_kernel_dtb.its create mode 100644 cmd/pinmux.c create mode 100644 configs/stm32mp15_optee_defconfig create mode 100644 configs/stm32mp15_trusted_defconfig create mode 100644 doc/device-tree-bindings/arm/stm32.txt create mode 100644 doc/device-tree-bindings/clock/st,stm32mp1-rcc.txt create mode 100644 doc/device-tree-bindings/mfd/stpmic1.txt create mode 100644 doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt create mode 100644 doc/device-tree-bindings/mtd/stm32-quadspi.txt create mode 100644 doc/device-tree-bindings/net/stm32-dwmac.txt create mode 100644 doc/device-tree-bindings/power/st,stm32mp1-pwr.txt create mode 100644 doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt create mode 100644 doc/device-tree-bindings/serial/st,stm32-usart.txt create mode 100644 doc/device-tree-bindings/watchdog/st,stm32-iwdg.txt create mode 100644 drivers/dfu/dfu_virt.c create mode 100644 drivers/hwspinlock/Kconfig create mode 100644 drivers/hwspinlock/Makefile create mode 100644 drivers/hwspinlock/hwspinlock-uclass.c create mode 100644 drivers/hwspinlock/sandbox_hwspinlock.c create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c create mode 100644 drivers/mailbox/stm32-ipcc.c create mode 100644 drivers/mtd/nand/raw/stm32_fmc2_nand.c create mode 100644 drivers/pinctrl/pinctrl-stmfx.c 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 drivers/ram/stm32mp1/stm32mp1_interactive.c create mode 100644 drivers/ram/stm32mp1/stm32mp1_tests.c create mode 100644 drivers/ram/stm32mp1/stm32mp1_tests.h create mode 100644 drivers/ram/stm32mp1/stm32mp1_tuning.c create mode 100644 drivers/ram/stm32mp1/stm32mp1_tuning.h create mode 100644 drivers/remoteproc/stm32_copro.c create mode 100644 drivers/usb/gadget/gen_udc_otg_phy.c create mode 100644 drivers/video/dw_mipi_dsi.c create mode 100644 drivers/video/mipi_display.c create mode 100644 drivers/video/orisetech_otm8009a.c create mode 100644 drivers/video/raydium-rm68200.c create mode 100644 drivers/video/stm32/stm32_dsi.c create mode 100644 drivers/watchdog/stm32mp_wdt.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/dt-bindings/rtc/rtc-stm32.h create mode 100644 include/dt-bindings/soc/stm32-hdp.h create mode 100644 include/dw_mipi_dsi.h create mode 100644 include/hwspinlock.h create mode 100644 include/power/stpmic1.h delete mode 100644 include/power/stpmu1.h create mode 100644 test/dm/hwspinlock.c create mode 100644 test/py/tests/test_pinmux.py diff --git a/.gitignore b/.gitignore index 8d18d6f49bcb..b22e7d0814b8 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ GTAGS *.orig *~ \#*# + +/oe-* +bitbake-cookerdaemon.log diff --git a/MAINTAINERS b/MAINTAINERS index abdb6dcdb513..17f9cd371a17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -242,7 +242,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/Makefile b/Makefile index 552687db5385..84cb3727e10e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = +EXTRAVERSION = -stm32mp-r1 NAME = # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1f3fa1575a31..e9eac9d51ea5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1313,21 +1313,27 @@ config ARCH_STM32MP select DM_GPIO select DM_RESET select DM_SERIAL + select ENV_VARS_UBOOT_RUNTIME_CONFIG select MISC select OF_CONTROL select OF_LIBFDT + imply OF_LIBFDT_OVERLAY + select OF_SYSTEM_SETUP select PINCTRL select REGMAP select SUPPORT_SPL select SYSCON select SYSRESET + select SYS_ARCH_TIMER select SYS_THUMB_BUILD imply CMD_DM + imply CMD_POWEROFF 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). + FBSL 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/cpu/armv7/arch_timer.c b/arch/arm/cpu/armv7/arch_timer.c index 3db31c020952..5de63053d593 100644 --- a/arch/arm/cpu/armv7/arch_timer.c +++ b/arch/arm/cpu/armv7/arch_timer.c @@ -49,6 +49,9 @@ unsigned long long get_ticks(void) ulong timer_get_boot_us(void) { + if (!gd->arch.timer_rate_hz) + timer_init(); + return lldiv(get_ticks(), gd->arch.timer_rate_hz / 1000000); } diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index d36447d18d36..a34602195a3f 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -553,6 +553,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/stm32h743i-eval.dts b/arch/arm/dts/stm32h743i-eval.dts index 28c876be27fc..368432f13c9b 100644 --- a/arch/arm/dts/stm32h743i-eval.dts +++ b/arch/arm/dts/stm32h743i-eval.dts @@ -105,5 +105,5 @@ <&pinctrl_sdmmc1_level_shifter>; pinctrl-names = "default"; bus-width = <4>; - st,dirpol; + st,sig-dir; }; diff --git a/arch/arm/dts/stm32mp15-ddr.dtsi b/arch/arm/dts/stm32mp15-ddr.dtsi index 4172c02f0a20..0164e34216e7 100644 --- a/arch/arm/dts/stm32mp15-ddr.dtsi +++ b/arch/arm/dts/stm32mp15-ddr.dtsi @@ -5,7 +5,7 @@ / { soc { - ddr: ddr@0x5A003000{ + ddr: ddr@5A003000{ u-boot,dm-pre-reloc; compatible = "st,stm32mp1-ddr"; diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi new file mode 100644 index 000000000000..da8331034294 --- /dev/null +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.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 1 = MT41J256M16-187 / DDR3-1066 bin F + * DDR density 4 + * timing mode optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC + * Tc > + 85C : N + */ +#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.41" +#define DDR_MEM_SPEED 533000 +#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 0x000A041B +#define DDR_DRAMTMG2 0x0607080F +#define DDR_DRAMTMG3 0x0050400C +#define DDR_DRAMTMG4 0x07040607 +#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 0x02050105 +#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 0x36D477D0 +#define DDR_DTPR1 0x098B00D8 +#define DDR_DTPR2 0x10023600 +#define DDR_MR0 0x00000830 +#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/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi new file mode 100644 index 000000000000..16b8cf623be3 --- /dev/null +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -0,0 +1,121 @@ +// 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.41" +#define DDR_MEM_SPEED 533000 +#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/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi new file mode 100644 index 000000000000..82781e713b81 --- /dev/null +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ +/* STM32MP157C ED1 BOARD configuration + * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. + * Reference used NT5CC256M16DP-DI from NANYA + * + * DDR type / Platform DDR3/3L + * freq 533MHz + * width 32 + * datasheet 1 = MT41J256M16-187 / DDR3-1066 bin F + * DDR density 8 + * timing mode optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC + * Tc > + 85C : N + */ +#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.41" +#define DDR_MEM_SPEED 533000 +#define DDR_MEM_SIZE 0x40000000 + +#define DDR_MSTR 0x00040401 +#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 0x000A041B +#define DDR_DRAMTMG2 0x0607080F +#define DDR_DRAMTMG3 0x0050400C +#define DDR_DRAMTMG4 0x07040607 +#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 0x02050105 +#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 0x00080808 +#define DDR_ADDRMAP2 0x00000000 +#define DDR_ADDRMAP3 0x00000000 +#define DDR_ADDRMAP4 0x00001F1F +#define DDR_ADDRMAP5 0x07070707 +#define DDR_ADDRMAP6 0x0F070707 +#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 0x36D477D0 +#define DDR_DTPR1 0x098B00D8 +#define DDR_DTPR2 0x10023600 +#define DDR_MR0 0x00000830 +#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/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi index 8a5a821ec4e2..82e710468d5c 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -3,7 +3,7 @@ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ -/* STM32MP157C ED1 and ED2 BOARD configuration +/* STM32MP157C ED1 BOARD configuration * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. * Reference used NT5CC256M16DP-DI from NANYA * @@ -15,10 +15,11 @@ * timing mode optimized * Scheduling/QoS options : type = 2 * address mapping : RBC + * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066 bin G 2x4Gb 533MHz v1.36" -#define DDR_MEM_SPEED 533 +#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.41" +#define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 #define DDR_MSTR 0x00040401 @@ -62,7 +63,7 @@ #define DDR_ADDRMAP11 0x00000000 #define DDR_ODTCFG 0x06000600 #define DDR_ODTMAP 0x00000001 -#define DDR_SCHED 0x00001201 +#define DDR_SCHED 0x00000C01 #define DDR_SCHED1 0x00000000 #define DDR_PERFHPR1 0x01000001 #define DDR_PERFLPR1 0x08000200 @@ -74,15 +75,15 @@ #define DDR_PCCFG 0x00000010 #define DDR_PCFGR_0 0x00010000 #define DDR_PCFGW_0 0x00000000 -#define DDR_PCFGQOS0_0 0x02100B03 +#define DDR_PCFGQOS0_0 0x02100C03 #define DDR_PCFGQOS1_0 0x00800100 -#define DDR_PCFGWQOS0_0 0x01100B03 +#define DDR_PCFGWQOS0_0 0x01100C03 #define DDR_PCFGWQOS1_0 0x01000200 #define DDR_PCFGR_1 0x00010000 #define DDR_PCFGW_1 0x00000000 -#define DDR_PCFGQOS0_1 0x02100B03 -#define DDR_PCFGQOS1_1 0x00800100 -#define DDR_PCFGWQOS0_1 0x01100B03 +#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 @@ -100,7 +101,7 @@ #define DDR_MR2 0x00000208 #define DDR_MR3 0x00000000 #define DDR_ODTCR 0x00010000 -#define DDR_ZQ0CR1 0x0000005B +#define DDR_ZQ0CR1 0x00000038 #define DDR_DX0GCR 0x0000CE81 #define DDR_DX0DLLCR 0x40000000 #define DDR_DX0DQTR 0xFFFFFFFF diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 85da5926551c..183d7ba7ebd7 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -14,6 +14,7 @@ ranges = <0 0x50002000 0xa400>; interrupt-parent = <&exti>; st,syscfg = <&exti 0x60 0xff>; + hwlocks = <&hsem 0>; pins-are-numbered; gpioa: gpio@50002000 { @@ -24,8 +25,7 @@ reg = <0x0 0x400>; clocks = <&rcc GPIOA>; st,bank-name = "GPIOA"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 0 16>; + status = "disabled"; }; gpiob: gpio@50003000 { @@ -36,8 +36,7 @@ reg = <0x1000 0x400>; clocks = <&rcc GPIOB>; st,bank-name = "GPIOB"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 16 16>; + status = "disabled"; }; gpioc: gpio@50004000 { @@ -48,8 +47,7 @@ reg = <0x2000 0x400>; clocks = <&rcc GPIOC>; st,bank-name = "GPIOC"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 32 16>; + status = "disabled"; }; gpiod: gpio@50005000 { @@ -60,8 +58,7 @@ reg = <0x3000 0x400>; clocks = <&rcc GPIOD>; st,bank-name = "GPIOD"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 48 16>; + status = "disabled"; }; gpioe: gpio@50006000 { @@ -72,8 +69,7 @@ reg = <0x4000 0x400>; clocks = <&rcc GPIOE>; st,bank-name = "GPIOE"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 64 16>; + status = "disabled"; }; gpiof: gpio@50007000 { @@ -84,8 +80,7 @@ reg = <0x5000 0x400>; clocks = <&rcc GPIOF>; st,bank-name = "GPIOF"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 80 16>; + status = "disabled"; }; gpiog: gpio@50008000 { @@ -96,8 +91,7 @@ reg = <0x6000 0x400>; clocks = <&rcc GPIOG>; st,bank-name = "GPIOG"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 96 16>; + status = "disabled"; }; gpioh: gpio@50009000 { @@ -108,8 +102,7 @@ reg = <0x7000 0x400>; clocks = <&rcc GPIOH>; st,bank-name = "GPIOH"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 112 16>; + status = "disabled"; }; gpioi: gpio@5000a000 { @@ -120,8 +113,7 @@ reg = <0x8000 0x400>; clocks = <&rcc GPIOI>; st,bank-name = "GPIOI"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 128 16>; + status = "disabled"; }; gpioj: gpio@5000b000 { @@ -132,8 +124,7 @@ reg = <0x9000 0x400>; clocks = <&rcc GPIOJ>; st,bank-name = "GPIOJ"; - ngpios = <16>; - gpio-ranges = <&pinctrl 0 144 16>; + status = "disabled"; }; gpiok: gpio@5000c000 { @@ -144,8 +135,29 @@ reg = <0xa000 0x400>; clocks = <&rcc GPIOK>; st,bank-name = "GPIOK"; - ngpios = <8>; - gpio-ranges = <&pinctrl 0 160 8>; + status = "disabled"; + }; + + adc1_in6_pins_a: adc1-in6 { + pins { + pinmux = ; + }; + }; + + adc12_ain_pins_a: adc12-ain-0 { + pins { + pinmux = , /* ADC1 in13 */ + , /* ADC1 in6 */ + , /* ADC2 in2 */ + ; /* ADC2 in6 */ + }; + }; + + adc12_usb_pwr_pins_a: adc12-usb-pwr-pins-0 { + pins { + pinmux = , /* ADC12 in18 */ + ; /* ADC12 in19 */ + }; }; cec_pins_a: cec-0 { @@ -153,180 +165,1374 @@ pinmux = ; bias-disable; drive-open-drain; - slew-rate = <0>; + slew-rate = <0>; + }; + }; + + cec_pins_sleep_a: cec-sleep-0 { + pins { + pinmux = ; /* HDMI_CEC */ + }; + }; + + cec_pins_b: cec-1 { + pins { + pinmux = ; + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + + cec_pins_sleep_b: cec-sleep-1 { + pins { + pinmux = ; /* HDMI_CEC */ + }; + }; + + dac_ch1_pins_a: dac-ch1 { + pins { + pinmux = ; + }; + }; + + dac_ch2_pins_a: dac-ch2 { + pins { + pinmux = ; + }; + }; + + dcmi_pins_a: dcmi-0 { + pins { + pinmux = ,/* DCMI_HSYNC */ + ,/* DCMI_VSYNC */ + ,/* DCMI_PIXCLK */ + ,/* DCMI_D0 */ + ,/* DCMI_D1 */ + ,/* DCMI_D2 */ + ,/* DCMI_D3 */ + ,/* DCMI_D4 */ + ,/* DCMI_D5 */ + ,/* DCMI_D6 */ + ,/* DCMI_D7 */ + ,/* DCMI_D8 */ + ,/* DCMI_D9 */ + ,/* DCMI_D10 */ + ;/* DCMI_D11 */ + bias-disable; + }; + }; + + dcmi_sleep_pins_a: dcmi-sleep-0 { + pins { + pinmux = ,/* DCMI_HSYNC */ + ,/* DCMI_VSYNC */ + ,/* DCMI_PIXCLK */ + ,/* DCMI_D0 */ + ,/* DCMI_D1 */ + ,/* DCMI_D2 */ + ,/* DCMI_D3 */ + ,/* DCMI_D4 */ + ,/* DCMI_D5 */ + ,/* DCMI_D6 */ + ,/* DCMI_D7 */ + ,/* DCMI_D8 */ + ,/* DCMI_D9 */ + ,/* DCMI_D10 */ + ;/* DCMI_D11 */ + }; + }; + + dfsdm_clkout_pins_a: dfsdm-clkout-pins-0 { + pins { + pinmux = ; /* DFSDM_CKOUT */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + }; + + dfsdm_clkout_sleep_pins_a: dfsdm-clkout-sleep-pins-0 { + pins { + pinmux = ; /* DFSDM_CKOUT */ + }; + }; + + dfsdm_data1_pins_a: dfsdm-data1-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA1 */ + }; + }; + + dfsdm_data1_sleep_pins_a: dfsdm-data1-sleep-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA1 */ + }; + }; + + dfsdm_data3_pins_a: dfsdm-data3-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA3 */ + }; + }; + + dfsdm_data3_sleep_pins_a: dfsdm-data3-sleep-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA3 */ + }; + }; + + 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 = <2>; + }; + 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 */ + }; + }; + + fmc_pins_a: fmc-0 { + pins1 { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + ; /* FMC_NE2_FMC_NCE */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + pins2 { + pinmux = ; /* FMC_NWAIT */ + bias-pull-up; + }; + }; + + fmc_sleep_pins_a: fmc-sleep-0 { + pins { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + , /* FMC_NWAIT */ + ; /* FMC_NE2_FMC_NCE */ + }; + }; + + hdp0_pins_a: hdp0-0 { + pins { + pinmux = ; /* HDP0 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp0_pins_sleep_a: hdp0-sleep-0 { + pins { + pinmux = ; /* HDP0 */ + }; + }; + + hdp0_pins_b: hdp0-1 { + pins { + pinmux = ; /* HDP0 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp0_pins_sleep_b: hdp0-sleep-1 { + pins { + pinmux = ; /* HDP0 */ + }; + }; + + hdp1_pins_a: hdp1-0 { + pins { + pinmux = ; /* HDP1 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp1_pins_sleep_a: hdp1-sleep-0 { + pins { + pinmux = ; /* HDP1 */ + }; + }; + + hdp1_pins_b: hdp1-1 { + pins { + pinmux = ; /* HDP1 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp1_pins_sleep_b: hdp1-sleep-1 { + pins { + pinmux = ; /* HDP1 */ + }; + }; + + hdp2_pins_a: hdp2-0 { + pins { + pinmux = ; /* HDP2 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp2_pins_sleep_a: hdp2-sleep-0 { + pins { + pinmux = ; /* HDP2 */ + }; + }; + + hdp2_pins_b: hdp2-1 { + pins { + pinmux = ; /* HDP2 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp2_pins_sleep_b: hdp2-sleep-1 { + pins { + pinmux = ; /* HDP2 */ + }; + }; + + hdp3_pins_a: hdp3-0 { + pins { + pinmux = ; /* HDP3 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp3_pins_sleep_a: hdp3-sleep-0 { + pins { + pinmux = ; /* HDP3 */ + }; + }; + + hdp3_pins_b: hdp3-1 { + pins { + pinmux = ; /* HDP3 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp3_pins_sleep_b: hdp3-sleep-1 { + pins { + pinmux = ; /* HDP3 */ + }; + }; + + hdp4_pins_a: hdp4-0 { + pins { + pinmux = ; /* HDP4 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp4_pins_sleep_a: hdp4-sleep-0 { + pins { + pinmux = ; /* HDP4 */ + }; + }; + + hdp4_pins_b: hdp4-1 { + pins { + pinmux = ; /* HDP4 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp4_pins_sleep_b: hdp4-sleep-1 { + pins { + pinmux = ; /* HDP4 */ + }; + }; + + hdp5_pins_a: hdp5-0 { + pins { + pinmux = ; /* HDP5 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp5_pins_sleep_a: hdp5-sleep-0 { + pins { + pinmux = ; /* HDP5 */ + }; + }; + + hdp5_pins_b: hdp5-1 { + pins { + pinmux = ; /* HDP5 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp5_pins_sleep_b: hdp5-sleep-1 { + pins { + pinmux = ; /* HDP5 */ + }; + }; + + hdp6_pins_a: hdp6-0 { + pins { + pinmux = ; /* HDP6 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp6_pins_sleep_a: hdp6-sleep-0 { + pins { + pinmux = ; /* HDP6 */ + }; + }; + + hdp6_pins_b: hdp6-1 { + pins { + pinmux = ; /* HDP6 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp6_pins_sleep_b: hdp6-sleep-1 { + pins { + pinmux = ; /* HDP6 */ + }; + }; + + hdp7_pins_a: hdp7-0 { + pins { + pinmux = ; /* HDP7 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp7_pins_sleep_a: hdp7-sleep-0 { + pins { + pinmux = ; /* HDP7 */ + }; + }; + + hdp7_pins_b: hdp7-1 { + pins { + pinmux = ; /* HDP7 */ + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + }; + + hdp7_pins_sleep_b: hdp7-sleep-1 { + pins { + pinmux = ; /* HDP7 */ + }; + }; + + i2c1_pins_a: i2c1-0 { + pins { + pinmux = , /* I2C1_SCL */ + ; /* I2C1_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + + i2c1_pins_sleep_a: i2c1-1 { + pins { + pinmux = , /* I2C1_SCL */ + ; /* I2C1_SDA */ + }; + }; + + i2c2_pins_a: i2c2-0 { + pins { + pinmux = , /* I2C2_SCL */ + ; /* I2C2_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + + i2c2_pins_sleep_a: i2c2-1 { + pins { + pinmux = , /* I2C2_SCL */ + ; /* I2C2_SDA */ + }; + }; + + i2c5_pins_a: i2c5-0 { + pins { + pinmux = , /* I2C5_SCL */ + ; /* I2C5_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + + i2c5_pins_sleep_a: i2c5-1 { + pins { + pinmux = , /* I2C5_SCL */ + ; /* I2C5_SDA */ + + }; + }; + + i2s2_pins_a: i2s2-0 { + pins { + pinmux = , /* I2S2_SDO */ + , /* I2S2_WS */ + ; /* I2S2_CK */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + }; + + i2s2_pins_sleep_a: i2s2-1 { + pins { + pinmux = , /* I2S2_SDO */ + , /* I2S2_WS */ + ; /* I2S2_CK */ + }; + }; + + ltdc_pins_a: ltdc-a-0 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + }; + + ltdc_pins_sleep_a: ltdc-a-1 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + }; + }; + + ltdc_pins_b: ltdc-b-0 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + }; + + ltdc_pins_sleep_b: ltdc-b-1 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + }; + }; + + m_can1_pins_a: m-can1-0 { + pins1 { + pinmux = ; /* CAN1_TX */ + slew-rate = <0>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-disable; + }; + }; + + m_can1_sleep_pins_a: m_can1-sleep@0 { + pins { + pinmux = , /* CAN1_TX */ + ; /* CAN1_RX */ + }; + }; + + pwm1_pins_a: pwm1-0 { + pins { + pinmux = , /* TIM1_CH1 */ + , /* TIM1_CH2 */ + ; /* TIM1_CH4 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm1_sleep_pins_a: pwm1-sleep-0 { + pins { + pinmux = , /* TIM1_CH1 */ + , /* TIM1_CH2 */ + ; /* TIM1_CH4 */ + }; + }; + + pwm2_pins_a: pwm2-0 { + pins { + pinmux = ; /* TIM2_CH4 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm2_sleep_pins_a: pwm2-sleep-0 { + pins { + pinmux = ; /* TIM2_CH4 */ + }; + }; + + pwm3_pins_a: pwm3-0 { + pins { + pinmux = ; /* TIM3_CH2 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm3_sleep_pins_a: pwm3-sleep-0 { + pins { + pinmux = ; /* TIM3_CH2 */ + }; + }; + + pwm4_pins_a: pwm4-0 { + pins { + pinmux = , /* TIM4_CH3 */ + ; /* TIM4_CH4 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm4_sleep_pins_a: pwm4-sleep-0 { + pins { + pinmux = , /* TIM4_CH3 */ + ; /* TIM4_CH4 */ + }; + }; + + pwm4_pins_b: pwm4-1 { + pins { + pinmux = ; /* TIM4_CH2 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm4_sleep_pins_b: pwm4-sleep-1 { + pins { + pinmux = ; /* TIM4_CH2 */ + }; + }; + + pwm5_pins_a: pwm5-0 { + pins { + pinmux = ; /* TIM5_CH2 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm5_sleep_pins_a: pwm5-sleep-0 { + pins { + pinmux = ; /* TIM5_CH2 */ + }; + }; + + pwm8_pins_a: pwm8-0 { + pins { + pinmux = ; /* TIM8_CH4 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm8_sleep_pins_a: pwm8-sleep-0 { + pins { + pinmux = ; /* TIM8_CH4 */ + }; + }; + + pwm12_pins_a: pwm12-0 { + pins { + pinmux = ; /* TIM12_CH1 */ + bias-pull-down; + drive-push-pull; + slew-rate = <0>; + }; + }; + + pwm12_sleep_pins_a: pwm12-sleep-0 { + pins { + pinmux = ; /* TIM12_CH1 */ + }; + }; + + qspi_bk1_pins_a: qspi-bk1-0 { + pins1 { + pinmux = , /* QSPI_BK1_IO0 */ + , /* QSPI_BK1_IO1 */ + , /* QSPI_BK1_IO2 */ + ; /* QSPI_BK1_IO3 */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + pins2 { + pinmux = ; /* QSPI_BK1_NCS */ + bias-pull-up; + drive-push-pull; + slew-rate = <1>; + }; + }; + + qspi_bk1_sleep_pins_a: qspi-bk1-sleep-0 { + pins { + pinmux = , /* QSPI_BK1_IO0 */ + , /* QSPI_BK1_IO1 */ + , /* QSPI_BK1_IO2 */ + , /* QSPI_BK1_IO3 */ + ; /* QSPI_BK1_NCS */ + }; + }; + + qspi_bk2_pins_a: qspi-bk2-0 { + pins1 { + pinmux = , /* QSPI_BK2_IO0 */ + , /* QSPI_BK2_IO1 */ + , /* QSPI_BK2_IO2 */ + ; /* QSPI_BK2_IO3 */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + pins2 { + pinmux = ; /* QSPI_BK2_NCS */ + bias-pull-up; + drive-push-pull; + slew-rate = <1>; + }; + }; + + qspi_bk2_sleep_pins_a: qspi-bk2-sleep-0 { + pins { + pinmux = , /* QSPI_BK2_IO0 */ + , /* QSPI_BK2_IO1 */ + , /* QSPI_BK2_IO2 */ + , /* QSPI_BK2_IO3 */ + ; /* QSPI_BK2_NCS */ + }; + }; + + qspi_clk_pins_a: qspi-clk-0 { + pins { + pinmux = ; /* QSPI_CLK */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + }; + + qspi_clk_sleep_pins_a: qspi-clk-sleep-0 { + pins { + pinmux = ; /* QSPI_CLK */ + }; + }; + + rtc_out2_rmp_pins_a: rtc-out2-rmp-pins@0 { + pins { + pinmux = ; /* RTC_OUT2_RMP */ + }; + }; + + sai2a_pins_a: sai2a-0 { + pins { + pinmux = , /* SAI2_SCK_A */ + , /* SAI2_SD_A */ + , /* SAI2_FS_A */ + ; /* SAI2_MCLK_A */ + slew-rate = <0>; + drive-push-pull; + bias-disable; + }; + }; + + sai2a_sleep_pins_a: sai2a-1 { + pins { + pinmux = , /* SAI2_SCK_A */ + , /* SAI2_SD_A */ + , /* SAI2_FS_A */ + ; /* SAI2_MCLK_A */ + }; + }; + + sai2b_pins_a: sai2b-0 { + pins1 { + pinmux = , /* SAI2_SCK_B */ + , /* SAI2_FS_B */ + ; /* SAI2_MCLK_B */ + slew-rate = <0>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* SAI2_SD_B */ + bias-disable; + }; + }; + + sai2b_sleep_pins_a: sai2b-1 { + pins { + pinmux = , /* SAI2_SD_B */ + , /* SAI2_SCK_B */ + , /* SAI2_FS_B */ + ; /* SAI2_MCLK_B */ + }; + }; + + sai2b_pins_b: sai2b-2 { + pins { + pinmux = ; /* SAI2_SD_B */ + bias-disable; + }; + }; + + sai2b_sleep_pins_b: sai2b-3 { + pins { + pinmux = ; /* SAI2_SD_B */ + }; + }; + + sai4a_pins_a: sai4a-0 { + pins { + pinmux = ; /* SAI4_SD_A */ + slew-rate = <0>; + drive-push-pull; + bias-disable; + }; + }; + + sai4a_sleep_pins_a: sai4a-1 { + pins { + pinmux = ; /* SAI4_SD_A */ + }; + }; + + sdmmc1_b4_pins_a: sdmmc1-b4-0 { + pins1 { + pinmux = , /* SDMMC1_D0 */ + , /* SDMMC1_D1 */ + , /* SDMMC1_D2 */ + , /* SDMMC1_D3 */ + ; /* SDMMC1_CMD */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* SDMMC1_CK */ + slew-rate = <2>; + drive-push-pull; + bias-disable; + }; + }; + + sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 { + pins1 { + pinmux = , /* SDMMC1_D0 */ + , /* SDMMC1_D1 */ + , /* SDMMC1_D2 */ + ; /* SDMMC1_D3 */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* SDMMC1_CK */ + slew-rate = <2>; + drive-push-pull; + bias-disable; + }; + pins3 { + pinmux = ; /* SDMMC1_CMD */ + slew-rate = <1>; + drive-open-drain; + bias-disable; }; }; - i2c1_pins_a: i2c1-0 { + sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { pins { - pinmux = , /* I2C1_SCL */ - ; /* I2C1_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; + pinmux = , /* SDMMC1_D0 */ + , /* SDMMC1_D1 */ + , /* SDMMC1_D2 */ + , /* SDMMC1_D3 */ + , /* SDMMC1_CK */ + ; /* SDMMC1_CMD */ }; }; - i2c2_pins_a: i2c2-0 { + sdmmc1_dir_pins_a: sdmmc1-dir-0 { + pins1 { + pinmux = , /* SDMMC1_D0DIR */ + , /* SDMMC1_D123DIR */ + ; /* SDMMC1_CDIR */ + slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; + pins2{ + pinmux = ; /* SDMMC1_CKIN */ + bias-pull-up; + }; + }; + + sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 { pins { - pinmux = , /* I2C2_SCL */ - ; /* I2C2_SDA */ - bias-disable; + pinmux = , /* SDMMC1_D0DIR */ + , /* SDMMC1_D123DIR */ + , /* SDMMC1_CDIR */ + ; /* SDMMC1_CKIN */ + }; + }; + + sdmmc2_b4_pins_a: sdmmc2-b4-0 { + pins1 { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ + ; /* SDMMC2_CMD */ + slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; + pins2 { + pinmux = ; /* SDMMC2_CK */ + slew-rate = <2>; + drive-push-pull; + bias-pull-up; + }; + }; + + sdmmc2_b4_od_pins_a: sdmmc2-b4-od-0 { + pins1 { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + ; /* SDMMC2_D3 */ + slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; + pins2 { + pinmux = ; /* SDMMC2_CK */ + slew-rate = <2>; + drive-push-pull; + bias-pull-up; + }; + pins3 { + pinmux = ; /* SDMMC2_CMD */ + slew-rate = <1>; drive-open-drain; - slew-rate = <0>; + bias-pull-up; }; }; - i2c5_pins_a: i2c5-0 { + sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 { pins { - pinmux = , /* I2C5_SCL */ - ; /* I2C5_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ + , /* SDMMC2_CK */ + ; /* SDMMC2_CMD */ }; }; - pwm2_pins_a: pwm2-0 { + sdmmc2_d47_pins_a: sdmmc2-d47-0 { pins { - pinmux = ; /* TIM2_CH4 */ - bias-pull-down; + pinmux = , /* SDMMC2_D4 */ + , /* SDMMC2_D5 */ + , /* SDMMC2_D6 */ + ; /* SDMMC2_D7 */ + slew-rate = <1>; drive-push-pull; - slew-rate = <0>; + bias-pull-up; }; }; - pwm8_pins_a: pwm8-0 { + sdmmc2_d47_sleep_pins_a: sdmmc2-d47-sleep-0 { pins { - pinmux = ; /* TIM8_CH4 */ - bias-pull-down; + pinmux = , /* SDMMC2_D4 */ + , /* SDMMC2_D5 */ + , /* SDMMC2_D6 */ + ; /* SDMMC2_D7 */ + }; + }; + + sdmmc3_b4_pins_a: sdmmc3-b4-0 { + pins1 { + pinmux = , /* SDMMC3_D0 */ + , /* SDMMC3_D1 */ + , /* SDMMC3_D2 */ + , /* SDMMC3_D3 */ + ; /* SDMMC3_CMD */ + slew-rate = <1>; drive-push-pull; - slew-rate = <0>; + bias-pull-up; + }; + pins2 { + pinmux = ; /* SDMMC3_CK */ + slew-rate = <2>; + drive-push-pull; + bias-pull-up; }; }; - pwm12_pins_a: pwm12-0 { - pins { - pinmux = ; /* TIM12_CH1 */ - bias-pull-down; + sdmmc3_b4_od_pins_a: sdmmc3-b4-od-0 { + pins1 { + pinmux = , /* SDMMC3_D0 */ + , /* SDMMC3_D1 */ + , /* SDMMC3_D2 */ + ; /* SDMMC3_D3 */ + slew-rate = <1>; drive-push-pull; - slew-rate = <0>; + bias-pull-up; + }; + pins2 { + pinmux = ; /* SDMMC3_CK */ + slew-rate = <2>; + drive-push-pull; + bias-pull-up; + }; + pins3 { + pinmux = ; /* SDMMC2_CMD */ + slew-rate = <1>; + drive-open-drain; + bias-pull-up; }; }; - qspi_clk_pins_a: qspi-clk-0 { + sdmmc3_b4_sleep_pins_a: sdmmc3-b4-sleep-0 { pins { - pinmux = ; /* QSPI_CLK */ + pinmux = , /* SDMMC3_D0 */ + , /* SDMMC3_D1 */ + , /* SDMMC3_D2 */ + , /* SDMMC3_D3 */ + , /* SDMMC3_CK */ + ; /* SDMMC3_CMD */ + }; + }; + + spdifrx_pins_a: spdifrx-0 { + pins { + pinmux = ; /* SPDIF_IN1 */ bias-disable; - drive-push-pull; - slew-rate = <3>; }; }; - qspi_bk1_pins_a: qspi-bk1-0 { + spdifrx_sleep_pins_a: spdifrx-1 { + pins { + pinmux = ; /* SPDIF_IN1 */ + }; + }; + + spi4_pins_a: spi4-0 { pins1 { - pinmux = , /* QSPI_BK1_IO0 */ - , /* QSPI_BK1_IO1 */ - , /* QSPI_BK1_IO2 */ - ; /* QSPI_BK1_IO3 */ + pinmux = , /* SPI4_SCK */ + ; /* SPI4_MOSI */ bias-disable; drive-push-pull; - slew-rate = <3>; + slew-rate = <1>; }; + pins2 { - pinmux = ; /* QSPI_BK1_NCS */ - bias-pull-up; - drive-push-pull; - slew-rate = <3>; + pinmux = ; /* SPI4_MISO */ + bias-disable; }; }; - qspi_bk2_pins_a: qspi-bk2-0 { + spi4_sleep_pins_a: spi4-sleep-0 { + pins { + pinmux = , /* SPI4_SCK */ + , /* SPI4_MISO */ + ; /* SPI4_MOSI */ + }; + }; + + spi5_pins_a: spi5-0 { pins1 { - pinmux = , /* QSPI_BK2_IO0 */ - , /* QSPI_BK2_IO1 */ - , /* QSPI_BK2_IO2 */ - ; /* QSPI_BK2_IO3 */ + pinmux = , /* SPI5_SCK */ + ; /* SPI5_MOSI */ bias-disable; drive-push-pull; - slew-rate = <3>; + slew-rate = <1>; }; + pins2 { - pinmux = ; /* QSPI_BK2_NCS */ - bias-pull-up; - drive-push-pull; - slew-rate = <3>; + pinmux = ; /* SPI5_MISO */ + bias-disable; }; }; - sdmmc1_b4_pins_a: sdmmc1-b4@0 { + + spi5_sleep_pins_a: spi5-sleep-0 { pins { - pinmux = , /* SDMMC1_D0 */ - , /* SDMMC1_D1 */ - , /* SDMMC1_D2 */ - , /* SDMMC1_D3 */ - , /* SDMMC1_CK */ - ; /* SDMMC1_CMD */ - slew-rate = <3>; + pinmux = , /* SPI5_SCK */ + , /* SPI5_MISO */ + ; /* SPI5_MOSI */ + }; + }; + + uart4_pins_a: uart4-0 { + pins1 { + pinmux = ; /* UART4_TX */ + bias-disable; drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* UART4_RX */ + bias-disable; + }; + }; + + uart4_idle_pins_a: uart4-idle-0 { + pins1 { + pinmux = ; /* UART4_TX */ + }; + pins2 { + pinmux = ; /* UART4_RX */ bias-disable; }; }; - sdmmc1_dir_pins_a: sdmmc1-dir@0 { + uart4_sleep_pins_a: uart4-sleep-0 { pins { - pinmux = , /* SDMMC1_D0DIR */ - , /* SDMMC1_D123DIR */ - , /* SDMMC1_CDIR */ - ; /* SDMMC1_CKIN */ - slew-rate = <3>; + pinmux = , /* UART4_TX */ + ; /* UART4_RX */ + }; + }; + + usart2_pins_a: usart2-0 { + pins1 { + pinmux = , /* USART2_TX */ + ; /* USART2_RTS */ + bias-disable; drive-push-pull; - bias-pull-up; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* USART2_RX */ + ; /* USART2_CTS_NSS */ + bias-disable; + }; + }; + + usart2_idle_pins_a: usart2-idle-0 { + pins1 { + pinmux = , /* USART2_TX */ + , /* USART2_RTS */ + ; /* USART2_CTS_NSS */ + }; + pins2 { + pinmux = ; /* USART2_RX */ + bias-disable; }; }; - sdmmc2_b4_pins_a: sdmmc2-b4@0 { + + usart2_sleep_pins_a: usart2-sleep-0 { pins { - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ - , /* SDMMC2_D3 */ - , /* SDMMC2_CK */ - ; /* SDMMC2_CMD */ - slew-rate = <3>; + pinmux = , /* USART2_TX */ + , /* USART2_RTS */ + , /* USART2_RX */ + ; /* USART2_CTS_NSS */ + }; + }; + + usart3_pins_a: usart3-0 { + pins1 { + pinmux = , /* USART3_TX */ + ; /* USART3_RTS */ + bias-disable; drive-push-pull; - bias-pull-up; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* USART3_RX */ + ; /* USART3_CTS_NSS */ + bias-disable; + }; + }; + + usart3_idle_pins_a: usart3-idle-0 { + pins1 { + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + ; /* USART3_CTS_NSS */ + }; + pins2 { + pinmux = ; /* USART3_RX */ + bias-disable; }; }; - sdmmc2_d47_pins_a: sdmmc2-d47@0 { + usart3_sleep_pins_a: usart3-sleep-0 { pins { - pinmux = , /* SDMMC2_D4 */ - , /* SDMMC2_D5 */ - , /* SDMMC2_D6 */ - ; /* SDMMC2_D7 */ - slew-rate = <3>; - drive-push-pull; - bias-pull-up; + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + , /* USART3_CTS_NSS */ + ; /* USART3_RX */ }; }; - uart4_pins_a: uart4-0 { + usart3_pins_b: usart3-1 { pins1 { - pinmux = ; /* UART4_TX */ + pinmux = , /* USART3_TX */ + ; /* USART3_RTS */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { - pinmux = ; /* UART4_RX */ + pinmux = , /* USART3_RX */ + ; /* USART3_CTS_NSS */ bias-disable; }; }; + usart3_idle_pins_b: usart3-idle-1 { + pins1 { + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + ; /* USART3_CTS_NSS */ + }; + pins2 { + pinmux = ; /* USART3_RX */ + bias-disable; + }; + }; + + usart3_sleep_pins_b: usart3-sleep-1 { + pins { + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + , /* USART3_CTS_NSS */ + ; /* USART3_RX */ + }; + }; + usbotg_hs_pins_a: usbotg_hs-0 { pins { pinmux = ; /* OTG_ID */ }; }; + + usbotg_fs_dp_dm_pins_a: usbotg-fs-dp-dm-0 { + pins { + pinmux = , /* OTG_FS_DM */ + ; /* OTG_FS_DP */ + }; + }; }; pinctrl_z: pin-controller-z@54004000 { @@ -337,6 +1543,7 @@ pins-are-numbered; interrupt-parent = <&exti>; st,syscfg = <&exti 0x60 0xff>; + hwlocks = <&hsem 0>; gpioz: gpio@54004000 { gpio-controller; @@ -347,8 +1554,17 @@ clocks = <&rcc GPIOZ>; st,bank-name = "GPIOZ"; st,bank-ioport = <11>; - ngpios = <8>; - gpio-ranges = <&pinctrl_z 0 400 8>; + status = "disabled"; + }; + + btreg: bt_reg_on-0 { + pins { + pinmux = ; + drive-push-pull; + bias-pull-up; + output-high; + slew-rate = <0>; + }; }; i2c4_pins_a: i2c4-0 { @@ -360,6 +1576,36 @@ slew-rate = <0>; }; }; + + i2c4_pins_sleep_a: i2c4-1 { + pins { + pinmux = , /* I2C4_SCL */ + ; /* I2C4_SDA */ + }; + }; + + 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; + }; + }; + + spi1_sleep_pins_a: spi1-sleep-0 { + pins { + pinmux = , /* SPI1_SCK */ + , /* SPI1_MISO */ + ; /* SPI1_MOSI */ + }; + }; }; }; }; diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 90d13f35c462..035b1c608fbf 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -17,19 +17,31 @@ gpio9 = &gpioj; gpio10 = &gpiok; gpio25 = &gpioz; + pinctrl0 = &pinctrl; + pinctrl1 = &pinctrl_z; + }; + + clocks { + u-boot,dm-pre-reloc; }; config { u-boot,dm-pre-reloc; }; - clocks { + reboot { u-boot,dm-pre-reloc; }; soc { u-boot,dm-pre-reloc; + etzpc: etzpc@5C007000 { + compatible = "st,stm32mp1-etzpc"; + reg = <0x5C007000 0x400>; + status = "okay"; + }; + stgen: stgen@5C008000 { compatible = "st,stm32-stgen"; reg = <0x5C008000 0x1000>; @@ -39,19 +51,7 @@ }; }; -&clk_hsi { - u-boot,dm-pre-reloc; -}; - -&clk_hse { - u-boot,dm-pre-reloc; -}; - -&clk_lse { - u-boot,dm-pre-reloc; -}; - -&clk_lsi { +&bsec { u-boot,dm-pre-reloc; }; @@ -59,19 +59,19 @@ u-boot,dm-pre-reloc; }; -&rcc { +&clk_hsi { u-boot,dm-pre-reloc; }; -&rcc_reboot { +&clk_hse { u-boot,dm-pre-reloc; }; -&pinctrl { +&clk_lsi { u-boot,dm-pre-reloc; }; -&pinctrl_z { +&clk_lse { u-boot,dm-pre-reloc; }; @@ -134,3 +134,40 @@ compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; + +&iwdg2 { + u-boot,dm-pre-reloc; +}; + +/* pre-reloc probe = reserve video frame buffer in video_reserve() */ +<dc { + u-boot,dm-pre-reloc; +}; + +&pinctrl { + u-boot,dm-pre-reloc; +}; + +&pinctrl_z { + u-boot,dm-pre-reloc; +}; + +&pwr { + u-boot,dm-pre-reloc; +}; + +&rcc { + u-boot,dm-pre-reloc; +}; + +&sdmmc1 { + compatible = "st,stm32-sdmmc2"; +}; + +&sdmmc2 { + compatible = "st,stm32-sdmmc2"; +}; + +&sdmmc3 { + compatible = "st,stm32-sdmmc2"; +}; 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 000000000000..0f9ed9f47ac0 --- /dev/null +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -0,0 +1,190 @@ +// 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>; + st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; + }; + 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; + + stusb1600: typec@28 { + #extcon-cells = <0>; + compatible = "st,stusb1600"; + reg = <0x28>; + status = "okay"; + }; +}; + +&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; + pins1 { + u-boot,dm-spl; + }; + pins2 { + 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 000000000000..e3d305a43fb5 --- /dev/null +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue . + */ + +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157cac-pinctrl.dtsi" +#include +#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>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + retram: retram@0x38000000 { + compatible = "shared-dma-pool"; + reg = <0x38000000 0x10000>; + no-map; + }; + + mcuram: mcuram@0x30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; + no-map; + }; + + mcuram2: mcuram2@0x10000000 { + compatible = "shared-dma-pool"; + reg = <0x10000000 0x40000>; + no-map; + }; + + vdev0vring0: vdev0vring0@10040000 { + compatible = "shared-dma-pool"; + reg = <0x10040000 0x2000>; + no-map; + }; + + vdev0vring1: vdev0vring1@10042000 { + compatible = "shared-dma-pool"; + reg = <0x10042000 0x2000>; + no-map; + }; + + vdev0buffer: vdev0buffer@10044000 { + compatible = "shared-dma-pool"; + reg = <0x10044000 0x4000>; + no-map; + }; + + gpu_reserved: gpu@dc000000 { + reg = <0xdc000000 0x4000000>; + no-map; + }; + }; + + sram: sram@10050000 { + compatible = "mmio-sram"; + reg = <0x10050000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10050000 0x10000>; + + dma_pool: dma_pool@0 { + reg = <0x0 0x10000>; + pool; + }; + }; + + led { + compatible = "gpio-leds"; + blue { + label = "heartbeat"; + gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + }; + + sound { + compatible = "audio-graph-card"; + label = "STM32MP1-DK"; + routing = + "Playback" , "MCLK", + "Capture" , "MCLK", + "MICL" , "Mic Bias"; + dais = <&sai2a_port &sai2b_port &i2s2_port>; + status = "okay"; + }; + + usb_phy_tuning: usb-phy-tuning { + st,hs-dc-level = <2>; + st,fs-rftime-tuning; + st,hs-rftime-reduction; + st,hs-current-trim = <15>; + st,hs-impedance-trim = <1>; + st,squelch-level = <3>; + st,hs-rx-offset = <2>; + st,no-lsfs-sc; + }; +}; + +&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"; + }; + adc2: adc@100 { + /* ANA0, ANA1, temp sensor, USB Type-C CC1 & CC2 */ + st,adc-channels = <0 1 12 18 19>; + /* temperature sensor min sample time */ + st,min-sample-time-nsecs = <10000>; + status = "okay"; + }; + adc_temp: temp { + status = "okay"; + }; +}; + +&cec { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cec_pins_b>; + pinctrl-1 = <&cec_pins_sleep_b>; + status = "okay"; +}; + +&dma1 { + sram = <&dma_pool>; +}; + +&dma2 { + sram = <&dma_pool>; +}; + +&dts { + status = "okay"; +}; + +ð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>; + }; + }; +}; + +&gpu { + contiguous-area = <&gpu_reserved>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2c1_pins_a>; + pinctrl-1 = <&i2c1_pins_sleep_a>; + i2c-scl-rising-time-ns = <100>; + i2c-scl-falling-time-ns = <7>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; + + cs42l51: cs42l51@4a { + compatible = "cirrus,cs42l51"; + reg = <0x4a>; + #sound-dai-cells = <0>; + status = "okay"; + + VL-supply = <&v3v3>; + VD-supply = <&v1v8_audio>; + VA-supply = <&v1v8_audio>; + VAHP-supply = <&v1v8_audio>; + + reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>; + + clocks = <&sai2a>; + clock-names = "MCLK"; + + cs42l51_port: port { + #address-cells = <1>; + #size-cells = <0>; + + cs42l51_tx_endpoint: endpoint@0 { + reg = <0>; + remote-endpoint = <&sai2a_endpoint>; + frame-master; + bitclock-master; + }; + + cs42l51_rx_endpoint: endpoint@1 { + reg = <1>; + remote-endpoint = <&sai2b_endpoint>; + frame-master; + bitclock-master; + }; + }; + }; + + hdmi-transmitter@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + iovcc-supply = <&v3v3_hdmi>; + cvcc12-supply = <&v1v2_hdmi>; + reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpiog>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <<dc_pins_a>; + pinctrl-1 = <<dc_pins_sleep_a>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + sii9022_in: endpoint { + remote-endpoint = <<dc_ep0_out>; + }; + }; + + port@1 { + reg = <1>; + sii9022_tx_endpoint: endpoint { + remote-endpoint = <&i2s2_endpoint>; + }; + }; + }; + }; +}; + +&i2c4 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2c4_pins_a>; + pinctrl-1 = <&i2c4_pins_sleep_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>; + interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; + st,usb-control-register = <0x30>; + + 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 = <800000>; + 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"; + }; + }; +}; + +&i2s2 { + clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2s2_pins_a>; + pinctrl-1 = <&i2s2_pins_sleep_a>; + status = "okay"; + + i2s2_port: port { + i2s2_endpoint: endpoint { + remote-endpoint = <&sii9022_tx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + }; + }; +}; + +&ipcc { + status = "okay"; +}; + +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +<dc { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&sii9022_in>; + }; + }; +}; + +&m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; + mbox-names = "vq0", "vq1", "shutdown"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + interrupt-names = "wdg"; + recovery; + status = "okay"; +}; + +&pwr { + pwr-supply = <&vdd>; +}; + +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&sai2 { + clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>; + clock-names = "pclk", "x8k", "x11k"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>; + pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>; + status = "okay"; + + sai2a: audio-controller@4400b004 { + #clock-cells = <0>; + dma-names = "tx"; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; + status = "okay"; + + sai2a_port: port { + sai2a_endpoint: endpoint { + remote-endpoint = <&cs42l51_tx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + }; + + sai2b: audio-controller@4400b024 { + dma-names = "rx"; + st,sync = <&sai2a 2>; + status = "okay"; + clocks = <&rcc SAI2_K>, <&sai2a>; + clock-names = "sai_ck", "MCLK"; + + sai2b_port: port { + sai2b_endpoint: endpoint { + remote-endpoint = <&cs42l51_rx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; + }; + }; +}; + +&sdmmc1 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; + broken-cd; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&spi4 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi4_pins_a>; + pinctrl-1 = <&spi4_sleep_pins_a>; + status = "disabled"; +}; + +&spi5 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi5_pins_a>; + pinctrl-1 = <&spi5_sleep_pins_a>; + status = "disabled"; +}; + +&timers1 { + /* spare dmas for other usage */ + /delete-property/dmas; + /delete-property/dma-names; + pwm { + pinctrl-0 = <&pwm1_pins_a>; + pinctrl-1 = <&pwm1_sleep_pins_a>; + pinctrl-names = "default", "sleep"; + status = "okay"; + }; + timer@0 { + status = "okay"; + }; +}; + +&timers3 { + /delete-property/dmas; + /delete-property/dma-names; + pwm { + pinctrl-0 = <&pwm3_pins_a>; + pinctrl-1 = <&pwm3_sleep_pins_a>; + pinctrl-names = "default", "sleep"; + status = "okay"; + }; + timer@2 { + status = "okay"; + }; +}; + +&timers4 { + /delete-property/dmas; + /delete-property/dma-names; + pwm { + pinctrl-0 = <&pwm4_pins_a &pwm4_pins_b>; + pinctrl-1 = <&pwm4_sleep_pins_a &pwm4_sleep_pins_b>; + pinctrl-names = "default", "sleep"; + status = "okay"; + }; + timer@3 { + status = "okay"; + }; +}; + +&timers5 { + /delete-property/dmas; + /delete-property/dma-names; + pwm { + pinctrl-0 = <&pwm5_pins_a>; + pinctrl-1 = <&pwm5_sleep_pins_a>; + pinctrl-names = "default", "sleep"; + status = "okay"; + }; + timer@4 { + status = "okay"; + }; +}; + +&timers6 { + status = "okay"; + /* spare dmas for other usage */ + /delete-property/dmas; + /delete-property/dma-names; + timer@5 { + status = "okay"; + }; +}; + +&timers12 { + /delete-property/dmas; + /delete-property/dma-names; + pwm { + pinctrl-0 = <&pwm12_pins_a>; + pinctrl-1 = <&pwm12_sleep_pins_a>; + pinctrl-names = "default", "sleep"; + status = "okay"; + }; + timer@11 { + status = "okay"; + }; +}; + +&uart4 { + pinctrl-names = "default", "sleep", "idle", "no_console_suspend"; + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; + status = "okay"; +}; + +&usart3 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&usart3_pins_b>; + pinctrl-1 = <&usart3_sleep_pins_b>; + pinctrl-2 = <&usart3_idle_pins_b>; + status = "disabled"; +}; + +&usbh_ehci { + phys = <&usbphyc_port0>; + phy-names = "usb"; + status = "okay"; +}; + +&usbotg_hs { + dr_mode = "peripheral"; + force-b-session-valid; + phys = <&usbphyc_port1 0>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usbphyc { + vdd3v3-supply = <&vdd_usb>; + status = "okay"; +}; + +&usbphyc_port0 { + st,phy-tuning = <&usb_phy_tuning>; +}; + +&usbphyc_port1 { + st,phy-tuning = <&usb_phy_tuning>; +}; + +&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 000000000000..06ef3a4095f1 --- /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 000000000000..c276c59590fc --- /dev/null +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue . + */ + +/dts-v1/; + +#include "stm32mp157a-dk1.dts" +#include + +/ { + model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; + compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; + + aliases { + serial1 = &usart2; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; + }; +}; + +&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_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>; + }; + }; + }; +}; + +&i2c1 { + touchscreen@2a { + compatible = "focaltech,ft6236"; + reg = <0x2a>; + interrupts = <2 2>; + interrupt-parent = <&gpiof>; + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + status = "okay"; + }; + touchscreen@38 { + compatible = "focaltech,ft6336"; + reg = <0x38>; + interrupts = <2 2>; + interrupt-parent = <&gpiof>; + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + status = "okay"; + }; +}; + +<dc { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep1_out: endpoint@1 { + reg = <1>; + remote-endpoint = <&dsi_in>; + }; + }; +}; + +&rtc { + st,lsco = ; + pinctrl-0 = <&rtc_out2_rmp_pins_a>; + pinctrl-names = "default"; +}; + +/* Wifi */ +&sdmmc2 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc2_b4_pins_a>; + pinctrl-1 = <&sdmmc2_b4_od_pins_a>; + pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; + non-removable; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + mmc-pwrseq = <&wifi_pwrseq>; + #address-cells = <1>; + #size-cells = <0>; + keep-power-in-suspend; + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +/* Bluetooth */ +&usart2 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&usart2_pins_a>; + pinctrl-1 = <&usart2_sleep_pins_a>; + pinctrl-2 = <&usart2_idle_pins_a>; + st,hw-flow-ctrl; + status = "okay"; + + bluetooth { + pinctrl-names = "default"; + pinctrl-0 = <&btreg>; + compatible = "brcm,bcm43438-bt"; + max-speed = <3000000>; + }; +}; diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 4898483e1d16..b6bf6f105331 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -9,44 +9,30 @@ / { aliases { + i2c3 = &i2c4; mmc0 = &sdmmc1; mmc1 = &sdmmc2; - i2c3 = &i2c4; }; - led { - compatible = "gpio-leds"; + config { + u-boot,boot-led = "heartbeat"; + st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; + }; - red { - label = "stm32mp:red:status"; - gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; - default-state = "off"; - }; - green { - label = "stm32mp:green:user"; - gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; - default-state = "on"; - }; - orange { - label = "stm32mp:orange:status"; - gpios = <&gpioh 7 GPIO_ACTIVE_HIGH>; - default-state = "off"; - }; + led { blue { - label = "stm32mp:blue:user"; - gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; + default-state = "on"; }; }; }; -&uart4_pins_a { +&clk_hse { + st,digbypass; +}; + +&i2c4 { u-boot,dm-pre-reloc; - pins1 { - u-boot,dm-pre-reloc; - }; - pins2 { - u-boot,dm-pre-reloc; - }; }; &i2c4_pins_a { @@ -56,19 +42,10 @@ }; }; -&uart4 { - u-boot,dm-pre-reloc; -}; - -&i2c4 { - u-boot,dm-pre-reloc; -}; - &pmic { u-boot,dm-pre-reloc; }; -/* CLOCK init */ &rcc { st,clksrc = < CLK_MPU_PLL1P @@ -101,7 +78,7 @@ CLK_FMC_ACLK CLK_QSPI_ACLK CLK_ETH_DISABLED - CLK_SDMMC12_PLL3R + CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE CLK_USBPHY_HSE @@ -110,7 +87,7 @@ CLK_SPI45_HSI CLK_SPI6_HSI CLK_I2C46_HSI - CLK_SDMMC3_PLL3R + CLK_SDMMC3_PLL4P CLK_USBO_USBPHY CLK_ADC_CKPER CLK_CEC_LSE @@ -121,17 +98,17 @@ CLK_UART35_HSI CLK_UART6_HSI CLK_UART78_HSI - CLK_SPDIF_PLL3Q + CLK_SPDIF_PLL4P CLK_FDCAN_PLL4Q CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q CLK_SAI4_PLL3Q - CLK_RNG1_CSI - CLK_RNG2_CSI + CLK_RNG1_LSI + CLK_RNG2_LSI CLK_LPTIM1_PCLK1 CLK_LPTIM23_PCLK3 - CLK_LPTIM45_PCLK3 + CLK_LPTIM45_LSE >; /* VCO = 1300.0 MHz => P = 650 (CPU) */ @@ -148,44 +125,54 @@ u-boot,dm-pre-reloc; }; - /* VCO = 786.4 MHz => P = 197, Q = 49, R = 98 */ + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ pll3: st,pll@2 { - cfg = < 2 97 3 15 7 PQR(1,1,1) >; - frac = < 0x9ba >; + cfg = < 1 33 1 16 36 PQR(1,1,1) >; + frac = < 0x1a04 >; u-boot,dm-pre-reloc; }; - /* VCO = 508.0 MHz => P = 56, Q = 56, R = 56 */ + /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ pll4: st,pll@3 { - cfg = < 5 126 8 8 8 PQR(1,1,1) >; + cfg = < 3 98 5 7 7 PQR(1,1,1) >; u-boot,dm-pre-reloc; }; }; -/* SPL part **************************************/ -/* MMC1 boot */ +&sdmmc1 { + u-boot,dm-spl; +}; + &sdmmc1_b4_pins_a { u-boot,dm-spl; - pins { + pins1 { + u-boot,dm-spl; + }; + pins2 { u-boot,dm-spl; }; }; &sdmmc1_dir_pins_a { u-boot,dm-spl; - pins { + pins1 { + u-boot,dm-spl; + }; + pins2 { u-boot,dm-spl; }; }; -&sdmmc1 { +&sdmmc2 { u-boot,dm-spl; }; -/* MMC2 boot */ &sdmmc2_b4_pins_a { u-boot,dm-spl; - pins { + pins1 { + u-boot,dm-spl; + }; + pins2 { u-boot,dm-spl; }; }; @@ -197,6 +184,16 @@ }; }; -&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 f8b770116711..37edf87e68cc 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -6,22 +6,96 @@ /dts-v1/; #include "stm32mp157c.dtsi" -#include "stm32mp157-pinctrl.dtsi" +#include "stm32mp157caa-pinctrl.dtsi" #include -#include +#include / { model = "STMicroelectronics STM32MP157C eval daughter"; compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; chosen { - stdout-path = "serial3:115200n8"; + stdout-path = "serial0:115200n8"; }; memory@c0000000 { reg = <0xC0000000 0x40000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + retram: retram@0x38000000 { + compatible = "shared-dma-pool"; + reg = <0x38000000 0x10000>; + no-map; + }; + + mcuram: mcuram@0x30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; + no-map; + }; + + mcuram2: mcuram2@0x10000000 { + compatible = "shared-dma-pool"; + reg = <0x10000000 0x40000>; + no-map; + }; + + vdev0vring0: vdev0vring0@10040000 { + compatible = "shared-dma-pool"; + reg = <0x10040000 0x2000>; + no-map; + }; + + vdev0vring1: vdev0vring1@10042000 { + compatible = "shared-dma-pool"; + reg = <0x10042000 0x2000>; + no-map; + }; + + vdev0buffer: vdev0buffer@10044000 { + compatible = "shared-dma-pool"; + reg = <0x10044000 0x4000>; + no-map; + }; + + gpu_reserved: gpu@f8000000 { + reg = <0xf8000000 0x8000000>; + no-map; + }; + }; + + aliases { + serial0 = &uart4; + }; + + sram: sram@10050000 { + compatible = "mmio-sram"; + reg = <0x10050000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10050000 0x10000>; + + dma_pool: dma_pool@0 { + reg = <0x0 0x10000>; + pool; + }; + }; + + led { + compatible = "gpio-leds"; + blue { + label = "heartbeat"; + gpios = <&gpiod 9 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + }; + sd_switch: regulator-sd_switch { compatible = "regulator-gpio"; regulator-name = "sd_switch"; @@ -36,39 +110,87 @@ }; }; -&rng1 { +&adc { + /* ANA0, ANA1 are dedicated pins and don't need pinctrl: only in6. */ + vdd-supply = <&vdd>; + vdda-supply = <&vdda>; + vref-supply = <&vdda>; status = "okay"; + adc1: adc@0 { + st,adc-channels = <0 1>; + /* 16.5 ck_cycles sampling time */ + st,min-sample-time-nsecs = <400>; + status = "okay"; + }; + jadc1: jadc@0 { + st,adc-channels = <0 1>; + /* 16.5 ck_cycles sampling time */ + st,min-sample-time-nsecs = <400>; + status = "okay"; + }; + /* temperature sensor on adc2 */ + adc2: adc@100 { + status = "okay"; + }; + adc_temp: temp { + status = "okay"; + }; }; -&timers6 { +&dac { + pinctrl-names = "default"; + pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; + vref-supply = <&vdda>; status = "okay"; - timer@5 { + dac1: dac@1 { status = "okay"; }; + dac2: dac@2 { + status = "okay"; + }; +}; + +&dma1 { + sram = <&dma_pool>; +}; + +&dma2 { + sram = <&dma_pool>; +}; + +&dts { + status = "okay"; +}; + +&gpu { + contiguous-area = <&gpu_reserved>; + status = "okay"; }; &i2c4 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c4_pins_a>; + pinctrl-1 = <&i2c4_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; - pmic: stpmu1@33 { - compatible = "st,stpmu1"; + pmic: stpmic@33 { + compatible = "st,stpmic1"; reg = <0x33>; - interrupts = <0 2>; - interrupt-parent = <&gpioa>; + interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; status = "okay"; - st,main_control_register = <0x04>; - st,vin_control_register = <0xc0>; - st,usb_control_register = <0x30>; + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; + st,usb-control-register = <0x30>; regulators { - compatible = "st,stpmu1-regulators"; + compatible = "st,stpmic1-regulators"; ldo1-supply = <&v3v3>; ldo2-supply = <&v3v3>; @@ -83,20 +205,8 @@ regulator-min-microvolt = <800000>; regulator-max-microvolt = <1350000>; regulator-always-on; - regulator-initial-mode = <2>; + regulator-initial-mode = <0>; regulator-over-current-protection; - - regulator-state-standby { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1200000>; - regulator-mode = <8>; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vdd_ddr: buck2 { @@ -104,22 +214,8 @@ regulator-min-microvolt = <1350000>; regulator-max-microvolt = <1350000>; regulator-always-on; - regulator-initial-mode = <2>; + regulator-initial-mode = <0>; regulator-over-current-protection; - - regulator-state-standby { - regulator-suspend-microvolt = <1350000>; - regulator-on-in-suspend; - regulator-mode = <8>; - }; - regulator-state-mem { - regulator-suspend-microvolt = <1350000>; - regulator-on-in-suspend; - regulator-mode = <8>; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vdd: buck3 { @@ -127,46 +223,18 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; - st,mask_reset; - regulator-initial-mode = <8>; + st,mask-reset; + regulator-initial-mode = <0>; regulator-over-current-protection; - - regulator-state-standby { - regulator-suspend-microvolt = <3300000>; - regulator-on-in-suspend; - regulator-mode = <8>; - }; - regulator-state-mem { - regulator-suspend-microvolt = <3300000>; - regulator-on-in-suspend; - regulator-mode = <8>; - }; - regulator-state-disk { - regulator-suspend-microvolt = <3300000>; - regulator-on-in-suspend; - regulator-mode = <8>; - }; }; v3v3: buck4 { regulator-name = "v3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - regulator-boot-on; + regulator-always-on; regulator-over-current-protection; - regulator-initial-mode = <8>; - - regulator-state-standby { - regulator-suspend-microvolt = <3300000>; - regulator-unchanged-in-suspend; - regulator-mode = <8>; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; + regulator-initial-mode = <0>; }; vdda: ldo1 { @@ -174,18 +242,6 @@ regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; interrupts = ; - interrupt-parent = <&pmic>; - - regulator-state-standby { - regulator-suspend-microvolt = <2900000>; - regulator-unchanged-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; v2v8: ldo2 { @@ -193,36 +249,14 @@ regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; interrupts = ; - interrupt-parent = <&pmic>; - - regulator-state-standby { - regulator-suspend-microvolt = <2800000>; - regulator-unchanged-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; - regulator-min-microvolt = <0000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; - - regulator-state-standby { - regulator-off-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vdd_usb: ldo4 { @@ -230,17 +264,6 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; interrupts = ; - interrupt-parent = <&pmic>; - - regulator-state-standby { - regulator-unchanged-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vdd_sd: ldo5 { @@ -248,19 +271,7 @@ regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; interrupts = ; - interrupt-parent = <&pmic>; regulator-boot-on; - - regulator-state-standby { - regulator-suspend-microvolt = <2900000>; - regulator-unchanged-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; v1v8: ldo6 { @@ -268,69 +279,88 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; interrupts = ; - interrupt-parent = <&pmic>; - - regulator-state-standby { - regulator-suspend-microvolt = <1800000>; - regulator-unchanged-in-suspend; - }; - regulator-state-mem { - regulator-off-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; regulator-over-current-protection; - - regulator-state-standby { - regulator-on-in-suspend; - }; - regulator-state-mem { - regulator-on-in-suspend; - }; - regulator-state-disk { - regulator-off-in-suspend; - }; }; - bst_out: boost { + bst_out: boost { regulator-name = "bst_out"; interrupts = ; - interrupt-parent = <&pmic>; - }; + }; vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - interrupt-parent = <&pmic>; regulator-active-discharge; }; vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - interrupt-parent = <&pmic>; regulator-active-discharge; }; }; + + onkey { + compatible = "st,stpmic1-onkey"; + interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; + status = "okay"; + }; + + watchdog { + compatible = "st,stpmic1-wdt"; + status = "disabled"; + }; }; }; +&ipcc { + status = "okay"; +}; + +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +&m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, + <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; + mbox-names = "vq0", "vq1", "shutdown"; + interrupt-parent = <&exti>; + interrupts = <68 1>; + interrupt-names = "wdg"; + recovery; + status = "okay"; +}; + &pwr { pwr-supply = <&vdd>; }; +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + &sdmmc1 { + pinctrl-names = "default", "opendrain", "sleep"; pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>; broken-cd; - st,dirpol; - st,negedge; - st,pin-ckin; + st,sig-dir; + st,neg-edge; + st,use-ckin; bus-width = <4>; vmmc-supply = <&vdd_sd>; vqmmc-supply = <&sd_switch>; @@ -343,36 +373,44 @@ }; &sdmmc2 { + pinctrl-names = "default", "opendrain", "sleep"; pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; + pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>; + pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>; non-removable; no-sd; no-sdio; - st,dirpol; - st,negedge; + st,neg-edge; bus-width = <8>; vmmc-supply = <&v3v3>; - vqmmc-supply = <&vdd>; + vqmmc-supply = <&v3v3>; + mmc-ddr-3_3v; status = "okay"; }; +&timers6 { + status = "okay"; + /* spare dmas for other usage */ + /delete-property/dmas; + /delete-property/dma-names; + timer@5 { + status = "okay"; + }; +}; + &uart4 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep", "idle", "no_console_suspend"; pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; status = "okay"; }; &usbotg_hs { - usb33d-supply = <&usb33>; -}; - -&usbphyc_port0 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; + vbus-supply = <&vbus_otg>; }; -&usbphyc_port1 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; +&usbphyc { + vdd3v3-supply = <&vdd_usb>; }; diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi index 30b173478c6c..ec0881318341 100644 --- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi @@ -7,29 +7,23 @@ / { aliases { - spi0 = &qspi; + gpio26 = &stmfx_pinctrl; i2c1 = &i2c2; i2c4 = &i2c5; + pinctrl2 = &stmfx_pinctrl; + 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 +55,6 @@ }; }; -&flash0 { - u-boot,dm-spl; +&usbotg_hs { + g-tx-fifo-size = <576>; }; - diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 902a42bee290..18742e83f159 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -6,44 +6,565 @@ /dts-v1/; #include "stm32mp157c-ed1.dts" +#include +#include +#include / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial1 = &usart3; + ethernet0 = ðernet0; + }; + + clocks { + clk_ext_camera: clk-ext-camera { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + + joystick { + compatible = "gpio-keys"; + #size-cells = <0>; + pinctrl-0 = <&joystick_pins>; + pinctrl-names = "default"; + button-0 { + label = "JoySel"; + linux,code = ; + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; + }; + button-1 { + label = "JoyDown"; + linux,code = ; + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <1 IRQ_TYPE_EDGE_RISING>; + }; + button-2 { + label = "JoyLeft"; + linux,code = ; + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <2 IRQ_TYPE_EDGE_RISING>; + }; + button-3 { + label = "JoyRight"; + linux,code = ; + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <3 IRQ_TYPE_EDGE_RISING>; + }; + button-4 { + label = "JoyUp"; + linux,code = ; + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + }; + }; + + panel_backlight: panel-backlight { + compatible = "gpio-backlight"; + gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; + default-on; + status = "okay"; + }; + + spdif_out: spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + status = "okay"; + + spdif_out_port: port { + spdif_out_endpoint: endpoint { + remote-endpoint = <&sai4a_endpoint>; + }; + }; + }; + + spdif_in: spdif-in { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dir"; + status = "okay"; + + spdif_in_port: port { + spdif_in_endpoint: endpoint { + remote-endpoint = <&spdifrx_endpoint>; + }; + }; + }; + + sound { + compatible = "audio-graph-card"; + label = "STM32MP1-EV"; + routing = + "AIF1CLK" , "MCLK1", + "AIF2CLK" , "MCLK1", + "IN1LN" , "MICBIAS2", + "DMIC2DAT" , "MICBIAS1", + "DMIC1DAT" , "MICBIAS1"; + dais = <&sai2a_port &sai2b_port &sai4a_port &spdifrx_port + &dfsdm0_port &dfsdm1_port &dfsdm2_port &dfsdm3_port>; + status = "okay"; + }; + + dmic0: dmic-0 { + compatible = "dmic-codec"; + #sound-dai-cells = <1>; + status = "okay"; + + port { + dmic0_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint0>; + }; + }; + }; + + dmic1: dmic-1 { + compatible = "dmic-codec"; + #sound-dai-cells = <1>; + status = "okay"; + + port { + dmic1_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint1>; + }; + }; + }; + + dmic2: dmic-2 { + compatible = "dmic-codec"; + #sound-dai-cells = <1>; + status = "okay"; + + port { + dmic2_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint2>; + }; + }; + }; + + dmic3: dmic-3 { + compatible = "dmic-codec"; + #sound-dai-cells = <1>; + status = "okay"; + + port { + dmic3_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint3>; + }; + }; + }; + + usb_phy_tuning: usb-phy-tuning { + st,hs-dc-level = <2>; + st,fs-rftime-tuning; + st,hs-rftime-reduction; + st,hs-current-trim = <15>; + st,hs-impedance-trim = <1>; + st,squelch-level = <3>; + st,hs-rx-offset = <2>; + st,no-lsfs-sc; + }; }; &cec { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&cec_pins_a>; + pinctrl-1 = <&cec_pins_sleep_a>; +}; + +&dcmi { + status = "okay"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&dcmi_pins_a>; + pinctrl-1 = <&dcmi_sleep_pins_a>; + + port { + dcmi_0: endpoint { + remote-endpoint = <&ov5640_0>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + pclk-max-frequency = <77000000>; + }; + }; +}; + +&dfsdm { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&dfsdm_clkout_pins_a + &dfsdm_data1_pins_a &dfsdm_data3_pins_a>; + pinctrl-1 = <&dfsdm_clkout_sleep_pins_a + &dfsdm_data1_sleep_pins_a &dfsdm_data3_sleep_pins_a>; + spi-max-frequency = <2048000>; + + clocks = <&rcc DFSDM_K>, <&rcc ADFSDM_K>; + clock-names = "dfsdm", "audio"; + status = "okay"; + + dfsdm0: filter@0 { + compatible = "st,stm32-dfsdm-dmic"; + st,adc-channels = <3>; + st,adc-channel-names = "dmic_u1"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <3>; + status = "okay"; + + asoc_pdm0: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm0 0>; + status = "okay"; + + dfsdm0_port: port { + dfsdm_endpoint0: endpoint { + remote-endpoint = <&dmic0_endpoint>; + }; + }; + }; + }; + + dfsdm1: filter@1 { + compatible = "st,stm32-dfsdm-dmic"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic_u2"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <3>; + status = "okay"; + + asoc_pdm1: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm1 0>; + status = "okay"; + + dfsdm1_port: port { + dfsdm_endpoint1: endpoint { + remote-endpoint = <&dmic1_endpoint>; + }; + }; + }; + }; + + dfsdm2: filter@2 { + compatible = "st,stm32-dfsdm-dmic"; + st,adc-channels = <3>; + st,adc-channel-names = "dmic_u3"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <3>; + status = "okay"; + + asoc_pdm2: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm2 0>; + status = "okay"; + + dfsdm2_port: port { + dfsdm_endpoint2: endpoint { + remote-endpoint = <&dmic2_endpoint>; + }; + }; + }; + }; + + dfsdm3: filter@3 { + compatible = "st,stm32-dfsdm-dmic"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic_u4"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <3>; + status = "okay"; + + asoc_pdm3: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm3 0>; + status = "okay"; + + dfsdm3_port: port { + dfsdm_endpoint3: endpoint { + remote-endpoint = <&dmic3_endpoint>; + }; + }; + }; + }; +}; + +&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>; + power-supply = <&v1v8>; + 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>; + }; + }; +}; + +&fmc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + nand: nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&hdp { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hdp0_pins_a &hdp6_pins_a &hdp7_pins_a>; + pinctrl-1 = <&hdp0_pins_sleep_a &hdp6_pins_sleep_a &hdp7_pins_sleep_a>; + status = "disabled"; + + muxing-hdp = <(STM32_HDP(0, HDP0_GPOVAL_0) | + STM32_HDP(6, HDP6_GPOVAL_6) | + STM32_HDP(7, HDP7_GPOVAL_7))>; }; &i2c2 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c2_pins_a>; + pinctrl-1 = <&i2c2_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; + + wm8994: wm8994@1b { + compatible = "wlf,wm8994"; + #sound-dai-cells = <0>; + reg = <0x1b>; + status = "okay"; + + gpio-controller; + #gpio-cells = <2>; + + DBVDD-supply = <&vdd>; + SPKVDD1-supply = <&vdd>; + SPKVDD2-supply = <&vdd>; + AVDD2-supply = <&v1v8>; + CPVDD-supply = <&v1v8>; + + wlf,ldoena-always-driven; + + clocks = <&sai2a>; + clock-names = "MCLK1"; + + wlf,gpio-cfg = <0x8101 0xa100 0xa100 0xa100 0xa101 0xa101 0xa100 0xa101 0xa101 0xa101 0xa101>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + wm8994_tx_port: port@0 { + reg = <0>; + wm8994_tx_endpoint: endpoint { + remote-endpoint = <&sai2a_endpoint>; + }; + }; + + wm8994_rx_port: port@1 { + reg = <1>; + wm8994_rx_endpoint: endpoint { + remote-endpoint = <&sai2b_endpoint>; + }; + }; + }; + }; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + pinctrl-names = "default"; + pinctrl-0 = <&ov5640_pins>; + reg = <0x3c>; + clocks = <&clk_ext_camera>; + clock-names = "xclk"; + DOVDD-supply = <&v2v8>; + powerdown-gpios = <&stmfx_pinctrl 18 GPIO_ACTIVE_HIGH>; + reset-gpios = <&stmfx_pinctrl 19 GPIO_ACTIVE_LOW>; + rotation = <180>; + status = "okay"; + + port { + ov5640_0: endpoint { + remote-endpoint = <&dcmi_0>; + bus-width = <8>; + data-shift = <2>; /* lines 9:2 are used */ + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + pclk-max-frequency = <77000000>; + }; + }; + }; + + 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>; + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins>; + + hog_pins: hog { + pins = "gpio14"; + drive-push-pull; + bias-pull-down; + }; + + joystick_pins: joystick { + pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; + drive-push-pull; + bias-pull-down; + }; + + ov5640_pins: camera { + pins = "agpio2", "agpio3"; /* stmfx pins 18 & 19 */ + drive-push-pull; + output-low; + }; + }; + }; + + gt9147: goodix_ts@5d { + compatible = "goodix,gt9147"; + reg = <0x5d>; + status = "okay"; + + irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; + irq-flags = ; + }; +}; + +&i2c4 { + pmic: stpmic@33 { + regulators { + v1v8: ldo6 { + regulator-enable-ramp-delay = <300000>; + }; + }; + }; }; &i2c5 { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c5_pins_a>; + pinctrl-1 = <&i2c5_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; + /delete-property/dmas; + /delete-property/dma-names; +}; + +<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", "sleep"; + pinctrl-0 = <&m_can1_pins_a>; + pinctrl-1 = <&m_can1_sleep_pins_a>; status = "okay"; }; &qspi { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; + pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a &qspi_bk2_sleep_pins_a>; reg = <0x58003000 0x1000>, <0x70000000 0x4000000>; #address-cells = <1>; #size-cells = <0>; status = "okay"; flash0: mx66l51235l@0 { + compatible = "jedec,spi-nor"; reg = <0>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; @@ -52,6 +573,7 @@ }; flash1: mx66l51235l@1 { + compatible = "jedec,spi-nor"; reg = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; @@ -60,11 +582,110 @@ }; }; +&sai2 { + clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_a>; + pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_a>; + clock-names = "pclk", "x8k", "x11k"; + status = "okay"; + + sai2a: audio-controller@4400b004 { + #clock-cells = <0>; + dma-names = "tx"; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; + status = "okay"; + + sai2a_port: port { + sai2a_endpoint: endpoint { + remote-endpoint = <&wm8994_tx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + }; + }; + }; + + sai2b: audio-controller@4400b024 { + dma-names = "rx"; + clocks = <&rcc SAI2_K>, <&sai2a>; + clock-names = "sai_ck", "MCLK"; + status = "okay"; + + sai2b_port: port { + sai2b_endpoint: endpoint { + remote-endpoint = <&wm8994_rx_endpoint>; + format = "i2s"; + mclk-fs = <256>; + }; + }; + }; +}; + +&sai4 { + clocks = <&rcc SAI4>, <&rcc PLL3_Q>, <&rcc PLL3_R>; + clock-names = "pclk", "x8k", "x11k"; + status = "okay"; + + sai4a: audio-controller@50027004 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sai4a_pins_a>; + pinctrl-1 = <&sai4a_sleep_pins_a>; + dma-names = "tx"; + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; + st,iec60958; + status = "okay"; + + sai4a_port: port { + sai4a_endpoint: endpoint { + remote-endpoint = <&spdif_out_endpoint>; + }; + }; + }; +}; + +&sdmmc3 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc3_b4_pins_a>; + pinctrl-1 = <&sdmmc3_b4_od_pins_a>; + pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>; + vmmc-supply = <&v3v3>; + broken-cd; + st,neg-edge; + bus-width = <4>; + status = "disabled"; +}; + +&spdifrx { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spdifrx_pins_a>; + pinctrl-1 = <&spdifrx_sleep_pins_a>; + status = "okay"; + + spdifrx_port: port { + spdifrx_endpoint: endpoint { + remote-endpoint = <&spdif_in_endpoint>; + }; + }; +}; + +&spi1 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi1_pins_a>; + pinctrl-1 = <&spi1_sleep_pins_a>; + status = "disabled"; +}; + &timers2 { status = "disabled"; + /* spare dmas for other usage (un-delete to enable pwm capture) */ + /delete-property/dmas; + /delete-property/dma-names; pwm { pinctrl-0 = <&pwm2_pins_a>; - pinctrl-names = "default"; + pinctrl-1 = <&pwm2_sleep_pins_a>; + pinctrl-names = "default", "sleep"; status = "okay"; }; timer@1 { @@ -74,9 +695,12 @@ &timers8 { status = "disabled"; + /delete-property/dmas; + /delete-property/dma-names; pwm { pinctrl-0 = <&pwm8_pins_a>; - pinctrl-names = "default"; + pinctrl-1 = <&pwm8_sleep_pins_a>; + pinctrl-names = "default", "sleep"; status = "okay"; }; timer@7 { @@ -86,9 +710,12 @@ &timers12 { status = "disabled"; + /delete-property/dmas; + /delete-property/dma-names; pwm { pinctrl-0 = <&pwm12_pins_a>; - pinctrl-names = "default"; + pinctrl-1 = <&pwm12_sleep_pins_a>; + pinctrl-names = "default", "sleep"; status = "okay"; }; timer@11 { @@ -96,6 +723,14 @@ }; }; +&usart3 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&usart3_pins_a>; + pinctrl-1 = <&usart3_sleep_pins_a>; + pinctrl-2 = <&usart3_idle_pins_a>; + status = "disabled"; +}; + &usbh_ehci { phys = <&usbphyc_port0>; phy-names = "usb"; @@ -114,3 +749,11 @@ &usbphyc { status = "okay"; }; + +&usbphyc_port0 { + st,phy-tuning = <&usb_phy_tuning>; +}; + +&usbphyc_port1 { + st,phy-tuning = <&usb_phy_tuning>; +}; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 33c5981869b3..4de499e1e409 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -19,42 +19,28 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; + clock-frequency = <650000000>; }; cpu1: cpu@1 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <1>; + clock-frequency = <650000000>; }; }; - psci { - compatible = "arm,psci"; - method = "smc"; - cpu_off = <0x84000002>; - cpu_on = <0x84000003>; + arm-pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = , + ; + interrupt-affinity = <&cpu0>, <&cpu1>; + interrupt-parent = <&intc>; }; - aliases { - gpio0 = &gpioa; - gpio1 = &gpiob; - gpio2 = &gpioc; - gpio3 = &gpiod; - gpio4 = &gpioe; - gpio5 = &gpiof; - gpio6 = &gpiog; - gpio7 = &gpioh; - gpio8 = &gpioi; - gpio9 = &gpioj; - gpio10 = &gpiok; - serial0 = &usart1; - serial1 = &usart2; - serial2 = &usart3; - serial3 = &uart4; - serial4 = &uart5; - serial5 = &usart6; - serial6 = &uart7; - serial7 = &uart8; + psci { + compatible = "arm,psci-1.0"; + method = "smc"; }; intc: interrupt-controller@a0021000 { @@ -104,6 +90,18 @@ compatible = "fixed-clock"; clock-frequency = <4000000>; }; + + clk_i2s_ckin: i2s_ckin { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + clk_dsi_phy: ck_dsi_phy { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; }; pm_domain { @@ -126,6 +124,61 @@ }; }; + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&dts>; + + trips { + cpu_alert1: cpu-alert1 { + temperature = <85000>; + hysteresis = <0>; + type = "passive"; + }; + + cpu-crit { + temperature = <120000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; + }; + + reboot { + compatible = "syscon-reboot"; + regmap = <&rcc>; + offset = <0x404>; + mask = <0x1>; + }; + + replicator { + /* + * non-configurable replicators don't show up on the + * AMBA bus. As such no need to add "arm,primecell" + */ + compatible = "arm,coresight-replicator"; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* replicator output ports */ + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = <&funnel_in_port4>; + }; + }; + }; + }; + soc { compatible = "simple-bus"; #address-cells = <1>; @@ -140,6 +193,12 @@ reg = <0x40000000 0x400>; clocks = <&rcc TIM2_K>; clock-names = "int"; + dmas = <&dmamux1 18 0x400 0x5>, + <&dmamux1 19 0x400 0x5>, + <&dmamux1 20 0x400 0x5>, + <&dmamux1 21 0x400 0x5>, + <&dmamux1 22 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up"; status = "disabled"; pwm { @@ -161,6 +220,13 @@ reg = <0x40001000 0x400>; clocks = <&rcc TIM3_K>; clock-names = "int"; + dmas = <&dmamux1 23 0x400 0x5>, + <&dmamux1 24 0x400 0x5>, + <&dmamux1 25 0x400 0x5>, + <&dmamux1 26 0x400 0x5>, + <&dmamux1 27 0x400 0x5>, + <&dmamux1 28 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; status = "disabled"; pwm { @@ -182,6 +248,11 @@ reg = <0x40002000 0x400>; clocks = <&rcc TIM4_K>; clock-names = "int"; + dmas = <&dmamux1 29 0x400 0x5>, + <&dmamux1 30 0x400 0x5>, + <&dmamux1 31 0x400 0x5>, + <&dmamux1 32 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4"; status = "disabled"; pwm { @@ -203,6 +274,13 @@ reg = <0x40003000 0x400>; clocks = <&rcc TIM5_K>; clock-names = "int"; + dmas = <&dmamux1 55 0x400 0x5>, + <&dmamux1 56 0x400 0x5>, + <&dmamux1 57 0x400 0x5>, + <&dmamux1 58 0x400 0x5>, + <&dmamux1 59 0x400 0x5>, + <&dmamux1 60 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; status = "disabled"; pwm { @@ -224,6 +302,8 @@ reg = <0x40004000 0x400>; clocks = <&rcc TIM6_K>; clock-names = "int"; + dmas = <&dmamux1 69 0x400 0x5>; + dma-names = "up"; status = "disabled"; timer@5 { @@ -240,6 +320,8 @@ reg = <0x40005000 0x400>; clocks = <&rcc TIM7_K>; clock-names = "int"; + dmas = <&dmamux1 70 0x400 0x5>; + dma-names = "up"; status = "disabled"; timer@6 { @@ -319,6 +401,7 @@ reg = <0x40009000 0x400>; clocks = <&rcc LPTIM1_K>; clock-names = "mux"; + power-domains = <&pd_core>; status = "disabled"; pwm { @@ -339,87 +422,196 @@ }; }; + 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"; + power-domains = <&pd_core>; + status = "disabled"; + }; + + i2s2: audio-controller@4000b000 { + compatible = "st,stm32h7-i2s"; + #sound-dai-cells = <0>; + reg = <0x4000b000 0x400>; + interrupts = ; + dmas = <&dmamux1 39 0x400 0x01>, + <&dmamux1 40 0x400 0x01>; + 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"; + power-domains = <&pd_core>; + status = "disabled"; + }; + + i2s3: audio-controller@4000c000 { + compatible = "st,stm32h7-i2s"; + #sound-dai-cells = <0>; + reg = <0x4000c000 0x400>; + interrupts = ; + dmas = <&dmamux1 61 0x400 0x01>, + <&dmamux1 62 0x400 0x01>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + spdifrx: audio-controller@4000d000 { + compatible = "st,stm32h7-spdifrx"; + #sound-dai-cells = <0>; + reg = <0x4000d000 0x400>; + clocks = <&rcc SPDIF_K>; + clock-names = "kclk"; + interrupts = ; + dmas = <&dmamux1 93 0x400 0x01>, + <&dmamux1 94 0x400 0x01>; + dma-names = "rx", "rx-ctrl"; + status = "disabled"; + }; + usart2: serial@4000e000 { compatible = "st,stm32h7-uart"; reg = <0x4000e000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>, + <&exti 27 1>; clocks = <&rcc USART2_K>; + resets = <&rcc USART2_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; usart3: serial@4000f000 { compatible = "st,stm32h7-uart"; reg = <0x4000f000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, + <&exti 28 1>; clocks = <&rcc USART3_K>; + resets = <&rcc USART3_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; uart4: serial@40010000 { compatible = "st,stm32h7-uart"; reg = <0x40010000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, + <&exti 30 1>; clocks = <&rcc UART4_K>; + resets = <&rcc UART4_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; uart5: serial@40011000 { compatible = "st,stm32h7-uart"; reg = <0x40011000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, + <&exti 31 1>; clocks = <&rcc UART5_K>; + resets = <&rcc UART5_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; i2c1: i2c@40012000 { compatible = "st,stm32f7-i2c"; reg = <0x40012000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>, + <&exti 21 1>; clocks = <&rcc I2C1_K>; resets = <&rcc I2C1_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux1 33 0x400 0x05>, + <&dmamux1 34 0x400 0x05>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x1>; status = "disabled"; }; i2c2: i2c@40013000 { compatible = "st,stm32f7-i2c"; reg = <0x40013000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>, + <&exti 22 1>; clocks = <&rcc I2C2_K>; resets = <&rcc I2C2_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux1 35 0x400 0x05>, + <&dmamux1 36 0x400 0x05>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x2>; status = "disabled"; }; i2c3: i2c@40014000 { compatible = "st,stm32f7-i2c"; reg = <0x40014000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <&exti 23 1>; clocks = <&rcc I2C3_K>; resets = <&rcc I2C3_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux1 73 0x400 0x05>, + <&dmamux1 74 0x400 0x05>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x4>; status = "disabled"; }; i2c5: i2c@40015000 { compatible = "st,stm32f7-i2c"; reg = <0x40015000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, + <&exti 25 1>; clocks = <&rcc I2C5_K>; resets = <&rcc I2C5_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux1 115 0x400 0x05>, + <&dmamux1 116 0x400 0x05>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x10>; status = "disabled"; }; @@ -429,6 +621,7 @@ interrupts = ; clocks = <&rcc CEC_K>, <&clk_lse>; clock-names = "cec", "hdmi-cec"; + power-domains = <&pd_core>; status = "disabled"; }; @@ -459,16 +652,26 @@ uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, + <&exti 32 1>; clocks = <&rcc UART7_K>; + resets = <&rcc UART7_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; uart8: serial@40019000 { compatible = "st,stm32h7-uart"; reg = <0x40019000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, + <&exti 33 1>; clocks = <&rcc UART8_K>; + resets = <&rcc UART8_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; @@ -479,6 +682,15 @@ reg = <0x44000000 0x400>; clocks = <&rcc TIM1_K>; clock-names = "int"; + dmas = <&dmamux1 11 0x400 0x5>, + <&dmamux1 12 0x400 0x5>, + <&dmamux1 13 0x400 0x5>, + <&dmamux1 14 0x400 0x5>, + <&dmamux1 15 0x400 0x5>, + <&dmamux1 16 0x400 0x5>, + <&dmamux1 17 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4", + "up", "trig", "com"; status = "disabled"; pwm { @@ -500,6 +712,15 @@ reg = <0x44001000 0x400>; clocks = <&rcc TIM8_K>; clock-names = "int"; + dmas = <&dmamux1 47 0x400 0x5>, + <&dmamux1 48 0x400 0x5>, + <&dmamux1 49 0x400 0x5>, + <&dmamux1 50 0x400 0x5>, + <&dmamux1 51 0x400 0x5>, + <&dmamux1 52 0x400 0x5>, + <&dmamux1 53 0x400 0x5>; + dma-names = "ch1", "ch2", "ch3", "ch4", + "up", "trig", "com"; status = "disabled"; pwm { @@ -517,8 +738,54 @@ usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <&exti 29 1>; clocks = <&rcc USART6_K>; + resets = <&rcc USART6_R>; + wakeup-source; + power-domains = <&pd_core>; + 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"; + power-domains = <&pd_core>; + status = "disabled"; + }; + + i2s1: audio-controller@44004000 { + compatible = "st,stm32h7-i2s"; + #sound-dai-cells = <0>; + reg = <0x44004000 0x400>; + interrupts = ; + dmas = <&dmamux1 37 0x400 0x01>, + <&dmamux1 38 0x400 0x01>; + 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"; + power-domains = <&pd_core>; status = "disabled"; }; @@ -529,6 +796,11 @@ reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; + dmas = <&dmamux1 105 0x400 0x5>, + <&dmamux1 106 0x400 0x5>, + <&dmamux1 107 0x400 0x5>, + <&dmamux1 108 0x400 0x5>; + dma-names = "ch1", "up", "trig", "com"; status = "disabled"; pwm { @@ -550,6 +822,9 @@ reg = <0x44007000 0x400>; clocks = <&rcc TIM16_K>; clock-names = "int"; + dmas = <&dmamux1 109 0x400 0x5>, + <&dmamux1 110 0x400 0x5>; + dma-names = "ch1", "up"; status = "disabled"; pwm { @@ -570,6 +845,9 @@ reg = <0x44008000 0x400>; clocks = <&rcc TIM17_K>; clock-names = "int"; + dmas = <&dmamux1 111 0x400 0x5>, + <&dmamux1 112 0x400 0x5>; + dma-names = "ch1", "up"; status = "disabled"; pwm { @@ -584,6 +862,199 @@ }; }; + 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"; + power-domains = <&pd_core>; + status = "disabled"; + }; + + sai1: sai@4400a000 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x4400a000 0x400>; + reg = <0x4400a000 0x4>; + interrupts = ; + resets = <&rcc SAI1_R>; + status = "disabled"; + + sai1a: audio-controller@4400a004 { + #sound-dai-cells = <0>; + + compatible = "st,stm32-sai-sub-a"; + reg = <0x4 0x1c>; + dmas = <&dmamux1 87 0x400 0x01>; + status = "disabled"; + }; + + sai1b: audio-controller@4400a024 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x24 0x1c>; + dmas = <&dmamux1 88 0x400 0x01>; + status = "disabled"; + }; + }; + + sai2: sai@4400b000 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x4400b000 0x400>; + reg = <0x4400b000 0x4>; + interrupts = ; + resets = <&rcc SAI2_R>; + status = "disabled"; + + sai2a: audio-controller@4400b004 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-a"; + reg = <0x4 0x1c>; + dmas = <&dmamux1 89 0x400 0x01>; + status = "disabled"; + }; + + sai2b: audio-controller@4400b024 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x24 0x1c>; + dmas = <&dmamux1 90 0x400 0x01>; + status = "disabled"; + }; + }; + + sai3: sai@4400c000 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x4400c000 0x400>; + reg = <0x4400c000 0x4>; + interrupts = ; + resets = <&rcc SAI3_R>; + status = "disabled"; + + sai3a: audio-controller@4400c004 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-a"; + reg = <0x04 0x1c>; + dmas = <&dmamux1 113 0x400 0x01>; + status = "disabled"; + }; + + sai3b: audio-controller@4400c024 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x24 0x1c>; + dmas = <&dmamux1 114 0x400 0x01>; + 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 0x1400>; + 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 = <0x1400 0 0 32 0 0 2 2>; + status = "disabled"; + }; + dma1: dma@48000000 { compatible = "st,stm32-dma"; reg = <0x48000000 0x400>; @@ -599,6 +1070,15 @@ #dma-cells = <4>; st,mem2mem; dma-requests = <8>; + dmas = <&mdma1 0 0x11 0x1200000a 0x48000008 0x00000020 1>, + <&mdma1 1 0x11 0x1200000a 0x48000008 0x00000800 1>, + <&mdma1 2 0x11 0x1200000a 0x48000008 0x00200000 1>, + <&mdma1 3 0x11 0x1200000a 0x48000008 0x08000000 1>, + <&mdma1 4 0x11 0x1200000a 0x4800000C 0x00000020 1>, + <&mdma1 5 0x11 0x1200000a 0x4800000C 0x00000800 1>, + <&mdma1 6 0x11 0x1200000a 0x4800000C 0x00200000 1>, + <&mdma1 7 0x11 0x1200000a 0x4800000C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; dma2: dma@48001000 { @@ -616,6 +1096,15 @@ #dma-cells = <4>; st,mem2mem; dma-requests = <8>; + dmas = <&mdma1 8 0x11 0x1200000a 0x48001008 0x00000020 1>, + <&mdma1 9 0x11 0x1200000a 0x48001008 0x00000800 1>, + <&mdma1 10 0x11 0x1200000a 0x48001008 0x00200000 1>, + <&mdma1 11 0x11 0x1200000a 0x48001008 0x08000000 1>, + <&mdma1 12 0x11 0x1200000a 0x4800100C 0x00000020 1>, + <&mdma1 13 0x11 0x1200000a 0x4800100C 0x00000800 1>, + <&mdma1 14 0x11 0x1200000a 0x4800100C 0x00200000 1>, + <&mdma1 15 0x11 0x1200000a 0x4800100C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; dmamux1: dma-router@48002000 { @@ -636,6 +1125,10 @@ clocks = <&rcc ADC12>, <&rcc ADC12_K>; clock-names = "bus", "adc"; interrupt-controller; + st,syscfg-vbooster = <&syscfg 0x4 0x100>; + st,syscfg-vbooster-clr = <&syscfg 0x44 0x100>; + st,syscfg-anaswvdd = <&syscfg 0x4 0x200>; + st,syscfg-anaswvdd-clr = <&syscfg 0x44 0x200>; #interrupt-cells = <1>; #address-cells = <1>; #size-cells = <0>; @@ -647,6 +1140,8 @@ reg = <0x0>; interrupt-parent = <&adc>; interrupts = <0>; + dmas = <&dmamux1 9 0x400 0x05>; + dma-names = "rx"; status = "disabled"; }; @@ -656,18 +1151,57 @@ reg = <0x100>; interrupt-parent = <&adc>; interrupts = <1>; + dmas = <&dmamux1 10 0x400 0x05>; + dma-names = "rx"; + /* temperature sensor */ + st,adc-channels = <12>; + st,min-sample-time-nsecs = <10000>; + status = "disabled"; + }; + + jadc1: jadc@0 { + compatible = "st,stm32mp1-adc"; + st,injected; + #io-channel-cells = <1>; + reg = <0x0>; + interrupt-parent = <&adc>; + interrupts = <3>; + status = "disabled"; + }; + + jadc2: jadc@100 { + compatible = "st,stm32mp1-adc"; + st,injected; + #io-channel-cells = <1>; + reg = <0x100>; + interrupt-parent = <&adc>; + interrupts = <4>; + /* temperature sensor */ + st,adc-channels = <12>; + st,min-sample-time-nsecs = <10000>; + status = "disabled"; + }; + + adc_temp: temp { + compatible = "st,stm32mp1-adc-temp"; + io-channels = <&adc2 12>; + nvmem-cells = <&ts_cal1>, <&ts_cal2>; + nvmem-cell-names = "ts_cal1", "ts_cal2"; + #io-channel-cells = <0>; + #thermal-sensor-cells = <0>; status = "disabled"; }; }; sdmmc3: sdmmc@48004000 { - compatible = "st,stm32-sdmmc2"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00253180>; reg = <0x48004000 0x400>, <0x48005000 0x400>; - reg-names = "sdmmc", "delay"; - interrupts = ; + interrupts = ; + interrupt-names = "cmd_irq"; clocks = <&rcc SDMMC3_K>; + clock-names = "apb_pclk"; resets = <&rcc SDMMC3_R>; - st,idma = <1>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; @@ -686,34 +1220,66 @@ g-np-tx-fifo-size = <32>; g-tx-fifo-size = <128 128 64 64 64 64 32 32>; dr_mode = "otg"; + usb33d-supply = <&usb33>; power-domains = <&pd_core>; status = "disabled"; }; + hsem: hwspinlock@4c000000 { + compatible = "st,stm32-hwspinlock"; + #hwlock-cells = <1>; + reg = <0x4c000000 0x400>; + clocks = <&rcc HSEM>; + clock-names = "hsem"; + status = "okay"; + }; + + ipcc: mailbox@4c001000 { + compatible = "st,stm32mp1-ipcc"; + #mbox-cells = <1>; + reg = <0x4c001000 0x400>; + st,proc-id = <0>; + interrupts-extended = + <&intc GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, + <&exti 61 1>; + interrupt-names = "rx", "tx", "wakeup"; + clocks = <&rcc IPCC>; + wakeup-source; + power-domains = <&pd_core>; + status = "disabled"; + }; + + dcmi: dcmi@4c006000 { + compatible = "st,stm32-dcmi"; + reg = <0x4c006000 0x400>; + interrupts = ; + resets = <&rcc CAMITF_R>; + clocks = <&rcc DCMI>; + clock-names = "mclk"; + dmas = <&dmamux1 75 0x400 0xd>; + dma-names = "tx"; + status = "disabled"; + }; + rcc: rcc@50000000 { compatible = "st,stm32mp1-rcc", "syscon"; reg = <0x50000000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; - }; - - rcc_reboot: rcc-reboot@50000000 { - compatible = "syscon-reboot"; - regmap = <&rcc>; - offset = <0x404>; - mask = <0x1>; + interrupts = ; }; pwr: pwr@50001000 { - compatible = "st,stm32mp1-pwr", "st,stm32-pwr", "syscon", "simple-mfd"; + compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd"; reg = <0x50001000 0x400>; - system-power-controller; + interrupts = ; - st,sysrcc = <&rcc>; - clocks = <&rcc PLL2_R>; - clock-names = "phyclk"; - pwr-regulators@c { + interrupt-controller; + #interrupt-cells = <3>; + + pwr-regulators { compatible = "st,stm32mp1,pwr-reg"; st,tzcr = <&rcc 0x0 0x1>; @@ -742,11 +1308,24 @@ interrupt-controller; #interrupt-cells = <2>; reg = <0x5000d000 0x400>; + hwlocks = <&hsem 1>; + + /* exti_pwr is an extra interrupt controller used for + * EXTI 55 to 60. It's mapped on pwr interrupt + * controller. + */ + exti_pwr: exti-pwr { + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pwr>; + st,irq-number = <6>; + }; }; - syscfg: system-config@50020000 { - compatible = "st,stm32-syscfg", "syscon"; + syscfg: syscon@50020000 { + compatible = "st,stm32mp157-syscfg", "syscon"; reg = <0x50020000 0x400>; + clocks = <&rcc SYSCFG>; }; lptimer2: timer@50021000 { @@ -756,6 +1335,7 @@ reg = <0x50021000 0x400>; clocks = <&rcc LPTIM2_K>; clock-names = "mux"; + power-domains = <&pd_core>; status = "disabled"; pwm { @@ -783,6 +1363,7 @@ reg = <0x50022000 0x400>; clocks = <&rcc LPTIM3_K>; clock-names = "mux"; + power-domains = <&pd_core>; status = "disabled"; pwm { @@ -803,6 +1384,7 @@ reg = <0x50023000 0x400>; clocks = <&rcc LPTIM4_K>; clock-names = "mux"; + power-domains = <&pd_core>; status = "disabled"; pwm { @@ -817,6 +1399,7 @@ reg = <0x50024000 0x400>; clocks = <&rcc LPTIM5_K>; clock-names = "mux"; + power-domains = <&pd_core>; status = "disabled"; pwm { @@ -835,6 +1418,196 @@ status = "disabled"; }; + sai4: sai@50027000 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x50027000 0x400>; + reg = <0x50027000 0x4>; + interrupts = ; + resets = <&rcc SAI4_R>; + status = "disabled"; + + sai4a: audio-controller@50027004 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-a"; + reg = <0x04 0x1c>; + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; + dmas = <&dmamux1 99 0x400 0x01>; + status = "disabled"; + }; + + sai4b: audio-controller@50027024 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x24 0x1c>; + dmas = <&dmamux1 100 0x400 0x01>; + status = "disabled"; + }; + }; + + dts: thermal@50028000 { + compatible = "st,stm32-thermal"; + reg = <0x50028000 0x100>; + interrupts = ; + clocks = <&rcc TMPSENS>; + clock-names = "pclk"; + #thermal-sensor-cells = <0>; + status = "disabled"; + }; + + hdp: hdp@5002a000 { + compatible = "st,stm32mp1-hdp"; + reg = <0x5002a000 0x400>; + clocks = <&rcc HDP>; + clock-names = "hdp"; + status = "disabled"; + }; + + funnel: funnel@50091000 { + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0x50091000 0x1000>; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* funnel input ports */ + port@0 { + reg = <0>; + funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = <&stm_out_port>; + }; + }; + + port@1 { + reg = <1>; + funnel_in_port1: endpoint { + slave-mode; /* A7-1 input */ + remote-endpoint = <&etm1_out_port>; + }; + }; + + port@2 { + reg = <2>; + funnel_in_port2: endpoint { + slave-mode; /* A7-2 input */ + remote-endpoint = <&etm2_out_port>; + }; + }; + + port@4 { + reg = <4>; + funnel_in_port4: endpoint { + slave-mode; /* REPLICATOR input */ + remote-endpoint = <&replicator_out_port0>; + }; + }; + + port@5 { + reg = <0>; + funnel_out_port0: endpoint { + remote-endpoint = <&etf_in_port>; + }; + }; + }; + }; + + etf: etf@50092000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x50092000 0x1000>; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + etf_in_port: endpoint { + slave-mode; + remote-endpoint = <&funnel_out_port0>; + }; + }; + + port@1 { + reg = <0>; + etf_out_port: endpoint { + remote-endpoint = <&tpiu_in_port>; + }; + }; + }; + }; + + tpiu: tpiu@50093000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0x50093000 0x1000>; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + + port { + tpiu_in_port: endpoint { + slave-mode; + remote-endpoint = <&etf_out_port>; + }; + }; + }; + + stm: stm@500a0000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x500a0000 0x1000>, <0x90000000 0x1000000>, + <0x50094000 0x1000>; + reg-names = "stm-base", "stm-stimulus-base", "cti-base"; + + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + stm_out_port: endpoint { + remote-endpoint = <&funnel_in_port0>; + }; + }; + }; + }; + + /* Cortex A7-1 */ + etm1: etm@500dc000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0x500dc000 0x1000>; + cpu = <&cpu0>; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + port { + etm1_out_port: endpoint { + remote-endpoint = <&funnel_in_port1>; + }; + }; + }; + + /* Cortex A7-2 */ + etm2: etm@500dd000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0x500dd000 0x1000>; + cpu = <&cpu1>; + clocks = <&rcc CK_TRACE>; + clock-names = "apb_pclk"; + + port { + etm2_out_port: endpoint { + remote-endpoint = <&funnel_in_port2>; + }; + }; + }; + cryp1: cryp@54001000 { compatible = "st,stm32mp1-cryp"; reg = <0x54001000 0x400>; @@ -844,6 +1617,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 0x0 0x0>; + dma-names = "in"; + dma-maxburst = <2>; + status = "disabled"; + }; + rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; @@ -857,28 +1642,52 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; - #dma-cells = <5>; + #dma-cells = <6>; dma-channels = <32>; dma-requests = <48>; }; + fmc: nand-controller@58002000 { + compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, + <0x80000000 0x1000>, + <0x88010000 0x1000>, + <0x88020000 0x1000>, + <0x81000000 0x1000>, + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; + dmas = <&mdma1 20 0x10 0x12000A02 0x0 0x0 0>, + <&mdma1 20 0x10 0x12000A08 0x0 0x0 0>, + <&mdma1 21 0x10 0x12000A0A 0x0 0x0 0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; + }; + qspi: qspi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; + dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, + <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; + dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; status = "disabled"; }; sdmmc1: sdmmc@58005000 { - compatible = "st,stm32-sdmmc2"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00253180>; reg = <0x58005000 0x1000>, <0x58006000 0x1000>; - reg-names = "sdmmc", "delay"; + interrupts = ; + interrupt-names = "cmd_irq"; clocks = <&rcc SDMMC1_K>; + clock-names = "apb_pclk"; resets = <&rcc SDMMC1_R>; - st,idma = <1>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; @@ -886,13 +1695,14 @@ }; sdmmc2: sdmmc@58007000 { - compatible = "st,stm32-sdmmc2"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00253180>; reg = <0x58007000 0x1000>, <0x58008000 0x1000>; - reg-names = "sdmmc", "delay"; - interrupts = ; + interrupts = ; + interrupt-names = "cmd_irq"; clocks = <&rcc SDMMC2_K>; + clock-names = "apb_pclk"; resets = <&rcc SDMMC2_R>; - st,idma = <1>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; @@ -906,12 +1716,47 @@ 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>, + <&intc GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>, + <&exti 70 1>; + interrupt-names = "macirq", + "eth_wake_irq", + "stm32_pwr_wakeup"; + clock-names = "stmmaceth", + "mac-clk-tx", + "mac-clk-rx", + "ethstp"; + clocks = <&rcc ETHMAC>, + <&rcc ETHTX>, + <&rcc ETHRX>, + <&rcc ETHSTP>; + st,syscon = <&syscfg 0x4>; + snps,mixed-burst; + snps,pbl = <2>; + snps,en-tx-lpi-clockgating; + snps,axi-config = <&stmmac_axi_config_0>; + snps,tso; + power-domains = <&pd_core>; + status = "disabled"; + }; + usbh_ohci: usbh-ohci@5800c000 { compatible = "generic-ohci"; reg = <0x5800c000 0x1000>; clocks = <&rcc USBH>; resets = <&rcc USBH_R>; interrupts = ; + power-domains = <&pd_core>; status = "disabled"; }; @@ -922,6 +1767,17 @@ resets = <&rcc USBH_R>; interrupts = ; companion = <&usbh_ohci>; + power-domains = <&pd_core>; + status = "disabled"; + }; + + gpu: gpu@59000000 { + compatible = "vivante,gc"; + reg = <0x59000000 0x800>; + interrupts = ; + clocks = <&rcc GPU>, <&rcc GPU_K>; + clock-names = "bus" ,"core"; + resets = <&rcc GPU_R>; status = "disabled"; }; @@ -932,6 +1788,7 @@ clock-names = "pclk", "ref", "px_clk"; resets = <&rcc DSI_R>; reset-names = "apb"; + phy-dsi-supply = <®18>; status = "disabled"; }; @@ -946,13 +1803,24 @@ 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>; + #clock-cells = <0>; compatible = "st,stm32mp1-usbphyc"; reg = <0x5a006000 0x1000>; clocks = <&rcc USBPHY_K>; resets = <&rcc USBPHY_R>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18>; status = "disabled"; usbphyc_port0: usb-phy@0 { @@ -969,35 +1837,136 @@ usart1: serial@5c000000 { compatible = "st,stm32h7-uart"; reg = <0x5c000000 0x400>; - interrupts = ; + interrupt-names = "event", "wakeup"; + interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>, + <&exti 26 1>; clocks = <&rcc USART1_K>; + resets = <&rcc USART1_R>; + wakeup-source; + power-domains = <&pd_core>; + 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 0x0>, + <&mdma1 35 0x0 0x40002 0x0 0x0 0x0>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; status = "disabled"; }; i2c4: i2c@5c002000 { compatible = "st,stm32f7-i2c"; reg = <0x5c002000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, + <&exti 24 1>; clocks = <&rcc I2C4_K>; resets = <&rcc I2C4_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&mdma1 36 0x0 0x40008 0x0 0x0 0>, + <&mdma1 37 0x0 0x40002 0x0 0x0 0>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x8>; status = "disabled"; }; + rtc: rtc@5c004000 { + compatible = "st,stm32mp1-rtc"; + reg = <0x5c004000 0x400>; + clocks = <&rcc RTCAPB>, <&rcc RTC>; + clock-names = "pclk", "rtc_ck"; + interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, + <&exti 19 1>; + status = "disabled"; + }; + + bsec: nvmem@5c005000 { + compatible = "st,stm32mp15-bsec"; + reg = <0x5c005000 0x400>; + #address-cells = <1>; + #size-cells = <1>; + ts_cal1: calib@5c { + reg = <0x5c 0x2>; + }; + ts_cal2: calib@5e { + reg = <0x5e 0x2>; + }; + }; + i2c6: i2c@5c009000 { compatible = "st,stm32f7-i2c"; reg = <0x5c009000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <&exti 54 1>; clocks = <&rcc I2C6_K>; resets = <&rcc I2C6_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&mdma1 38 0x0 0x40008 0x0 0x0 0>, + <&mdma1 39 0x0 0x40002 0x0 0x0 0>; + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x20>; + status = "disabled"; + }; + + 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>; + }; + }; + }; + + m4_rproc: m4@0 { + compatible = "st,stm32mp1-rproc"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x00000000 0x38000000 0x10000>, + <0x30000000 0x30000000 0x60000>, + <0x10000000 0x10000000 0x60000>; + resets = <&rcc MCU_R>; + reset-names = "mcu_rst"; + st,syscfg-pdds = <&pwr 0x014 0x1>; + st,syscfg-holdboot = <&rcc 0x10C 0x1>; + st,syscfg-tz = <&rcc 0x000 0x1>; + status = "disabled"; + + m4_system_resources { + compatible = "rproc-srm-core"; status = "disabled"; }; }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; }; diff --git a/arch/arm/dts/stm32mp157caa-pinctrl.dtsi b/arch/arm/dts/stm32mp157caa-pinctrl.dtsi new file mode 100644 index 000000000000..9b9cd086c2b1 --- /dev/null +++ b/arch/arm/dts/stm32mp157caa-pinctrl.dtsi @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { + soc { + pinctrl: pin-controller@50002000 { + st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@50008000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 96 16>; + }; + + gpioh: gpio@50009000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 112 16>; + }; + + gpioi: gpio@5000a000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 128 16>; + }; + + gpioj: gpio@5000b000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 144 16>; + }; + + gpiok: gpio@5000c000 { + status = "okay"; + ngpios = <8>; + gpio-ranges = <&pinctrl 0 160 8>; + }; + }; + + pinctrl_z: pin-controller-z@54004000 { + st,package = ; + + gpioz: gpio@54004000 { + status = "okay"; + ngpios = <8>; + gpio-ranges = <&pinctrl_z 0 400 8>; + }; + }; + }; +}; diff --git a/arch/arm/dts/stm32mp157cab-pinctrl.dtsi b/arch/arm/dts/stm32mp157cab-pinctrl.dtsi new file mode 100644 index 000000000000..c570cf9d26f7 --- /dev/null +++ b/arch/arm/dts/stm32mp157cab-pinctrl.dtsi @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { + soc { + pinctrl: pin-controller@50002000 { + st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + status = "okay"; + ngpios = <6>; + gpio-ranges = <&pinctrl 6 86 6>; + }; + + gpiog: gpio@50008000 { + status = "okay"; + ngpios = <10>; + gpio-ranges = <&pinctrl 6 102 10>; + }; + + gpioh: gpio@50009000 { + status = "okay"; + ngpios = <2>; + gpio-ranges = <&pinctrl 0 112 2>; + }; + }; + }; +}; diff --git a/arch/arm/dts/stm32mp157cac-pinctrl.dtsi b/arch/arm/dts/stm32mp157cac-pinctrl.dtsi new file mode 100644 index 000000000000..777f9919d33d --- /dev/null +++ b/arch/arm/dts/stm32mp157cac-pinctrl.dtsi @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { + soc { + pinctrl: pin-controller@50002000 { + st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@50008000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 96 16>; + }; + + gpioh: gpio@50009000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 112 16>; + }; + + gpioi: gpio@5000a000 { + status = "okay"; + ngpios = <12>; + gpio-ranges = <&pinctrl 0 128 12>; + }; + }; + + pinctrl_z: pin-controller-z@54004000 { + st,package = ; + + gpioz: gpio@54004000 { + status = "okay"; + ngpios = <8>; + gpio-ranges = <&pinctrl_z 0 400 8>; + }; + }; + }; +}; diff --git a/arch/arm/dts/stm32mp157cad-pinctrl.dtsi b/arch/arm/dts/stm32mp157cad-pinctrl.dtsi new file mode 100644 index 000000000000..c4c303a2db88 --- /dev/null +++ b/arch/arm/dts/stm32mp157cad-pinctrl.dtsi @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { + soc { + pinctrl: pin-controller@50002000 { + st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + status = "okay"; + ngpios = <6>; + gpio-ranges = <&pinctrl 6 86 6>; + }; + + gpiog: gpio@50008000 { + status = "okay"; + ngpios = <10>; + gpio-ranges = <&pinctrl 6 102 10>; + }; + + gpioh: gpio@50009000 { + status = "okay"; + ngpios = <2>; + gpio-ranges = <&pinctrl 0 112 2>; + }; + }; + }; +}; diff --git a/arch/arm/include/asm/arch-stm32/gpio.h b/arch/arm/include/asm/arch-stm32/gpio.h index 84859b144795..570e80a6ba80 100644 --- a/arch/arm/include/asm/arch-stm32/gpio.h +++ b/arch/arm/include/asm/arch-stm32/gpio.h @@ -7,6 +7,8 @@ #ifndef _GPIO_H_ #define _GPIO_H_ +#define STM32_GPIOS_PER_BANK 16 + enum stm32_gpio_port { STM32_GPIO_PORT_A = 0, STM32_GPIO_PORT_B, @@ -109,6 +111,9 @@ struct stm32_gpio_regs { struct stm32_gpio_priv { struct stm32_gpio_regs *regs; + unsigned int gpio_range; }; +int stm32_offset_to_index(struct udevice *dev, unsigned int offset); + #endif /* _GPIO_H_ */ diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 8a929fa91322..0c68c24c09b1 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -16,8 +16,12 @@ config SPL select SPL_REGMAP select SPL_DM_RESET select SPL_SERIAL_SUPPORT + select SPL_SPI_LOAD select SPL_SYSCON - select SPL_DRIVERS_MISC_SUPPORT + select SPL_WATCHDOG_SUPPORT + imply BOOTSTAGE_STASH if SPL_BOOTSTAGE + imply SPL_BOOTSTAGE + imply SPL_DISPLAY_PRINT imply SPL_LIBDISK_SUPPORT config SYS_SOC @@ -25,18 +29,87 @@ 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 OF_BOARD_SETUP select PINCTRL_STM32 select STM32_RCC select STM32_RESET - select SYS_ARCH_TIMER - select SYSRESET_SYSCON + select STM32_SERIAL + imply BOOTCOUNT_LIMIT + imply SYSRESET_PSCI if STM32MP1_TRUSTED + imply SYSRESET_SYSCON if !STM32MP1_TRUSTED help target STMicroelectronics SOC STM32MP1 family + STM32MP153 or STM32MP151 STMicroelectronics MPU with core ARMv7 + dual core A7 for STM32MP153, monocore for STM32MP151 + +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 provide ST smc to manage secure devices + +config STM32MP1_OPTEE + bool "Support trusted boot with TF-A and OPTEE" + depends on STM32MP1_TRUSTED + default n + help + Say Y here to enable boot with TF-A and OPTEE + Trusted boot chain is : + BootRom => TF-A.stm32 (clock & DDR) => OPTEE => U-Boot.stm32 + OPTEE monitor provide ST smc to manage secure devices + +config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2 + hex "Partition to use for MMC2 to load U-Boot from" + depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION && TARGET_STM32MP1 + default 1 + help + Partition on the MMC2 to load U-Boot from when the MMC2 is being + used in raw mode + +config STM32_ETZPC + bool "STM32 Extended TrustZone Protection" + depends on TARGET_STM32MP1 + default y + help + Say y to enable STM32 Extended TrustZone Protection + Controller (ETZPC) + +source "board/st/stm32mp1/Kconfig" + +config CMD_STM32PROG + bool "command stm32prog for STM32CudeProgrammer" + default y + depends on CMD_DFU + imply CMD_GPT if MMC + imply DFU_MMC if MMC + imply DFU_NAND if NAND + select DFU_RAM + imply DFU_SF if DM_SPI_FLASH + select DFU_VIRT + select PARTITION_TYPE_GUID + help + activate a specific command stm32prog for STM32MP soc family + witch update the device with the tools STM32CubeProgrammer, + using UART with STM32 protocol or USB with DFU protocol + NB: access to not volatile memory (NOR/NAND/SD/eMMC) is based + on U-Boot DFU framework + +config CMD_STM32KEY + bool "command stm32key to fuse public key hash" + default y + depends on CMD_FUSE + help + fuse public key hash in corresponding fuse used to authenticate + binary. config SYS_TEXT_BASE prompt "U-Boot base address" @@ -46,22 +119,23 @@ config SYS_TEXT_BASE when DDR driver is used: DDR + 1MB (0xC0100000) -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 +config NR_DRAM_BANKS default 1 - help - Partition on the second MMC to load U-Boot from when the MMC is being - used in raw mode -source "board/st/stm32mp1/Kconfig" +config BOOTSTAGE_STASH_ADDR + default 0xC3000000 -# currently activated for debug / should be deactivated for real product -if DEBUG_UART -config DEBUG_UART_BOARD_INIT +if BOOTCOUNT_LIMIT +config SYS_BOOTCOUNT_SINGLEWORD default y +# TAMP_BOOTCOUNT = TAMP_BACKUP_REGISTER(21) +config SYS_BOOTCOUNT_ADDR + default 0x5C00A154 +endif + +if DEBUG_UART # debug on UART4 by default config DEBUG_UART_BASE default 0x40010000 @@ -69,6 +143,10 @@ config DEBUG_UART_BASE # clock source is HSI on reset config DEBUG_UART_CLOCK default 64000000 + +# currently activated for debug / should be deactivated for real product +config DEBUG_UART_BOARD_INIT + default y endif endif diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index f59ced5ee1b1..09636db01b35 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -10,7 +10,13 @@ obj-y += syscon.o ifdef CONFIG_SPL_BUILD obj-y += spl.o else +obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ +obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o + +obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-y += bsec.o +obj-y += cmd_poweroff.o endif -obj-$(CONFIG_ARMV7_PSCI) += psci.o + obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o +obj-$(CONFIG_STM32_ETZPC) += stm32-etzpc.o diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 0e152efc045f..913dbef41ad5 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ @@ -7,10 +7,14 @@ #include #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) */ @@ -168,7 +172,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); @@ -270,6 +274,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 +283,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 +309,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, @@ -405,8 +434,23 @@ 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,stm32mp-bsec" }, + { .compatible = "st,stm32mp15-bsec" }, {} }; @@ -417,15 +461,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, - .flags = DM_FLAG_PRE_RELOC, -}; - -/* 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, +#ifndef CONFIG_STM32MP1_TRUSTED + .probe = stm32mp_bsec_probe, +#endif }; diff --git a/arch/arm/mach-stm32mp/cmd_poweroff.c b/arch/arm/mach-stm32mp/cmd_poweroff.c new file mode 100644 index 000000000000..a6fdc79c79f9 --- /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) 2018, 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; +} diff --git a/arch/arm/mach-stm32mp/cmd_stm32key.c b/arch/arm/mach-stm32mp/cmd_stm32key.c new file mode 100644 index 000000000000..4245e6f4b1e9 --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32key.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include + +#define STM32_OTP_HASH_KEY_START 24 +#define STM32_OTP_HASH_KEY_SIZE 8 + +static void read_hash_value(u32 addr) +{ + int i; + + for (i = 0; i < STM32_OTP_HASH_KEY_SIZE; i++) { + printf("OTP value %i: %x\n", STM32_OTP_HASH_KEY_START + i, + __be32_to_cpu(*(u32 *)addr)); + addr += 4; + } +} + +static void fuse_hash_value(u32 addr, bool print) +{ + struct udevice *dev; + u32 word, val; + int i, 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; + } + + for (i = 0; i < STM32_OTP_HASH_KEY_SIZE; i++) { + if (print) + printf("Fuse OTP %i : %x\n", + STM32_OTP_HASH_KEY_START + i, + __be32_to_cpu(*(u32 *)addr)); + + word = STM32_OTP_HASH_KEY_START + i; + val = __be32_to_cpu(*(u32 *)addr); + misc_write(dev, STM32_BSEC_OTP(word), &val, 4); + + addr += 4; + } +} + +static int confirm_prog(void) +{ + puts("Warning: Programming fuses is an irreversible operation!\n" + " This may brick your system.\n" + " Use this command only if you are sure of what you are doing!\n" + "\nReally perform this fuse programming? \n"); + + if (confirm_yesno()) + return 1; + + puts("Fuse programming aborted\n"); + return 0; +} + +int do_stm32key(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u32 addr; + const char *op = argc >= 2 ? argv[1] : NULL; + int confirmed = argc > 3 && !strcmp(argv[2], "-y"); + + argc -= 2 + confirmed; + argv += 2 + confirmed; + + if (argc < 1) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[0], NULL, 16); + if (!addr) + return CMD_RET_USAGE; + + if (!strcmp(op, "read")) + read_hash_value(addr); + + if (!strcmp(op, "fuse")) { + if (!confirmed && !confirm_prog()) + return CMD_RET_FAILURE; + fuse_hash_value(addr, !confirmed); + } + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(stm32key, 4, 1, do_stm32key, + "Fuse ST Hash key", + "read : Read the hash store at addr in memory\n" + "stm32key fuse [-y] : Fuse hash store at addr in otp\n"); diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile new file mode 100644 index 000000000000..bb7b7e777426 --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2018, STMicroelectronics - All Rights Reserved +# + +obj-y += cmd_stm32prog.o +obj-y += stm32prog.o +obj-y += stm32prog_serial.o +obj-y += stm32prog_usb.o diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c new file mode 100644 index 000000000000..d1c07dc1f9fa --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include "stm32prog.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct stm32prog_data *data; + ulong addr, size; + int dev; + enum stm32prog_link_t link = LINK_UNDEFINED; + bool reset = false; + + if (argc < 3 || argc > 5) + return CMD_RET_USAGE; + + if (!strcmp(argv[1], "serial")) { + link = LINK_SERIAL; + } else { + if (!strcmp(argv[1], "usb")) { + link = LINK_USB; + } else { + pr_err("not supported link=%s\n", argv[1]); + return CMD_RET_USAGE; + } + } + dev = (int)simple_strtoul(argv[2], NULL, 10); + + addr = STM32_DDR_BASE; + size = 0; + if (argc > 3) { + addr = simple_strtoul(argv[3], NULL, 16); + if (!addr) + return CMD_RET_FAILURE; + } + if (argc > 4) + size = simple_strtoul(argv[4], NULL, 16); + + data = stm32prog_init(link, dev, addr, size); + if (!data) + return CMD_RET_FAILURE; + + switch (link) { + case LINK_SERIAL: + reset = stm32prog_serial_loop(data); + break; + case LINK_USB: + reset = stm32prog_usb_loop(data, dev); + break; + default: + break; + } + + stm32prog_clean(data); + + puts("Download done\n"); + if (reset) { + puts("Reset...\n"); + run_command("reset", 0); + } + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog, + " [] []\n" + "start communication with tools STM32Cubeprogrammer on with Flashlayout at ", + " = serial|usb\n" + " = device instance\n" + " = address of flashlayout\n" + " = size of flashlayout\n" +); diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c new file mode 100644 index 000000000000..d263b3859405 --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -0,0 +1,1647 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stm32prog.h" + +/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */ +#define GPT_HEADER_SZ 34 + +#define OPT_SELECT BIT(0) +#define OPT_EMPTY BIT(1) +#define OPT_DELETE BIT(2) + +#define IS_SELECT(part) (part->option & OPT_SELECT) +#define IS_EMPTY(part) (part->option & OPT_EMPTY) +#define IS_DELETE(part) (part->option & OPT_DELETE) + +#define ROOTFS_MMC0_UUID \ + EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \ + 0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82) + +#define ROOTFS_MMC1_UUID \ + EFI_GUID(0x491F6117, 0x415D, 0x4F53, \ + 0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6) + +#define ROOTFS_MMC2_UUID \ + EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \ + 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18) + +/* + * unique partition guid (uuid) for partition named "rootfs" + * on each MMC instance = SD Card or eMMC + * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..." + */ +const static efi_guid_t uuid_mmc[3] = { + ROOTFS_MMC0_UUID, + ROOTFS_MMC1_UUID, + ROOTFS_MMC2_UUID +}; + +DECLARE_GLOBAL_DATA_PTR; +#define ENV_BUF_LEN SZ_1K + +/* order of column in flash layout file */ +enum stm32prog_col_t { + COL_OPTION, + COL_ID, + COL_NAME, + COL_TYPE, + COL_IP, + COL_OFFSET, + COL_NB_STM32 +}; + +/* partition handling routines : CONFIG_CMD_MTDPARTS */ +int mtdparts_init(void); +int find_dev_and_part(const char *id, struct mtd_device **dev, + u8 *part_num, struct part_info **part); + +char *stm32prog_get_error(struct stm32prog_data *data) +{ + const char error_msg[] = "Unspecified"; + + if (strlen(data->error) == 0) + strcpy(data->error, error_msg); + + return data->error; +} + +u8 stm32prog_header_check(struct raw_header_s *raw_header, + struct image_header_s *header) +{ + int i; + + header->present = 0; + header->image_checksum = 0x0; + header->image_length = 0x0; + + /*pr_debug("%s entry\n", __func__);*/ + if (!raw_header || !header) { + pr_debug("%s:no header data\n", __func__); + return -1; + } + if (raw_header->magic_number != + (('S' << 0) | ('T' << 8) | ('M' << 16) | (0x32 << 24))) { + pr_debug("%s:invalid magic number : 0x%x\n", + __func__, raw_header->magic_number); + return -2; + } + /* only header v1.0 supported */ + if (raw_header->header_version != 0x00010000) { + pr_debug("%s:invalid header version : 0x%x\n", + __func__, raw_header->header_version); + return -3; + } + if (raw_header->reserved1 != 0x0 || raw_header->reserved2) { + pr_debug("%s:invalid reserved field\n", __func__); + return -4; + } + for (i = 0; i < (sizeof(raw_header->padding) / 4); i++) { + if (raw_header->padding[i] != 0) { + pr_debug("%s:invalid padding field\n", __func__); + return -5; + } + } + header->present = 1; + header->image_checksum = le32_to_cpu(raw_header->image_checksum); + header->image_length = le32_to_cpu(raw_header->image_length); + + /*pr_debug("%s exit\n", __func__);*/ + + return 0; +} + +static u32 stm32prog_header_checksum(u32 addr, struct image_header_s *header) +{ + u32 i, checksum; + u8 *payload; + + /* compute checksum on payload */ + payload = (u8 *)addr; + checksum = 0; + for (i = header->image_length; i > 0; i--) + checksum += *(payload++); + + return checksum; +} + +/* FLASHLAYOUT PARSING *****************************************/ +static int parse_option(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + char *c = p; + + part->option = 0; + if (!strcmp(p, "-")) + return 0; + + while (*c) { + switch (*c) { + case 'P': + part->option |= OPT_SELECT; + break; + case 'E': + part->option |= OPT_EMPTY; + break; + case 'D': + part->option |= OPT_DELETE; + break; + default: + result = -EINVAL; + stm32prog_err("Layout: invalid option '%c' in %s)", + *c, p); + return -EINVAL; + } + c++; + } + if (!(part->option & OPT_SELECT)) { + stm32prog_err("Layout: missing 'P' in option %s", p); + return -EINVAL; + } + + /* pr_debug("option : %x\n", part->option); */ + + return result; +} + +static int parse_id(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + unsigned long value; + + result = strict_strtoul(p, 0, &value); + part->id = value; + if (result || value > PHASE_LAST_USER) { + stm32prog_err("Layout: invalid phase value = %s", p); + result = -EINVAL; + } + /* pr_debug("phase : %x\n", part->id); */ + + return result; +} + +static int parse_name(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + + if (strlen(p) < sizeof(part->name)) { + strcpy(part->name, p); + } else { + stm32prog_err("Layout: partition name too long [%d] : %s", + strlen(p), p); + result = -EINVAL; + } + /* pr_debug("name : %s\n", part->name); */ + + return result; +} + +static int parse_type(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + int len = 0; + + part->bin_nb = 0; + if (!strncmp(p, "Binary", 6)) { + part->part_type = PART_BINARY; + + /* search for Binary(X) case */ + len = strlen(p); + part->bin_nb = 1; + if (len > 6) { + if (len < 8 || + (p[6] != '(') || + (p[len - 1] != ')')) + result = -EINVAL; + else + part->bin_nb = + simple_strtoul(&p[7], NULL, 10); + } + } else if (!strcmp(p, "System")) { + part->part_type = PART_SYSTEM; + } else if (!strcmp(p, "FileSystem")) { + part->part_type = PART_FILESYSTEM; + } else if (!strcmp(p, "RawImage")) { + part->part_type = RAW_IMAGE; + } else { + result = -EINVAL; + } + if (result) + stm32prog_err("Layout: type parsing error : '%s'", p); + /* pr_debug("type : %d\n", part->part_type); */ + + return result; +} + +static int parse_ip(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + int len = 0; + + part->dev_id = 0; + if (!strcmp(p, "none")) { + part->dev_type = DFU_DEV_VIRT; + } else if (!strncmp(p, "mmc", 3)) { + part->dev_type = DFU_DEV_MMC; + len = 3; + } else if (!strncmp(p, "nor", 3)) { + part->dev_type = DFU_DEV_SF; + len = 3; + } else if (!strncmp(p, "nand", 4)) { + part->dev_type = DFU_DEV_NAND; + len = 4; + } else { + result = -EINVAL; + } + if (len) { + /* only one digit allowed for device id */ + if (strlen(p) != len + 1) { + result = -EINVAL; + } else { + part->dev_id = p[len] - '0'; + if (part->dev_id > 9) + result = -EINVAL; + } + } + if (result) + stm32prog_err("Layout: ip parsing error : '%s'", p); + /* pr_debug("dev : %d\n", part->dev_id); */ + + return result; +} + +static int parse_offset(struct stm32prog_data *data, + char *p, struct stm32prog_part_t *part) +{ + int result = 0; + char *tail; + + part->part_id = 0; + part->addr = 0; + part->size = 0; + /* eMMC boot parttion */ + if (!strncmp(p, "boot", 4)) { + if (p[4] == '1') { + part->part_id = -1; + } else if (p[4] == '2') { + part->part_id = -2; + } else { + stm32prog_err("Layout: invalid part '%s'", p); + result = -EINVAL; + } + } else { + part->addr = simple_strtoull(p, &tail, 0); + if (tail == p || *tail != '\0') { + stm32prog_err("Layout: invalid offset '%s'", p); + result = -EINVAL; + } + } + /* pr_debug("addr : 0x%llx, part_id : %d\n", part->addr, + * part->part_id); + */ + + return result; +} + +static +int (* const parse[COL_NB_STM32])(struct stm32prog_data *data, char *p, + struct stm32prog_part_t *part) = { + [COL_OPTION] = parse_option, + [COL_ID] = parse_id, + [COL_NAME] = parse_name, + [COL_TYPE] = parse_type, + [COL_IP] = parse_ip, + [COL_OFFSET] = parse_offset, +}; + +static int parse_flash_layout(struct stm32prog_data *data, + ulong addr, + ulong size) +{ + int column = 0, part_nb = 0, ret; + bool end_of_line, eof; + char *p, *start, *last, *col; + struct stm32prog_part_t *part; + int part_list_size; + bool stm32image = false; + + data->part_nb = 0; + + /* check if STM32image is detected */ + if (!stm32prog_header_check((struct raw_header_s *)addr, + &data->header)) { + u32 checksum; + + addr = addr + BL_HEADER_SIZE; + size = data->header.image_length; + stm32image = true; + + checksum = stm32prog_header_checksum(addr, &data->header); + if (checksum != data->header.image_checksum) { + stm32prog_err("Layout: invalid checksum : 0x%x expected 0x%x", + checksum, data->header.image_checksum); + return -EIO; + } + } + if (!size) + return -EINVAL; + + start = (char *)addr; + last = start + size; + + *last = 0x0; /* force null terminated string */ + pr_debug("flash layout =\n%s\n", start); + + /* calculate expected number of partitions */ + part_list_size = 1; + p = start; + while (*p && (p < last)) { + if (*p++ == '\n') { + part_list_size++; + if (p < last && *p == '#') + part_list_size--; + } + } + if (part_list_size > PHASE_LAST_USER) { + stm32prog_err("Layout: too many line"); + return -1; + } + part = calloc(sizeof(struct stm32prog_part_t), part_list_size); + if (!part) { + stm32prog_err("Layout: alloc failed"); + return -ENOMEM; + } + data->part_array = part; + + /* main parsing loop */ + eof = false; + p = start; + col = start; /* 1st column */ + while (!eof) { + end_of_line = false; + switch (*p) { + /* CR is ignored and replaced by NULL chararc*/ + case '\r': + *p = '\0'; + p++; + continue; + /* end of column detected */ + case '\0': + end_of_line = true; + eof = true; + break; + case '\n': + end_of_line = true; + break; + case '\t': + break; + case '#': + /* comment line is skipped */ + if (column == 0 && p == col) { + while ((p < last) && *p) + if (*p++ == '\n') + break; + col = p; + if (p >= last || !*p) + eof = true; + continue; + } + /* no break */ + /* by default continue with the next character */ + default: + p++; + continue; + } + + /* replace by \0 to allow string parsing */ + *p = '\0'; + p++; + if (p >= last) { + eof = true; + end_of_line = true; + } + /*pr_debug("%d:%d = '%s' => ", part_nb, column, col);*/ + if (strlen(col) == 0) { + col = p; + /* skip empty line */ + if (column == 0 && end_of_line) + continue; + /* multiple TAB allowed in tsv file */ + if (!stm32image) + continue; + stm32prog_err("empty field for line %d", part_nb); + return -1; + } + if (column < COL_NB_STM32) { + ret = parse[column](data, col, part); + if (ret) + return ret; + } + + /* save the beginning of the next column */ + column++; + col = p; + + if (!end_of_line) + continue; + + /* end of the line detected */ + if (column < COL_NB_STM32) { + stm32prog_err("Layout: no enought column for line %d", + part_nb); + return -EINVAL; + } + column = 0; + part_nb++; + part++; + if (part_nb >= part_list_size) { + part = NULL; + if (!eof) { + stm32prog_err("Layout: no enought memory for %d part", + part_nb); + return -EINVAL; + } + } + } + data->part_nb = part_nb; + if (data->part_nb == 0) { + stm32prog_err("Layout: no partition found"); + return -ENODEV; + } + + return 0; +} + +static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b) +{ + struct stm32prog_part_t *parta, *partb; + + parta = container_of(a, struct stm32prog_part_t, list); + partb = container_of(b, struct stm32prog_part_t, list); + + if (parta->part_id != partb->part_id) + return parta->part_id - partb->part_id; + else + return parta->addr > partb->addr ? 1 : -1; +} + +static int init_device(struct stm32prog_data *data, + struct stm32prog_dev_t *dev) +{ + struct mmc *mmc = NULL; +#ifdef CONFIG_MTD_PARTITIONS + struct blk_desc *block_dev = NULL; + struct mtd_info *mtd = NULL; + char mtd_id[16]; + char cmdbuf[40]; +#endif + int part_id; + int ret; + u64 first_addr = 0, last_addr = 0; + struct stm32prog_part_t *part, *next_part; + u64 part_addr, part_size; + + dev->lba_blk_size = MMC_MAX_BLOCK_LEN; + switch (dev->dev_type) { + case DFU_DEV_MMC: + mmc = find_mmc_device(dev->dev_id); + if (mmc_init(mmc)) { + stm32prog_err("mmc device %d not found", dev->dev_id); + return -ENODEV; + } + block_dev = mmc_get_blk_desc(mmc); + if (!block_dev) { + stm32prog_err("mmc device %d not probed", dev->dev_id); + return -ENODEV; + } + dev->lba_blk_size = mmc->read_bl_len; + dev->erase_size = mmc->erase_grp_size * block_dev->blksz; + + /* reserve a full erase group for each GTP headers */ + if (mmc->erase_grp_size > GPT_HEADER_SZ) { + first_addr = dev->erase_size; + last_addr = (u64)(block_dev->lba - + mmc->erase_grp_size) * + block_dev->blksz; + } else { + first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz; + last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) * + block_dev->blksz; + } + pr_debug("MMC %d: lba=%ld blksz=%ld\n", dev->dev_id, + block_dev->lba, block_dev->blksz); + pr_debug(" available address = 0x%llx..0x%llx\n", + first_addr, last_addr); + break; +#ifdef CONFIG_MTD_PARTITIONS + case DFU_DEV_SF: +#ifdef CONFIG_SPI_FLASH + sprintf(cmdbuf, "sf probe %d", dev->dev_id); + if (run_command(cmdbuf, 0)) { + stm32prog_err("invalid device : %s", cmdbuf); + return -ENODEV; + } + sprintf(mtd_id, "nor%d", dev->dev_id); + pr_debug("%s\n", mtd_id); + break; +#else + stm32prog_err("device SF nor supported"); + return -ENODEV; +#endif + case DFU_DEV_NAND: + sprintf(cmdbuf, "nand device %d", dev->dev_id); + if (run_command(cmdbuf, 0)) { + stm32prog_err("invalid device : %s", cmdbuf); + return -ENODEV; + } + sprintf(mtd_id, "nand%d", dev->dev_id); + pr_debug("%s\n", mtd_id); + break; +#endif + default: + stm32prog_err("unknown device type = %d", dev->dev_type); + return -ENODEV; + } +#ifdef CONFIG_MTD_PARTITIONS + if (dev->dev_type == DFU_DEV_SF || + dev->dev_type == DFU_DEV_NAND) { +#ifdef CONFIG_SPI_FLASH + if (dev->dev_type == DFU_DEV_NAND) { + /* sf probe is needed for mtdparts + * because mtdids can use nor0 and nor driver + * is not probed by default as nand + */ + sprintf(cmdbuf, "sf probe %d", dev->dev_id); + run_command(cmdbuf, 0); + } +#endif + mtdparts_init(); + mtd = get_mtd_device_nm(mtd_id); + if (IS_ERR(mtd)) { + stm32prog_err("MTD device %s not found", mtd_id); + return -ENODEV; + } + first_addr = 0; + last_addr = mtd->size; + dev->erase_size = mtd->erasesize; + pr_debug("MTD device %s : size=%lld erasesize=%d\n", + mtd_id, mtd->size, mtd->erasesize); + pr_debug(" available address = 0x%llx..0x%llx\n", + first_addr, last_addr); + } + dev->mtd = mtd; +#endif + pr_debug(" erase size = 0x%x\n", dev->erase_size); + dev->block_dev = block_dev; + + /* order partition list in offset order */ + list_sort(NULL, &dev->part_list, &part_cmp); + part_id = 1; + pr_debug("id : Opt Phase Name type.n dev.n addr size part_off part_size\n"); + list_for_each_entry(part, &dev->part_list, list) { + if (part->bin_nb > 1) { + if (dev->dev_type != DFU_DEV_NAND || + part->id >= PHASE_FIRST_USER || + strncmp(part->name, "fsbl", 4)) { + stm32prog_err("%s: multiple binary %d not supported for phase %d", + part->name, part->bin_nb, + part->id); + return -EINVAL; + } + } + if (part->part_type == RAW_IMAGE) { + part->part_id = 0x0; + part->addr = 0x0; + if (block_dev) + part->size = block_dev->lba * block_dev->blksz; + else + part->size = last_addr; + pr_debug("-- : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx\n", + part->option, part->id, part->name, + part->part_type, part->bin_nb, part->dev_type, + part->dev_id, part->addr, part->size); + continue; + } + if (part->part_id < 0) { /* boot hw partition for eMMC */ + if (mmc) { + part->size = mmc->capacity_boot; + } else { + stm32prog_err("%s: hw partition not expected : %d", + part->name, part->part_id); + return -ENODEV; + } + } else { + part->part_id = part_id++; + + /* last partition : size to the end of the device */ + if (part->list.next != &dev->part_list) { + next_part = + container_of(part->list.next, + struct stm32prog_part_t, + list); + if (part->addr < next_part->addr) { + part->size = next_part->addr - + part->addr; + } else { + stm32prog_err("%s: invalid address : 0x%llx >= 0x%llx", + part->name, part->addr, + next_part->addr); + return -EINVAL; + } + } else { + if (part->addr <= last_addr) { + part->size = last_addr - part->addr; + } else { + stm32prog_err("%s: invalid address 0x%llx (max=0x%llx)", + part->name, part->addr, + last_addr); + return -EINVAL; + } + } + if (part->addr < first_addr) { + stm32prog_err("%s: invalid address 0x%llx (min=0x%llx)", + part->name, part->addr, + first_addr); + return -EINVAL; + } + } + if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) { + stm32prog_err("%s: not aligned address : 0x%llx on erase size 0x%x", + part->name, part->addr, + part->dev->erase_size); + return -EINVAL; + } + pr_debug("%02d : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx", + part->part_id, part->option, part->id, part->name, + part->part_type, part->bin_nb, part->dev_type, + part->dev_id, part->addr, part->size); + + part_addr = 0; + part_size = 0; + /* check coherency with existing partition */ + if (block_dev) { + disk_partition_t partinfo; + + /* only check partition size for partial update */ + if (data->full_update || part->part_id < 0) { + pr_debug("\n"); + continue; + } + + ret = part_get_info(block_dev, part->part_id, + &partinfo); + + if (ret) { + stm32prog_err("Couldn't find part %d on device mmc %d", + part_id, part->dev_id); + return -ENODEV; + } + part_addr = (u64)partinfo.start * partinfo.blksz; + part_size = (u64)partinfo.size * partinfo.blksz; + } + +#ifdef CONFIG_MTD_PARTITIONS + if (mtd) { + char mtd_part_id[32]; + struct part_info *mtd_part; + struct mtd_device *mtd_dev; + u8 part_num; + + sprintf(mtd_part_id, "%s,%d", mtd_id, + part->part_id - 1); + ret = find_dev_and_part(mtd_part_id, &mtd_dev, + &part_num, &mtd_part); + if (ret != 0) { + stm32prog_err("Invalid partition %s", + mtd_part_id); + return -ENODEV; + } + part_addr = mtd_part->offset; + part_size = mtd_part->size; + } +#endif + pr_debug(" %08llx %08llx\n", part_addr, part_size); + + if (part->addr != part_addr) { + stm32prog_err("%s: Bad address requested for partition %d = 0x%llx <> 0x%llx", + part->name, part->part_id, part->addr, + part_addr); + return -ENODEV; + } + if (part->size != part_size) { + stm32prog_err("%s: Bad size requested for partition %d = 0x%llx <> 0x%llx", + part->name, part->part_id, part->size, + part_size); + return -ENODEV; + } + } + return 0; +} + +static int treat_partition_list(struct stm32prog_data *data) +{ + int i, j; + struct stm32prog_part_t *part; + + for (j = 0; j < STM32PROG_MAX_DEV; j++) { + data->dev[j].dev_type = -1; + INIT_LIST_HEAD(&data->dev[j].part_list); + } + + data->full_update = 1; + /*pr_debug("id : S Phase Name type dev.n addr id\n");*/ + for (i = 0; i < data->part_nb; i++) { + part = &data->part_array[i]; + part->alt_id = -1; + + /* skip partition with IP="none" */ + if (part->dev_type == DFU_DEV_VIRT) { + if (IS_SELECT(part)) { + stm32prog_err("Layout: selected none phase = 0x%x", + part->id); + return -EINVAL; + } + continue; + } + + /* + * pr_debug("%02d : %1d %02x %14s %02d %02d.%02d 0x%08llx %d\n", + * i, part->option, part->id, part->name, + * part->part_type, part->dev_id_type, part->dev_id, + * part->addr, part->part_id); + */ + if (!IS_SELECT(part) && part->part_type != RAW_IMAGE) + data->full_update = 0; + + if (part->id == PHASE_FLASHLAYOUT || + part->id > PHASE_LAST_USER) { + stm32prog_err("Layout: invalid phase = 0x%x", + part->id); + return -EINVAL; + } + for (j = i + 1; j < data->part_nb; j++) { + if (part->id == data->part_array[j].id) { + stm32prog_err("Layout: duplicated phase %d at line %d and %d", + part->id, i, j); + return -EINVAL; + } + } + for (j = 0; j < STM32PROG_MAX_DEV; j++) { + if (data->dev[j].dev_type == -1) { + /* new device found */ + data->dev[j].dev_type = part->dev_type; + data->dev[j].dev_id = part->dev_id; + data->dev_nb++; + break; + } else if ((part->dev_type == data->dev[j].dev_type) && + (part->dev_id == data->dev[j].dev_id)) { + break; + } + } + if (j == STM32PROG_MAX_DEV) { + stm32prog_err("Layout: too many device"); + return -EINVAL; + } + part->dev = &data->dev[j]; + list_add_tail(&part->list, &data->dev[j].part_list); + } + + return 0; +} + +static int create_partitions(struct stm32prog_data *data) +{ + int offset = 0; + char cmdbuf[32]; + char buf[ENV_BUF_LEN]; + char uuid[UUID_STR_LEN + 1]; + unsigned char *uuid_bin; + int i, mmc_id; + bool rootfs_found; + struct stm32prog_part_t *part; + + puts("partitions : "); + /* initialize the selected device */ + for (i = 0; i < data->dev_nb; i++) { + /* gpt support only for MMC */ + if (data->dev[i].dev_type != DFU_DEV_MMC) + continue; + + offset = 0; + rootfs_found = false; + memset(buf, 0, sizeof(buf)); + + list_for_each_entry(part, &data->dev[i].part_list, list) { + /* skip eMMC boot partitions */ + if (part->part_id < 0) + continue; + + /* skip Raw Image */ + if (part->part_type == RAW_IMAGE) + continue; + + offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + "name=%s,start=0x%llx,size=0x%llx", + part->name, + part->addr, + part->size); + + if (part->part_type == PART_BINARY) + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + ",type=data"); + else + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + ",type=linux"); + + if (part->part_type == PART_SYSTEM) + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + ",bootable"); + + if (!rootfs_found && !strcmp(part->name, "rootfs")) { + mmc_id = part->dev_id; + rootfs_found = true; + if (mmc_id < ARRAY_SIZE(uuid_mmc)) { + uuid_bin = + (unsigned char *)uuid_mmc[mmc_id].b; + uuid_bin_to_str(uuid_bin, uuid, + UUID_STR_FORMAT_GUID); + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + ",uuid=%s", uuid); + } + } + + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + ";"); + } + + if (offset) { + sprintf(cmdbuf, "gpt write mmc %d \"%s\"", + data->dev[i].dev_id, buf); + pr_debug("cmd: %s\n", cmdbuf); + if (run_command(cmdbuf, 0)) { + stm32prog_err("partitionning fail : %s", + cmdbuf); + return -1; + } + } + + if (data->dev[i].block_dev) + part_init(data->dev[i].block_dev); + +#ifdef DEBUG + sprintf(cmdbuf, "gpt verify mmc %d", + data->dev[i].dev_id); + pr_debug("cmd: %s ", cmdbuf); + if (run_command(cmdbuf, 0)) + printf("fail !\n"); + else + printf("OK\n"); + + /* TEMP : for debug, display partition */ + sprintf(cmdbuf, "part list mmc %d", + data->dev[i].dev_id); + run_command(cmdbuf, 0); +#endif + } + puts("done\n"); + return 0; +} + +static int stm32prog_alt_add(struct stm32prog_data *data, + struct dfu_entity *dfu, + struct stm32prog_part_t *part) +{ + int ret = 0; + int offset = 0; + char devstr[4]; + char dfustr[10]; + char buf[ENV_BUF_LEN]; + u32 size; + char multiplier, type; + + /* max 3 digit for sector size */ + if (part->size > SZ_1M) { + size = (u32)(part->size / SZ_1M); + multiplier = 'M'; + } else if (part->size > SZ_1K) { + size = (u32)(part->size / SZ_1K); + multiplier = 'K'; + } else { + size = (u32)part->size; + multiplier = 'B'; + } + if (IS_SELECT(part) && !IS_EMPTY(part)) + type = 'e'; /*Readable and Writeable*/ + else + type = 'a';/*Readable*/ + + memset(buf, 0, sizeof(buf)); + offset = snprintf(buf, ENV_BUF_LEN - offset, + "@%s/0x%02x/1*%d%c%c ", + part->name, part->id, + size, multiplier, type); + + if (part->part_type == RAW_IMAGE) { + u64 dfu_size; + + if (part->dev->dev_type == DFU_DEV_MMC) + dfu_size = part->size / part->dev->lba_blk_size; + else + dfu_size = part->size; + offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + "raw 0x0 0x%llx", dfu_size); + } else if (part->part_id < 0) { + u64 nb_blk = part->size / part->dev->lba_blk_size; + + /* lba_blk_size, mmc->read_bl_len */ + offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + "raw 0x%llx 0x%llx", + part->addr, nb_blk); + offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + " mmcpart %d;", -(part->part_id)); + } else { + if (part->part_type == PART_SYSTEM && + (part->dev_type == DFU_DEV_NAND || + part->dev_type == DFU_DEV_SF)) + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + "partubi"); + else + offset += snprintf(buf + offset, + ENV_BUF_LEN - offset, + "part"); + offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + " %d %d;", + part->dev_id, + part->part_id); + } + switch (part->dev_type) { + case DFU_DEV_MMC: + sprintf(dfustr, "mmc"); + sprintf(devstr, "%d", part->dev_id); + break; + case DFU_DEV_SF: + sprintf(dfustr, "sf"); + sprintf(devstr, "0:%d", part->dev_id); + break; + case DFU_DEV_NAND: + sprintf(dfustr, "nand"); + sprintf(devstr, "%d", part->dev_id); + break; + default: + stm32prog_err("invalid dev_type: %d", part->dev_type); + return -ENODEV; + } + ret = dfu_alt_add(dfu, dfustr, devstr, buf); + pr_debug("dfu_alt_add(%s,%s,%s) result %d\n", + dfustr, devstr, buf, ret); + + return ret; +} + +static int stm32prog_alt_add_virt(struct dfu_entity *dfu, + char *name, int phase, int size) +{ + int ret = 0; + char devstr[4]; + char buf[ENV_BUF_LEN]; + + sprintf(devstr, "%d", phase); + sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size); + ret = dfu_alt_add(dfu, "virt", devstr, buf); + pr_debug("dfu_alt_add(virt,%s,%s) result %d\n", devstr, buf, ret); + + return ret; +} + +static int dfu_init_entities(struct stm32prog_data *data) +{ + int ret = 0; + int phase, i, alt_id; + struct stm32prog_part_t *part; + struct dfu_entity *dfu; + int alt_nb; + + /* nb of alternate = nb part not virtual or 1 for FlashLayout + * + 3 virtual for CMD and OTP and PMIC + */ + if (data->part_nb == 0) { + alt_nb = 4; + } else { + alt_nb = 3; + for (i = 0; i < data->part_nb; i++) { + if (data->part_array[i].dev_type != DFU_DEV_VIRT) + alt_nb++; + } + } + + if (dfu_alt_init(alt_nb, &dfu)) + return -ENODEV; + + puts("DFU alt info setting: "); + if (data->part_nb) { + alt_id = 0; + for (phase = 1; + (phase <= PHASE_LAST_USER) && + (alt_id < alt_nb) && !ret; + phase++) { + /* ordering alt setting by phase id */ + part = NULL; + for (i = 0; i < data->part_nb; i++) { + if (phase == data->part_array[i].id) { + part = &data->part_array[i]; + break; + } + } + if (!part) + continue; + if (part->dev_type == DFU_DEV_VIRT) + continue; + part->alt_id = alt_id; + alt_id++; + + ret = stm32prog_alt_add(data, dfu, part); + } + } else { + char buf[ENV_BUF_LEN]; + + sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000", + PHASE_FLASHLAYOUT, STM32_DDR_BASE); + ret = dfu_alt_add(dfu, "ram", NULL, buf); + pr_debug("dfu_alt_add(ram, NULL,%s) result %d\n", buf, ret); + } + + if (!ret) + ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512); + + if (!ret) + ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512); + +#ifdef CONFIG_DM_PMIC + if (!ret) + ret = stm32prog_alt_add_virt(dfu, "PMIC", PHASE_PMIC, 8); +#endif + + if (ret) + stm32prog_err("dfu init failed: %d", ret); + puts("done\n"); +#ifdef DEBUG + /* TEMP : for debug */ + dfu_show_entities(); +#endif + return ret; +} + +int stm32prog_otp_write(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ + pr_debug("%s : %x %lx\n", __func__, offset, *size); + + if (!data->otp_part) { + data->otp_part = memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE); + if (!data->otp_part) + return -ENOMEM; + } + + if (!offset) + memset(data->otp_part, 0, OTP_SIZE); + + if (offset + *size > OTP_SIZE) + *size = OTP_SIZE - offset; + + memcpy((void *)((u32)data->otp_part + offset), buffer, *size); + return 0; +} + +int stm32prog_otp_read(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ +#ifndef CONFIG_ARM_SMCCC + stm32prog_err("OTP update not supported"); + return -1; +#else + int result = 0; + + pr_debug("%s : %x %lx\n", __func__, offset, *size); + /* alway read for first packet */ + if (!offset) { + if (!data->otp_part) + data->otp_part = + memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE); + + if (!data->otp_part) { + result = -ENOMEM; + goto end_otp_read; + } + + /* init struct with 0 */ + memset(data->otp_part, 0, OTP_SIZE); + + /* call the service */ + result = stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_READ_ALL, + (u32)data->otp_part, 0); + if (result) + goto end_otp_read; + } + + if (!data->otp_part) { + result = -ENOMEM; + goto end_otp_read; + } + + if (offset + *size > OTP_SIZE) + *size = OTP_SIZE - offset; + memcpy(buffer, (void *)((u32)data->otp_part + offset), *size); + +end_otp_read: + pr_debug("%s : result %i\n", __func__, result); + return result; +#endif +} + +int stm32prog_otp_start(struct stm32prog_data *data) +{ +#ifndef CONFIG_ARM_SMCCC + stm32prog_err("OTP update not supported"); + return -1; +#else + int result = 0; + struct arm_smccc_res res; + + if (!data->otp_part) { + stm32prog_err("start OTP without data"); + return -1; + } + + arm_smccc_smc(STM32_SMC_BSEC, STM32_SMC_WRITE_ALL, + (u32)data->otp_part, 0, 0, 0, 0, 0, &res); + + if (!res.a0) { + switch (res.a1) { + case 0: + result = 0; + break; + case 1: + stm32prog_err("Provisioning"); + result = 0; + break; + default: + pr_err("%s: OTP incorrect value (err = %ld)\n", + __func__, res.a1); + result = -EINVAL; + break; + } + } else { + pr_err("%s: Failed to exec in secure mode (err = %ld)\n", + __func__, res.a0); + result = -EINVAL; + } + + free(data->otp_part); + data->otp_part = NULL; + pr_debug("%s : result %i\n", __func__, result); + return result; +#endif +} + +int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ + pr_debug("%s : %x %lx\n", __func__, offset, *size); + + if (!offset) + memset(data->pmic_part, 0, PMIC_SIZE); + + if (offset + *size > PMIC_SIZE) + *size = PMIC_SIZE - offset; + + memcpy(&data->pmic_part[offset], buffer, *size); + + return 0; +} + +int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, u8 *buffer, + long *size) +{ +#ifndef CONFIG_DM_PMIC + stm32prog_err("PMIC update not supported"); + return -EOPNOTSUPP; +#else /* CONFIG_DM_PMIC */ + int result = 0; + + pr_debug("%s : %x %lx\n", __func__, offset, *size); + + /* alway request PMIC for first packet */ + if (!offset) { + /* init struct with 0 */ + memset(data->pmic_part, 0, PMIC_SIZE); + + result = stpmic1_nvm_read_all(data->pmic_part, PMIC_SIZE); + if (result < 0) + goto end_pmic_read; + } + + if (offset + *size > PMIC_SIZE) + *size = PMIC_SIZE - offset; + + memcpy(buffer, &data->pmic_part[offset], *size); + +end_pmic_read: + pr_debug("%s : result %i\n", __func__, result); + return result; +#endif /* CONFIG_DM_PMIC */ +} + +int stm32prog_pmic_start(struct stm32prog_data *data) +{ +#ifndef CONFIG_DM_PMIC + stm32prog_err("PMIC update not supported"); + return -EOPNOTSUPP; +#else /* CONFIG_DM_PMIC */ + return stpmic1_nvm_write_all(data->pmic_part, PMIC_SIZE); +#endif /* CONFIG_DM_PMIC */ +} + +/* copy FSBL on NAND to improve reliability on NAND */ +static int stm32prog_copy_fsbl(struct stm32prog_part_t *part) +{ +#ifndef CONFIG_CMD_NAND + return -1; +#else + loff_t start, lim; + size_t count, actual = 0; + int ret, i; + void *fsbl; + nand_erase_options_t opts; + struct image_header_s header; + struct raw_header_s raw_header; + + if (part->dev_type != DFU_DEV_NAND) + return -1; + + start = part->addr; + lim = part->size; + count = BL_HEADER_SIZE; + + ret = nand_read_skip_bad(part->dev->mtd, start, &count, &actual, lim, + (void *)&raw_header); + if (ret) + return ret; + if (stm32prog_header_check(&raw_header, &header)) + return -1; + + count = header.image_length + BL_HEADER_SIZE; + fsbl = calloc(1, count); + if (!fsbl) + return -ENOMEM; + ret = nand_read_skip_bad(part->dev->mtd, start, &count, &actual, lim, + fsbl); + if (ret) + goto error; + + memset(&opts, 0, sizeof(opts)); + opts.length = count; + opts.spread = 1; +#ifndef DEBUG + opts.quiet = 1; +#endif + + for (i = part->bin_nb - 1; i > 0; i--) { + size_t block_offset; + + /* copy to next block */ + start += actual; + block_offset = start & (part->dev->mtd->erasesize - 1); + if (block_offset != 0) + start += part->dev->mtd->erasesize - block_offset; + + lim = part->size - (start - part->addr); + + /* first erase */ + opts.offset = start; + opts.lim = lim; + ret = nand_erase_opts(part->dev->mtd, &opts); + if (ret) + goto error; + + /* then write */ + ret = nand_write_skip_bad(part->dev->mtd, + start, &count, &actual, + lim, fsbl, WITH_WR_VERIFY); + if (ret) + goto error; + } + +error: + free(fsbl); + /* pr_debug("%s exit ret=%d\n", __func__, ret); */ + return ret; +#endif +} + +void stm32prog_end_phase(struct stm32prog_data *data) +{ + if (data->phase == PHASE_FLASHLAYOUT) { + if (parse_flash_layout(data, STM32_DDR_BASE, 0)) + stm32prog_err("Layout: invalid FlashLayout"); + return; + } + + if (!data->cur_part) + return; + + if (data->cur_part->part_id < 0) { + char cmdbuf[60]; + + sprintf(cmdbuf, "mmc bootbus %d 0 0 0; mmc partconf %d 1 %d 0", + data->cur_part->dev_id, data->cur_part->dev_id, + -(data->cur_part->part_id)); + if (run_command(cmdbuf, 0)) { + stm32prog_err("commands %s have failed", cmdbuf); + return; + } + } + + if (data->cur_part->bin_nb > 1) { + if (stm32prog_copy_fsbl(data->cur_part)) { + stm32prog_err("copy of fsbl failed"); + return; + } + } +} + +void stm32prog_do_reset(struct stm32prog_data *data) +{ + if (data->phase == PHASE_RESET) { + data->phase = PHASE_DO_RESET; + puts("Reset requested\n"); + } +} + +void stm32prog_next_phase(struct stm32prog_data *data) +{ + int phase, i; + struct stm32prog_part_t *part; + + /*pr_debug("%s entry\n", __func__);*/ + + phase = data->phase; + switch (phase) { + case PHASE_RESET: + case PHASE_END: + case PHASE_DO_RESET: + return; + } + + /* found next selected partition */ + phase++; + data->cur_part = NULL; + data->dfu_seq = 0; + data->phase = PHASE_END; + while ((phase <= PHASE_LAST_USER) && !data->cur_part) { + for (i = 0; i < data->part_nb; i++) { + part = &data->part_array[i]; + if (part->id == phase) { + if (IS_SELECT(part) && !IS_EMPTY(part)) { + data->cur_part = part; + data->phase = phase; + } + break; + } + } + phase++; + } + if (data->phase == PHASE_END) + puts("Phase=END\n"); + + /*pr_debug("%s exit phase=0x%x\n", __func__, data->phase);*/ +} + +static int part_delete(struct stm32prog_data *data, + struct stm32prog_part_t *part) +{ + int ret = 0; + unsigned long blks, blks_offset, blks_size; +#ifdef CONFIG_SPI_FLASH + char cmdbuf[40]; +#endif + + printf("Erasing %s ", part->name); + switch (part->dev_type) { + case DFU_DEV_MMC: + printf("on mmc %d: ", part->dev->dev_id); + blks_offset = lldiv(part->addr, part->dev->lba_blk_size); + blks_size = lldiv(part->size, part->dev->lba_blk_size); + /* -1 or -2 : delete boot partition of MMC + * need to switch to associated hwpart 1 or 2 + */ + if (part->part_id < 0) + if (blk_select_hwpart_devnum(IF_TYPE_MMC, + part->dev->dev_id, + -part->part_id)) + return -1; + blks = blk_derase(part->dev->block_dev, blks_offset, blks_size); + /* return to user partition */ + if (part->part_id < 0) + blk_select_hwpart_devnum(IF_TYPE_MMC, + part->dev->dev_id, 0); + if (blks != blks_size) { + ret = -1; + stm32prog_err("mmc erase failed"); + } + break; + +#ifdef CONFIG_SPI_FLASH + case DFU_DEV_SF: + printf("on sf %d: ", part->dev->dev_id); + sprintf(cmdbuf, "sf erase 0x%llx 0x%llx", + part->addr, part->size); + if (run_command(cmdbuf, 0)) { + ret = -1; + stm32prog_err("sf erase commands failed (%s)", cmdbuf); + } + break; +#endif + +#ifdef CONFIG_CMD_NAND + case DFU_DEV_NAND: + printf("on nand %d: ", part->dev->dev_id); + nand_erase_options_t opts; + memset(&opts, 0, sizeof(opts)); + opts.offset = part->addr; + opts.length = part->size; + opts.quiet = 1; + ret = nand_erase_opts(part->dev->mtd, &opts); + if (ret) + stm32prog_err("nand erase failed"); + break; +#endif + default: + ret = -1; + stm32prog_err("erase invalid"); + break; + } + if (!ret) + printf("done\n"); + + return ret; +} + +void stm32prog_devices_init(struct stm32prog_data *data) +{ + int i; + int ret; + struct stm32prog_part_t *part; + + ret = treat_partition_list(data); + if (ret) + goto error; + + /* initialize the selected device */ + for (i = 0; i < data->dev_nb; i++) { + ret = init_device(data, &data->dev[i]); + if (ret) + goto error; + } + + /* delete RAW partition before create partition */ + for (i = 0; i < data->part_nb; i++) { + part = &data->part_array[i]; + + if (part->part_type != RAW_IMAGE) + continue; + + if (!IS_SELECT(part) || !IS_DELETE(part)) + continue; + + ret = part_delete(data, part); + if (ret) + goto error; + } + + if (data->full_update) { + ret = create_partitions(data); + if (ret) + goto error; + } + + /* delete partition GPT or MTD */ + for (i = 0; i < data->part_nb; i++) { + part = &data->part_array[i]; + + if (part->part_type == RAW_IMAGE) + continue; + + if (!IS_SELECT(part) || !IS_DELETE(part)) + continue; + + ret = part_delete(data, part); + if (ret) + goto error; + } + + return; + +error: + data->part_nb = 0; +} + +int stm32prog_dfu_init(struct stm32prog_data *data) +{ + /* init device if no error */ + if (data->part_nb) + stm32prog_devices_init(data); + + if (data->part_nb) + stm32prog_next_phase(data); + + /* prepare DFU for device read/write */ + dfu_free_entities(); + return dfu_init_entities(data); +} + +struct stm32prog_data *stm32prog_init(enum stm32prog_link_t link, + int link_dev, + ulong addr, + ulong size) +{ + struct stm32prog_data *data; + + /*pr_debug("%s entry\n", __func__);*/ + data = (struct stm32prog_data *)malloc(sizeof(*data)); + + if (!data) { + pr_err("alloc failed"); + goto err; + } + memset(data, 0x0, sizeof(*data)); + data->read_phase = PHASE_RESET; + data->phase = PHASE_FLASHLAYOUT; + + parse_flash_layout(data, addr, size); + + /* prepare DFU for device read/write */ + if (stm32prog_dfu_init(data)) + goto err; + + switch (link) { + case LINK_SERIAL: + if (stm32prog_serial_init(data, link_dev)) + goto err; + data->buffer = memalign(CONFIG_SYS_CACHELINE_SIZE, + USART_RAM_BUFFER_SIZE); + break; + case LINK_USB: + break; + default: + break; + } + /*pr_debug("%s exit ok\n", __func__);*/ + return data; + +err: + free(data); + pr_debug("%s exit error\n", __func__); + return 0; +} + +void stm32prog_clean(struct stm32prog_data *data) +{ + /* clean */ + dfu_free_entities(); + free(data->part_array); + free(data->otp_part); + free(data->buffer); + free(data->header_data); + free(data); +} diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h new file mode 100644 index 000000000000..51541bc79e9c --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef _STM32PROG_H_ +#define _STM32PROG_H_ + +/* - configuration part -----------------------------*/ +#define USART_BL_VERSION 0x40 /* USART bootloader version V4.0*/ +#define UBOOT_BL_VERSION 0x03 /* bootloader version V0.3*/ +#define DEVICE_ID_BYTE1 0x05 /* MSB byte of device ID*/ +#define DEVICE_ID_BYTE2 0x00 /* LSB byte of device ID*/ +#define USART_RAM_BUFFER_SIZE 256 /* Size of USART_RAM_Buf buffer*/ + +/* - Commands -----------------------------*/ +#define GET_CMD_COMMAND 0x00 /* Get CMD command*/ +#define GET_VER_COMMAND 0x01 /* Get Version command*/ +#define GET_ID_COMMAND 0x02 /* Get ID command*/ +#define GET_PHASE_COMMAND 0x03 /* Get Phase command*/ +#define RM_COMMAND 0x11 /* Read Memory command*/ +#define READ_PART_COMMAND 0x12 /* Read Partition command*/ +#define START_COMMAND 0x21 /* START command (Go)*/ +#define DOWNLOAD_COMMAND 0x31 /* Download command*/ +/* existing command for other STM32 but not used */ +/* ERASE 0x43 */ +/* EXTENDED_ERASE 0x44 */ +/* WRITE_UNPROTECTED 0x73 */ +/* READOUT_PROTECT 0x82 */ +/* READOUT_UNPROTECT 0x92 */ + +/* - miscellaneous defines ----------------------------------------*/ +#define INIT_BYTE 0x7F /*Init Byte ID*/ +#define ACK_BYTE 0x79 /*Acknowlede Byte ID*/ +#define NACK_BYTE 0x1F /*No Acknowlede Byte ID*/ +#define ABORT_BYTE 0x5F /*ABORT*/ + +/* - phase defines ------------------------------------------------*/ +#define PHASE_FLASHLAYOUT 0x00 +#define PHASE_FIRST_USER 0x10 +#define PHASE_LAST_USER 0xF0 +#define PHASE_CMD 0xF1 +#define PHASE_OTP 0xF2 +#define PHASE_SSP 0xF3 +#define PHASE_PMIC 0xF4 +#define PHASE_END 0xFE +#define PHASE_RESET 0xFF +#define PHASE_DO_RESET 0x1FF + +#define DEFAULT_ADDRESS 0xFFFFFFFF + +#define OTP_SIZE 1024 +#define PMIC_SIZE 8 + +enum stm32prog_link_t { + LINK_SERIAL, + LINK_USB, + LINK_UNDEFINED, +}; + +struct image_header_s { + bool present; + u32 image_checksum; + u32 image_length; +}; + +struct raw_header_s { + u32 magic_number; + u32 image_signature[64 / 4]; + u32 image_checksum; + u32 header_version; + u32 image_length; + u32 image_entry_point; + u32 reserved1; + u32 load_address; + u32 reserved2; + u32 version_number; + u32 option_flags; + u32 ecdsa_algorithm; + u32 ecdsa_public_key[64 / 4]; + u32 padding[83 / 4]; + u32 binary_type; +}; + +#define BL_HEADER_SIZE sizeof(struct raw_header_s) + +/* partition type in flashlayout file */ +enum stm32prog_part_type { + PART_BINARY, + PART_SYSTEM, + PART_FILESYSTEM, + RAW_IMAGE +}; + +/* device information */ +struct stm32prog_dev_t { + enum dfu_device_type dev_type; + char dev_id; + struct blk_desc *block_dev; + u32 lba_blk_size; /* for MMC RAW */ + u32 erase_size; + struct mtd_info *mtd; + /* list of partition for this device / ordered in offset */ + struct list_head part_list; +}; + +/* partition information build form FlashLayout and device */ +struct stm32prog_part_t { + /* FlashLayout inforamtion */ + int option; + int id; + enum stm32prog_part_type part_type; + enum dfu_device_type dev_type; + char dev_id; + /* partition name + * (16 char in gpt, + 1 for null terminated string + */ + char name[16 + 1]; + u64 addr; + u64 size; + enum stm32prog_part_type bin_nb; /* SSBL repeatition */ + + /* information on associated device */ + struct stm32prog_dev_t *dev; /* pointer to device */ + /* partition id in gpt when >0, -1 and -2 for boot partition of MMC */ + s16 part_id; + int alt_id; /* alt id in usb/dfu */ + + struct list_head list; +}; + +#define STM32PROG_MAX_DEV 5 +struct stm32prog_data { + /* Layout information */ + int dev_nb; /* device number*/ + struct stm32prog_dev_t dev[STM32PROG_MAX_DEV]; /* array of device */ + int part_nb; /* nb of partition */ + struct stm32prog_part_t *part_array; /* array of partition */ + int full_update; + + /* command internal information */ + int phase; + u32 offset; + char error[255]; + struct stm32prog_part_t *cur_part; + u32 *otp_part; + u8 pmic_part[PMIC_SIZE]; + + /* STM32 header information */ + struct raw_header_s *header_data; + struct image_header_s header; + + /* SERIAL information */ + u32 cursor; + u32 packet_number; + u32 checksum; + u8 *buffer; /* size = USART_RAM_BUFFER_SIZE*/ + int dfu_seq; + u8 read_phase; +}; + +/* OTP access */ +int stm32prog_otp_write(struct stm32prog_data *data, u32 offset, + u8 *buffer, long *size); +int stm32prog_otp_read(struct stm32prog_data *data, u32 offset, + u8 *buffer, long *size); +int stm32prog_otp_start(struct stm32prog_data *data); + +/* PMIC access */ +int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, + u8 *buffer, long *size); +int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, + u8 *buffer, long *size); +int stm32prog_pmic_start(struct stm32prog_data *data); + +/* generic part*/ +u8 stm32prog_header_check(struct raw_header_s *raw_header, + struct image_header_s *header); +int stm32prog_dfu_init(struct stm32prog_data *data); +void stm32prog_end_phase(struct stm32prog_data *data); +void stm32prog_next_phase(struct stm32prog_data *data); +void stm32prog_do_reset(struct stm32prog_data *data); + +int stm32prog_serial_init(struct stm32prog_data *data, int link_dev); + +char *stm32prog_get_error(struct stm32prog_data *data); + +#define stm32prog_err(args...) {\ + if (data->phase != PHASE_RESET) { \ + sprintf(data->error, args); \ + data->phase = PHASE_RESET; \ + pr_err("Error: %s\n", data->error); } \ + } + +/* Main function */ +struct stm32prog_data *stm32prog_init(enum stm32prog_link_t link, + int dev, ulong addr, ulong size); +bool stm32prog_serial_loop(struct stm32prog_data *data); +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev); +void stm32prog_clean(struct stm32prog_data *data); + +#endif diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c new file mode 100644 index 000000000000..36f9393d7610 --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -0,0 +1,972 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "stm32prog.h" + +struct udevice *down_serial_dev; + +const u8 cmd_id[] = { + GET_CMD_COMMAND, + GET_VER_COMMAND, + GET_ID_COMMAND, + GET_PHASE_COMMAND, + RM_COMMAND, + READ_PART_COMMAND, + START_COMMAND, + DOWNLOAD_COMMAND +}; + +#define NB_CMD sizeof(cmd_id) + +/* DFU support for serial *********************************************/ +struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) +{ + int alt_id; + + if (!data->cur_part) + if (data->phase == PHASE_FLASHLAYOUT) + alt_id = 0; + else + return NULL; + else + alt_id = data->cur_part->alt_id; + + return dfu_get_entity(alt_id); +} + +static int stm32prog_write(struct stm32prog_data *data, u8 *buffer, + u32 buffer_size) +{ + struct dfu_entity *dfu_entity; + u8 ret = 0; + + dfu_entity = stm32prog_get_entity(data); + if (!dfu_entity) + return -ENODEV; + + ret = dfu_write(dfu_entity, + buffer, + buffer_size, + data->dfu_seq); + + if (ret) { + stm32prog_err("DFU write failed [%d] cnt: %d", + ret, data->dfu_seq); + } + data->dfu_seq++; + /* handle rollover as in driver/dfu/dfu.c */ + data->dfu_seq &= 0xffff; + if (buffer_size == 0) + data->dfu_seq = 0; /* flush done */ + + return ret; +} + +static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset, + u8 *buffer, u32 buffer_size) +{ + struct dfu_entity *dfu_entity; + int ret; + + /* pr_debug("%s entry\n", __func__); */ + if (data->dfu_seq) { + stm32prog_err("DFU write pending for phase %d, seq %d", + data->phase, data->dfu_seq); + return -EINVAL; + } + if (phase == PHASE_FLASHLAYOUT || phase > PHASE_LAST_USER) { + stm32prog_err("read failed : phase %d is invalid", phase); + return -EINVAL; + } + if (data->read_phase <= PHASE_LAST_USER && + phase != data->read_phase) { + /* clear previous read session */ + dfu_entity = dfu_get_entity(data->read_phase - 1); + if (dfu_entity) + dfu_transaction_cleanup(dfu_entity); + } + dfu_entity = dfu_get_entity(phase - 1); + if (!dfu_entity) { + stm32prog_err("read failed : phase %d is unknown", phase); + return -ENODEV; + } + /* clear pending read before to force offset */ + if (dfu_entity->inited && + (data->read_phase != phase || data->offset != offset)) + dfu_transaction_cleanup(dfu_entity); + + /* initiate before to force offset */ + if (!dfu_entity->inited) { + ret = dfu_transaction_initiate(dfu_entity, true); + if (ret < 0) { + stm32prog_err("DFU read init failed [%d] phase = %d offset = 0x%08x", + ret, phase, offset); + return ret; + } + } + /* force new offset */ + if (dfu_entity->offset != offset) + dfu_entity->offset = offset; + data->offset = offset; + data->read_phase = phase; + pr_debug("\nSTM32 download read %s offset=0x%x\n", + dfu_entity->name, offset); + ret = dfu_read(dfu_entity, buffer, buffer_size, + dfu_entity->i_blk_seq_num); + if (ret < 0) { + stm32prog_err("DFU read failed [%d] phase = %d offset = 0x%08x", + ret, phase, offset); + return ret; + } + if (ret < buffer_size) { + data->offset = 0; + data->read_phase = PHASE_END; + memset(buffer + ret, 0, buffer_size - ret); + } else { + data->offset += ret; + } + /*pr_debug("%s exit ret=%d\n", __func__, ret);*/ + return ret; +} + +/* UART access ***************************************************/ +int stm32prog_serial_init(struct stm32prog_data *data, int link_dev) +{ + struct udevice *dev = NULL; + int node; + char alias[10]; + const char *path; + struct dm_serial_ops *ops; + /* no parity, 8 bits, 1 stop */ + u32 serial_config = SERIAL_DEFAULT_CONFIG; + + down_serial_dev = NULL; + + sprintf(alias, "serial%d", link_dev); + path = fdt_get_alias(gd->fdt_blob, alias); + if (!path) { + pr_err("%s alias not found", alias); + return -ENODEV; + } + node = fdt_path_offset(gd->fdt_blob, path); + if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, + &dev)) { + down_serial_dev = dev; + } else if (node > 0 && + !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), + &dev)) { + if (!device_probe(dev)) + down_serial_dev = dev; + } + /*pr_debug("alias=%s, path=%s, node = %d, dev=%0x\n", + * alias, path, node, (u32)down_serial_dev); + */ + if (!down_serial_dev) { + pr_err("%s = %s device not found", alias, path); + return -ENODEV; + } + + /* force silent console on uart only when used */ + if (gd->cur_serial_dev == down_serial_dev) + gd->flags |= GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT; + else + gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT); + + ops = serial_get_ops(down_serial_dev); + + if (!ops) { + pr_err("%s = %s missing ops", alias, path); + return -ENODEV; + } + if (!ops->setconfig) { + pr_err("%s = %s missing setconfig", alias, path); + return -ENODEV; + } + + clrsetbits_le32(&serial_config, SERIAL_PAR_MASK, SERIAL_PAR_EVEN); + + return ops->setconfig(down_serial_dev, serial_config); +} + +static void stm32prog_serial_flush(void) +{ + struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); + int err; + + do { + err = ops->getc(down_serial_dev); + } while (err != -EAGAIN); +} + +static int stm32prog_serial_getc_err(void) +{ + struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); + int err; + + do { + err = ops->getc(down_serial_dev); + if (err == -EAGAIN) + ctrlc(); + } while ((err == -EAGAIN) && (!had_ctrlc())); + + return err; +} + +static u8 stm32prog_serial_getc(void) +{ + int err; + + err = stm32prog_serial_getc_err(); + + return err >= 0 ? err : 0; +} + +static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count) +{ + struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); + int err; + + do { + err = ops->getc(down_serial_dev); + if (err >= 0) { + *buffer++ = err; + *count -= 1; + } else if (err == -EAGAIN) { + ctrlc(); + } else { + break; + } + } while (*count && !had_ctrlc()); + + return !!(err < 0); +} + +static void stm32prog_serial_putc(u8 w_byte) +{ + struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); + int err; + + do { + err = ops->putc(down_serial_dev, w_byte); + } while (err == -EAGAIN); +} + +/* Helper function ************************************************/ + +static u8 stm32prog_header(struct stm32prog_data *data) +{ + u8 ret; + u8 boot = 0; + struct dfu_entity *dfu_entity; + u64 size = 0; + + /*pr_debug("%s entry\n", __func__);*/ + + dfu_entity = stm32prog_get_entity(data); + if (!dfu_entity) + return -ENODEV; + + printf("\nSTM32 download write %s\n", dfu_entity->name); + + /* force cleanup to avoid issue with previous read */ + dfu_transaction_cleanup(dfu_entity); + + ret = stm32prog_header_check(data->header_data, + &data->header); + + /* no header : max size is partition size */ + if (ret) { + dfu_entity->get_medium_size(dfu_entity, &size); + data->header.image_length = size; + } + + /**** Flash the header if necessary for boot partition */ + if (data->phase < PHASE_FIRST_USER) + boot = 1; + + /* write header if boot partition */ + if (boot) { + if (ret) { + stm32prog_err("invalid header (error %d)", ret); + } else { + ret = stm32prog_write(data, + (u8 *)data->header_data, + BL_HEADER_SIZE); + } + } else { + if (ret) + printf(" partition without checksum\n"); + ret = 0; + } + + free(data->header_data); + data->header_data = NULL; + /*pr_debug("%s result=%d\n", __func__, ret);*/ + return ret; +} + +static u8 stm32prog_start(struct stm32prog_data *data, u32 address) +{ + u8 ret = 0; + struct dfu_entity *dfu_entity; + + /*pr_debug("%s entry\n", __func__);*/ + + if (address < 0x100) { + if (address == PHASE_OTP) + return stm32prog_otp_start(data); + + if (address == PHASE_PMIC) + return stm32prog_pmic_start(data); + + if (address == PHASE_RESET || address == PHASE_END) { + data->cur_part = NULL; + data->dfu_seq = 0; + data->phase = address; + return 0; + } + if (address != data->phase) { + stm32prog_err("invalid received phase id %d, current phase is %d", + (u8)address, (u8)data->phase); + return -EINVAL; + } + } + /* check the last loaded partition */ + if (address == DEFAULT_ADDRESS || address == data->phase) { + switch (data->phase) { + case PHASE_END: + case PHASE_RESET: + case PHASE_DO_RESET: + data->cur_part = NULL; + data->phase = PHASE_DO_RESET; + return 0; + } + dfu_entity = stm32prog_get_entity(data); + if (!dfu_entity) + return -ENODEV; + + if (data->dfu_seq) { + ret = dfu_flush(dfu_entity, NULL, 0, data->dfu_seq); + data->dfu_seq = 0; + if (ret) { + stm32prog_err("DFU flush failed [%d]", ret); + return ret; + } + } + printf("\n received length = 0x%x\n", data->cursor); + if (data->header.present) { + if (data->cursor != + (data->header.image_length + BL_HEADER_SIZE)) { + stm32prog_err("transmission interrupted (length=0x%x expected=0x%x)", + data->cursor, + data->header.image_length + + BL_HEADER_SIZE); + return -EIO; + } + if (data->header.image_checksum != data->checksum) { + stm32prog_err("invalid checksum received (0x%x expected 0x%x)", + data->checksum, + data->header.image_checksum); + return -EIO; + } + printf("\n checksum OK (0x%x)\n", data->checksum); + } + + stm32prog_end_phase(data); + /* update DFU with received flashlayout */ + if (data->phase == PHASE_FLASHLAYOUT) + stm32prog_dfu_init(data); + /* found next selected partition */ + stm32prog_next_phase(data); + } else { + void (*entry)(void) = (void *)address; + + printf("## Starting application at 0x%x ...\n", address); + (*entry)(); + printf("## Application terminated\n"); + ret = -ENOEXEC; + } + /*pr_debug("%s exit ret=%d, phase=0x%x, add=0x%x\n", __func__, + * ret, data->phase, address); + */ + return ret; +} + +/* + * Function Name : get_address + * Description : Get address if it is valid + * Input : None + * Output : None + * Return : The address area or Error_32 + */ +static u32 get_address(u8 *tmp_xor) +{ + u32 address = 0x0; + u8 data; + + data = stm32prog_serial_getc(); + *tmp_xor ^= data; + address |= ((u32)data) << 24; + + data = stm32prog_serial_getc(); + address |= ((u32)data) << 16; + *tmp_xor ^= data; + + data = stm32prog_serial_getc(); + address |= ((u32)data) << 8; + *tmp_xor ^= data; + + data = stm32prog_serial_getc(); + address |= ((u32)data); + *tmp_xor ^= data; + + return address; +} + +static void stm32prog_serial_result(u8 result) +{ + /* always flush fifo before to send result */ + stm32prog_serial_flush(); + stm32prog_serial_putc(result); +} + +/* Command -----------------------------------------------*/ +/* + * Function Name : get_cmd_command + * Description : Respond to Get command + * Input : None + * Output : None + * Return : None + */ +static void get_cmd_command(struct stm32prog_data *data) +{ + u32 counter = 0x0; + + stm32prog_serial_putc(NB_CMD); + stm32prog_serial_putc(USART_BL_VERSION); + + for (counter = 0; counter < NB_CMD; counter++) + stm32prog_serial_putc(cmd_id[counter]); + + stm32prog_serial_result(ACK_BYTE); +} + +/* + * Function Name : get_version_command + * Description : Respond to Get Version command + * Input : None + * Output : None + * Return : None + */ +static void get_version_command(struct stm32prog_data *data) +{ + stm32prog_serial_putc(UBOOT_BL_VERSION); + stm32prog_serial_result(ACK_BYTE); +} + +/* + * Function Name : get_id_command + * Description : Respond to Get ID command + * Input : None + * Output : None + * Return : None + */ +static void get_id_command(struct stm32prog_data *data) +{ + /* Send Device IDCode */ + stm32prog_serial_putc(0x1); + stm32prog_serial_putc(DEVICE_ID_BYTE1); + stm32prog_serial_putc(DEVICE_ID_BYTE2); + stm32prog_serial_result(ACK_BYTE); +} + +/* + * Function Name : get_phase_command + * Description : Respond to Get phase + * Input : None + * Output : None + * Return : None + */ +static void get_phase_command(struct stm32prog_data *data) +{ + char *err_msg = NULL; + u8 i, length = 0; + u32 destination = DEFAULT_ADDRESS; /* destination address */ + int phase = data->phase; + + if (phase == PHASE_RESET || phase == PHASE_DO_RESET) { + err_msg = stm32prog_get_error(data); + length = strlen(err_msg); + } + if (phase == PHASE_FLASHLAYOUT) + destination = STM32_DDR_BASE; + + stm32prog_serial_putc(length + 5); /* Total length */ + stm32prog_serial_putc(phase & 0xFF); /* partition ID */ + stm32prog_serial_putc(destination); /* byte 1 of address */ + stm32prog_serial_putc(destination >> 8); /* byte 2 of address */ + stm32prog_serial_putc(destination >> 16); /* byte 3 of address */ + stm32prog_serial_putc(destination >> 24); /* byte 4 of address */ + + stm32prog_serial_putc(length); /* Information length */ + for (i = 0; i < length; i++) + stm32prog_serial_putc(err_msg[i]); + stm32prog_serial_result(ACK_BYTE); + + if (phase == PHASE_RESET) + stm32prog_do_reset(data); +} + +/* + * Function Name : read_memory_command + * Description : Read data from memory + * Input : None + * Output : None + * Return : None + */ +static void read_memory_command(struct stm32prog_data *data) +{ + u32 address = 0x0; + u8 rcv_data = 0x0, tmp_xor = 0x0; + u32 counter = 0x0; + + /* Read memory address */ + address = get_address(&tmp_xor); + + /* If address memory is not received correctly */ + rcv_data = stm32prog_serial_getc(); + if (rcv_data != tmp_xor) { + stm32prog_serial_result(NACK_BYTE); + return; + } + + stm32prog_serial_result(ACK_BYTE); + + /* Read the number of bytes to be received: + * Max NbrOfData = Data + 1 = 256 + */ + rcv_data = stm32prog_serial_getc(); + tmp_xor = ~rcv_data; + if (stm32prog_serial_getc() != tmp_xor) { + stm32prog_serial_result(NACK_BYTE); + return; + } + + /* If checksum is correct send ACK */ + stm32prog_serial_result(ACK_BYTE); + + /* Send data to the host: + * Number of data to read = data + 1 + */ + for (counter = (rcv_data + 1); counter != 0; counter--) + stm32prog_serial_putc(*(u8 *)(address++)); +} + +/* + * Function Name : start_command + * Description : Jump to user application in RAM or partition check + * Input : None + * Output : None + * Return : None + */ +static void start_command(struct stm32prog_data *data) +{ + u32 address = 0; + u8 tmp_xor = 0x0; + u8 ret, rcv_data; + + /* Read memory address */ + address = get_address(&tmp_xor); + + /* If address memory is not received correctly */ + rcv_data = stm32prog_serial_getc(); + if (rcv_data != tmp_xor) { + stm32prog_serial_result(NACK_BYTE); + return; + } + /* validate partition */ + ret = stm32prog_start(data, + address); + + if (ret) + stm32prog_serial_result(ABORT_BYTE); + else + stm32prog_serial_result(ACK_BYTE); +} + +/* + * Function Name : download_command + * Description : Write data to Flash + * Input : None + * Output : None + * Return : Result + */ +static void download_command(struct stm32prog_data *data) +{ + u32 address = 0x0; + u8 my_xor = 0x0; + u8 rcv_xor; + u32 counter = 0x0, codesize = 0x0; + u8 *ramaddress = 0; + u8 rcv_data = 0x0; + struct image_header_s *image_header = &data->header; + u32 cursor = data->cursor; + long size = 0; + u8 operation; + u32 packet_number; + u32 result = ACK_BYTE; + u8 ret; + int i; + bool error; + int rcv; + + address = get_address(&my_xor); + + /* If address memory is not received correctly */ + rcv_xor = stm32prog_serial_getc(); + if (rcv_xor != my_xor) { + result = NACK_BYTE; + goto end; + } + + /* If address valid send ACK */ + stm32prog_serial_result(ACK_BYTE); + + /* get packet number and operation type */ + operation = (u8)((u32)address >> 24); + packet_number = ((u32)(((u32)address << 8))) >> 8; + + switch (operation) { + /* supported operation */ + case PHASE_FLASHLAYOUT: + case PHASE_OTP: + case PHASE_PMIC: + break; + default: + result = NACK_BYTE; + goto end; + } + /* check the packet number */ + if (packet_number == 0) { + /* erase: re-initialize the image_header struct */ + data->packet_number = 0; + if (data->header_data) + memset(data->header_data, 0, BL_HEADER_SIZE); + else + data->header_data = calloc(1, BL_HEADER_SIZE); + cursor = 0; + data->cursor = 0; + data->checksum = 0; + /*idx = cursor;*/ + } else { + data->packet_number++; + } + + /* Check with the number of current packet if the device receive + * the true packet + */ + if (packet_number != data->packet_number) { + data->packet_number--; + result = NACK_BYTE; + goto end; + } + + /*-- Read number of bytes to be written and data -----------*/ + + /* Read the number of bytes to be written: + * Max NbrOfData = data + 1 <= 256 + */ + rcv_data = stm32prog_serial_getc(); + + /* NbrOfData to write = data + 1 */ + codesize = rcv_data + 0x01; + + if (codesize > USART_RAM_BUFFER_SIZE) { + result = NACK_BYTE; + goto end; + } + + /* Checksum Initialization */ + my_xor = rcv_data; + + /* UART receive data and send to Buffer */ + counter = codesize; + error = stm32prog_serial_get_buffer(data->buffer, &counter); + + /* read checksum */ + if (!error) { + rcv = stm32prog_serial_getc_err(); + error = !!(rcv < 0); + rcv_xor = rcv; + } + + if (error) { + printf("transmission error on packet %d, byte %d\n", + packet_number, codesize - counter); + /* waiting end of packet before flush & NACK */ + mdelay(30); + data->packet_number--; + result = NACK_BYTE; + goto end; + } + + /* Compute Checksum */ + ramaddress = data->buffer; + for (counter = codesize; counter != 0; counter--) + my_xor ^= *(ramaddress++); + + /* If Checksum is incorrect */ + if (rcv_xor != my_xor) { + printf("checksum error on packet %d\n", + packet_number); + data->packet_number--; + result = NACK_BYTE; + goto end; + } + + /* Update current position in buffer */ + data->cursor += codesize; + + if (operation == PHASE_OTP) { + size = data->cursor - cursor; + /* no header for OTP */ + if (stm32prog_otp_write(data, cursor, + data->buffer, &size)) + result = ABORT_BYTE; + goto end; + } + + if (operation == PHASE_PMIC) { + size = data->cursor - cursor; + /* no header for PMIC */ + if (stm32prog_pmic_write(data, cursor, + data->buffer, &size)) + result = ABORT_BYTE; + goto end; + } + + if (cursor < BL_HEADER_SIZE) { + /* size = portion of header in this chunck */ + if (data->cursor >= BL_HEADER_SIZE) + size = BL_HEADER_SIZE - cursor; + else + size = data->cursor - cursor; + memcpy((void *)((u32)(data->header_data) + cursor), + data->buffer, size); + cursor += size; + + if (cursor == BL_HEADER_SIZE) { + /* Check and Write the header */ + if (stm32prog_header(data)) { + result = ABORT_BYTE; + goto end; + } + } else { + goto end; + } + } + /* + * pr_debug("packet_number = 0x%x\n", packet_number); + * pr_debug("cursor = 0x%x\n", data->cursor); + * pr_debug("image_length = 0x%x\n", image_header->image_length); + * pr_debug("codesize = 0x%x\n", codesize); + */ + if (image_header->present) { + if (data->cursor <= BL_HEADER_SIZE) + goto end; + /* compute checksum on payload */ + for (i = size; i < codesize; i++) + data->checksum += data->buffer[i]; + + if (data->cursor > + image_header->image_length + BL_HEADER_SIZE) { + pr_err("expected size exceeded\n"); + result = ABORT_BYTE; + goto end; + } + + /* write data (payload) */ + ret = stm32prog_write(data, + &data->buffer[size], + codesize - size); + } else { + /* write all */ + ret = stm32prog_write(data, + data->buffer, + codesize); + } + if (ret) + result = ABORT_BYTE; + +end: + /*pr_debug("%s : result = 0x%x\n", __func__, result);*/ + stm32prog_serial_result(result); +} + +/* + * Function Name : read_partition + * Description : read data from Flash + * Input : None + * Output : None + * Return : Result + */ +static void read_partition_command(struct stm32prog_data *data) +{ + u32 part_id, codesize, offset = 0, rcv_data; + long size; + u8 tmp_xor; + int i, res; + u8 buffer[256]; + + part_id = stm32prog_serial_getc(); + tmp_xor = part_id; + + offset = get_address(&tmp_xor); + + rcv_data = stm32prog_serial_getc(); + if (rcv_data != tmp_xor) { + pr_debug("1st checksum received = %x, computed %x\n", + rcv_data, tmp_xor); + goto error; + } + stm32prog_serial_putc(ACK_BYTE); + + /* NbrOfData to read = data + 1 */ + rcv_data = stm32prog_serial_getc(); + codesize = rcv_data + 0x01; + tmp_xor = rcv_data; + + rcv_data = stm32prog_serial_getc(); + if ((rcv_data ^ tmp_xor) != 0xFF) { + pr_debug("2nd checksum received = %x, computed %x\n", + rcv_data, tmp_xor); + goto error; + } + + pr_debug("%s : %x\n", __func__, part_id); + switch (part_id) { + case PHASE_OTP: + res = 0; + size = codesize; + if (!stm32prog_otp_read(data, offset, buffer, &size)) + res = size; + break; + case PHASE_PMIC: + res = 0; + size = codesize; + if (!stm32prog_pmic_read(data, offset, buffer, &size)) + res = size; + break; + default: + res = stm32prog_read(data, part_id, offset, + buffer, codesize); + break; + } + if (res > 0) { + stm32prog_serial_putc(ACK_BYTE); + /*----------- Send data to the host -----------*/ + for (i = 0; i < res; i++) + stm32prog_serial_putc(buffer[i]); + /*----------- Send filler to the host -----------*/ + for (; i < codesize; i++) + stm32prog_serial_putc(0x0); + return; + } + stm32prog_serial_result(ABORT_BYTE); + return; + +error: + stm32prog_serial_result(NACK_BYTE); +} + +/** SERIAL LOOP ****************************************************/ + +/* + * Function Name : stm32prog_serial_loop + * Description : USART bootloader Loop routine + * Input : data + * Output : None + * Return : None + */ +bool stm32prog_serial_loop(struct stm32prog_data *data) +{ + u32 counter = 0x0; + u8 command = 0x0; + u8 found; + int phase = data->phase; + + /* element of cmd_func need to aligned with cmd_id[]*/ + void (*cmd_func[NB_CMD])(struct stm32prog_data *) = { + /* GET_CMD_COMMAND */ get_cmd_command, + /* GET_VER_COMMAND */ get_version_command, + /* GET_ID_COMMAND */ get_id_command, + /* GET_PHASE_COMMAND */ get_phase_command, + /* RM_COMMAND */ read_memory_command, + /* READ_PART_COMMAND */ read_partition_command, + /* START_COMMAND */ start_command, + /* DOWNLOAD_COMMAND */ download_command + }; + + /* flush and NACK pending command received during u-boot init + * request command reemit + */ + stm32prog_serial_result(NACK_BYTE); + + clear_ctrlc(); /* forget any previous Control C */ + while (!had_ctrlc()) { + phase = data->phase; + + if (phase == PHASE_DO_RESET) + return true; + + /* Get the user command: read first byte */ + command = stm32prog_serial_getc(); + + if (command == INIT_BYTE) { + puts("\nConnected\n"); + stm32prog_serial_result(ACK_BYTE); + continue; + } + + found = 0; + for (counter = 0; counter < NB_CMD; counter++) + if (cmd_id[counter] == command) { + found = 1; + break; + } + if (found) + if ((command ^ stm32prog_serial_getc()) != 0xFF) + found = 0; + if (!found) { + /* wait to be sure that all data are received + * in the FIFO before flush (CMD and XOR) + */ + mdelay(2); + stm32prog_serial_result(NACK_BYTE); + } else { + /*pr_debug("+ cmd %x\n", counter);*/ + stm32prog_serial_result(ACK_BYTE); + cmd_func[counter](data); + } + WATCHDOG_RESET(); + } + + /* clean device */ + if (gd->cur_serial_dev == down_serial_dev) { + /* restore console on uart */ + gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT); + } + down_serial_dev = NULL; + + return false; /* no reset after ctrlc */ +} diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c new file mode 100644 index 000000000000..c7dd678c669b --- /dev/null +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include "stm32prog.h" + +struct stm32prog_data *stm32prog_data; + +static int stm32prog_get_alternate(struct stm32prog_data *data) +{ + if (data->cur_part) + return data->cur_part->alt_id; + else + return -EINVAL; +} + +static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase, + u32 offset) +{ + struct stm32prog_part_t *part; + int i; + + if (phase == data->phase) { + data->offset = offset; + data->dfu_seq = 0; + return 0; + } + + /* found partition */ + for (i = 0; i < data->part_nb; i++) { + part = &data->part_array[i]; + if (part->id == phase) { + data->cur_part = part; + data->phase = phase; + data->offset = offset; + data->dfu_seq = 0; + return 0; + } + } + + return -EINVAL; +} + +static int stm32prog_cmd_write(u64 offset, void *buf, long *len) +{ + u8 phase; + u32 address; + u8 *pt = buf; + void (*entry)(void); + int ret; + + if (*len < 5) { + pr_err("size not allowed\n"); + return -EINVAL; + } + if (offset) { + pr_err("invalid offset\n"); + return -EINVAL; + } + phase = pt[0]; + address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4]; + if (phase == PHASE_RESET) { + entry = (void *)address; + printf("## Starting application at 0x%x ...\n", address); + (*entry)(); + printf("## Application terminated\n"); + return 0; + } + /* set phase and offset */ + ret = stm32prog_set_phase(stm32prog_data, phase, address); + if (ret) + pr_err("failed: %d\n", ret); + return ret; +} + +#define PHASE_MIN_SIZE 9 +static int stm32prog_cmd_read(u64 offset, void *buf, long *len) +{ + u32 destination = DEFAULT_ADDRESS; /* destination address */ + u32 dfu_offset; + u8 *pt_buf = buf; + int phase; + char *err_msg; + int length; + + if (*len < PHASE_MIN_SIZE) { + pr_err("request exceeds allowed area\n"); + return -EINVAL; + } + if (offset) { + *len = 0; /* EOF for second request */ + return 0; + } + phase = stm32prog_data->phase; + if (phase == PHASE_FLASHLAYOUT) + destination = STM32_DDR_BASE; + dfu_offset = stm32prog_data->offset; + + /* mandatory header, size = PHASE_MIN_SIZE */ + *pt_buf++ = (u8)(phase & 0xFF); + *pt_buf++ = (u8)(destination); + *pt_buf++ = (u8)(destination >> 8); + *pt_buf++ = (u8)(destination >> 16); + *pt_buf++ = (u8)(destination >> 24); + *pt_buf++ = (u8)(dfu_offset); + *pt_buf++ = (u8)(dfu_offset >> 8); + *pt_buf++ = (u8)(dfu_offset >> 16); + *pt_buf++ = (u8)(dfu_offset >> 24); + + if (phase == PHASE_RESET || phase == PHASE_DO_RESET) { + err_msg = stm32prog_get_error(stm32prog_data); + length = strlen(err_msg); + if (length + PHASE_MIN_SIZE > *len) + length = *len - PHASE_MIN_SIZE; + + memcpy(pt_buf, err_msg, length); + *len = PHASE_MIN_SIZE + length; + stm32prog_do_reset(stm32prog_data); + } else if (phase == PHASE_FLASHLAYOUT) { + *pt_buf++ = stm32prog_data->part_nb ? 1 : 0; + *len = PHASE_MIN_SIZE + 1; + } else { + *len = PHASE_MIN_SIZE; + } + + return 0; +} + +/* DFU access to virtual partition */ + +void dfu_flush_callback(struct dfu_entity *dfu) +{ + if (!stm32prog_data) + return; + + if (dfu->dev_type == DFU_DEV_VIRT) { + if (dfu->data.virt.dev_num == PHASE_OTP) + stm32prog_otp_start(stm32prog_data); + else if (dfu->data.virt.dev_num == PHASE_PMIC) + stm32prog_pmic_start(stm32prog_data); + return; + } + + if (dfu->dev_type == DFU_DEV_RAM) { + if (dfu->alt == 0 && + stm32prog_data->phase == PHASE_FLASHLAYOUT) { + stm32prog_end_phase(stm32prog_data); + /* waiting DFU DETACH for reenumeration */ + } + return; + } + + if (dfu->alt == stm32prog_get_alternate(stm32prog_data)) { + stm32prog_end_phase(stm32prog_data); + stm32prog_next_phase(stm32prog_data); + } +} + +void dfu_initiated_callback(struct dfu_entity *dfu) +{ + int phase; + + if (!stm32prog_data) + return; + + phase = stm32prog_data->phase; + if (dfu->alt == stm32prog_get_alternate(stm32prog_data)) { + dfu->offset = stm32prog_data->offset; + stm32prog_set_phase(stm32prog_data, phase, 0); + pr_debug("dfu offset = 0x%llx\n", dfu->offset); + } +} + +int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len) +{ + if (dfu->dev_type != DFU_DEV_VIRT) + return -EINVAL; + + switch (dfu->data.virt.dev_num) { + case PHASE_CMD: + return stm32prog_cmd_write(offset, buf, len); + + case PHASE_OTP: + return stm32prog_otp_write(stm32prog_data, (u32)offset, + buf, len); + + case PHASE_PMIC: + return stm32prog_pmic_write(stm32prog_data, (u32)offset, + buf, len); + } + *len = 0; + return 0; +} + +int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len) +{ + if (dfu->dev_type != DFU_DEV_VIRT) + return -EINVAL; + + switch (dfu->data.virt.dev_num) { + case PHASE_CMD: + return stm32prog_cmd_read(offset, buf, len); + + case PHASE_OTP: + return stm32prog_otp_read(stm32prog_data, (u32)offset, + buf, len); + + case PHASE_PMIC: + return stm32prog_pmic_read(stm32prog_data, (u32)offset, + buf, len); + } + *len = 0; + return 0; +} + +int dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) +{ + if (dfu->dev_type != DFU_DEV_VIRT) { + *size = 0; + pr_debug("%s, invalid dev_type = %d\n", + __func__, dfu->dev_type); + return -EINVAL; + } + + switch (dfu->data.virt.dev_num) { + case PHASE_CMD: + *size = 512; + break; + case PHASE_OTP: + *size = OTP_SIZE; + break; + case PHASE_PMIC: + *size = PMIC_SIZE; + break; + } + + return 0; +} + +/* USB download gadget for STM32 Programmer */ + +static const char product[] = + "USB download gadget@Device ID /0x500, @Revision ID /0x0000"; + +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) +{ + int ret; + + stm32prog_data = data; + g_dnl_set_product(product); + if (stm32prog_data->phase == PHASE_FLASHLAYOUT) { + ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu"); + if (ret || stm32prog_data->phase == PHASE_DO_RESET) + return ret; + /* prepare the second enumeration with the FlashLayout */ + if (stm32prog_data->phase == PHASE_FLASHLAYOUT) + stm32prog_dfu_init(data); + /* found next selected partition */ + stm32prog_next_phase(data); + } + return (run_usb_dnl_gadget(dev, "usb_dnl_dfu") || + (stm32prog_data->phase == PHASE_DO_RESET)); +} + +int g_dnl_get_board_bcd_device_number(int gcnum) +{ + pr_debug("%s\n", __func__); + return 0x200; +} diff --git a/arch/arm/mach-stm32mp/config.mk b/arch/arm/mach-stm32mp/config.mk index cde5850e9343..bd8944a6c798 100644 --- a/arch/arm/mach-stm32mp/config.mk +++ b/arch/arm/mach-stm32mp/config.mk @@ -3,7 +3,21 @@ # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # -ALL-$(CONFIG_SPL_BUILD) += spl/u-boot-spl.stm32 +ifndef CONFIG_SPL +ALL-y += u-boot.stm32 +else +ifdef CONFIG_SPL_BUILD +ALL-y += spl/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 0e01f8e61385..5d5ce4a50107 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -6,18 +6,23 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include +#include /* RCC register */ #define RCC_TZCR (STM32_RCC_BASE + 0x00) #define RCC_DBGCFGR (STM32_RCC_BASE + 0x080C) #define RCC_BDCR (STM32_RCC_BASE + 0x0140) #define RCC_MP_APB5ENSETR (STM32_RCC_BASE + 0x0208) + #define RCC_BDCR_VSWRST BIT(31) #define RCC_BDCR_RTCSRC GENMASK(17, 16) #define RCC_DBGCFGR_DBGCKEN BIT(8) @@ -55,10 +60,34 @@ #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 + +DECLARE_GLOBAL_DATA_PTR; + #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 +143,7 @@ static void security_init(void) */ writel(0x0, TAMP_CR1); } +#endif /* CONFIG_STM32MP1_TRUSTED */ /* * Debug init @@ -130,10 +160,12 @@ 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; + /* read bootrom context */ bootrom_device = (bootrom_itf & BOOTROM_MODE_MASK) >> BOOTROM_MODE_SHIFT; bootrom_instance = @@ -167,8 +199,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 */ @@ -176,7 +209,8 @@ 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) && \ +#if defined(CONFIG_DEBUG_UART) &&\ + !defined(CONFIG_STM32MP1_TRUSTED) && \ (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) else debug_uart_init(); @@ -203,25 +237,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"; @@ -234,7 +337,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; } @@ -242,20 +345,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; + 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); - + 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: - 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"); @@ -268,17 +399,44 @@ static void setup_boot_mode(void) env_set("boot_instance", cmd); break; case BOOT_FLASH_NAND: + sprintf(cmd, "%d", instance); env_set("boot_device", "nand"); - env_set("boot_instance", "0"); + env_set("boot_instance", cmd); break; case BOOT_FLASH_NOR: env_set("boot_device", "nor"); env_set("boot_instance", "0"); break; + } + + switch (forced_mode) { + case BOOT_FASTBOOT: + printf("Enter fastboot!\n"); + env_set("preboot", "env set preboot; fastboot 0"); + break; + case BOOT_STM32PROG: + printf("Enter STM32CubeProgrammer mode!\n"); + env_set("preboot", "env set preboot; stm32prog usb 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: default: pr_debug("unexpected boot mode = %x\n", boot_mode); break; } + + /* clear TAMP for next reboot */ + clrsetbits_le32(TAMP_BOOT_CONTEXT, TAMP_BOOT_FORCED_MASK, BOOT_NORMAL); } /* @@ -304,7 +462,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) return ret; @@ -342,12 +500,12 @@ 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) 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; @@ -361,3 +519,45 @@ int arch_misc_init(void) return 0; } + +/* + * This function is called right before the kernel is booted. "blob" is the + * device tree that will be passed to the kernel. + */ +int ft_system_setup(void *blob, bd_t *bd) +{ + int ret = 0; + u32 pkg; + +#if CONFIG_STM32_ETZPC + ret = stm32_fdt_fixup_etzpc(blob); + if (ret) + return ret; +#endif + + switch (get_cpu_package()) { + case PKG_AA_LBGA448: + pkg = STM32MP157CAA; + break; + case PKG_AB_LBGA354: + pkg = STM32MP157CAB; + break; + case PKG_AC_TFBGA361: + pkg = STM32MP157CAC; + break; + case PKG_AD_TFBGA257: + pkg = STM32MP157CAD; + break; + default: + pkg = 0; + break; + } + if (pkg) { + do_fixup_by_compat_u32(blob, "st,stm32mp157-pinctrl", + "st,package", pkg, false); + do_fixup_by_compat_u32(blob, "st,stm32mp157-z-pinctrl", + "st,package", pkg, false); + } + + return ret; +} diff --git a/arch/arm/mach-stm32mp/include/mach/ddr.h b/arch/arm/mach-stm32mp/include/mach/ddr.h index 18575842ba9a..b8a17cfbddb8 100644 --- a/arch/arm/mach-stm32mp/include/mach/ddr.h +++ b/arch/arm/mach-stm32mp/include/mach/ddr.h @@ -6,6 +6,13 @@ #ifndef __MACH_STM32MP_DDR_H_ #define __MACH_STM32MP_DDR_H_ -int board_ddr_power_init(void); +/* DDR power initializations */ +enum ddr_type { + STM32MP_DDR3, + STM32MP_LPDDR2, + STM32MP_LPDDR3, +}; + +int board_ddr_power_init(enum ddr_type ddr_type); #endif diff --git a/arch/arm/mach-stm32mp/include/mach/gpio.h b/arch/arm/mach-stm32mp/include/mach/gpio.h index 5151150b8d88..5ca76d21ff1e 100644 --- a/arch/arm/mach-stm32mp/include/mach/gpio.h +++ b/arch/arm/mach-stm32mp/include/mach/gpio.h @@ -8,6 +8,8 @@ #define _STM32_GPIO_H_ #include +#define STM32_GPIOS_PER_BANK 16 + enum stm32_gpio_port { STM32_GPIO_PORT_A = 0, STM32_GPIO_PORT_B, @@ -110,5 +112,9 @@ struct stm32_gpio_regs { struct stm32_gpio_priv { struct stm32_gpio_regs *regs; + unsigned int gpio_range; }; + +int stm32_offset_to_index(struct udevice *dev, unsigned int offset); + #endif /* _STM32_GPIO_H_ */ diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 5d0bdca1787d..41478733d7e9 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -13,13 +13,10 @@ #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 -#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,20 +25,27 @@ #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 +#define STM32_MCU_SRAM_BASE 0x30000000 +#define STM32_MCU_SRAM_SIZE (3 * SZ_128K) + #define STM32_DDR_BASE 0xC0000000 #define STM32_DDR_SIZE SZ_1G #ifndef __ASSEMBLY__ +#include + /* enumerated used to identify the SYSCON driver instance */ enum { STM32MP_SYSCON_UNKNOWN, - STM32MP_SYSCON_STGEN, + STM32MP_SYSCON_ETZPC, + STM32MP_SYSCON_IWDG, STM32MP_SYSCON_PWR, + STM32MP_SYSCON_STGEN, + STM32MP_SYSCON_SYSCFG, }; /* @@ -87,18 +91,41 @@ enum boot_device { /* TAMP registers */ #define TAMP_BACKUP_REGISTER(x) (STM32_TAMP_BASE + 0x100 + 4 * x) +/* secure access */ #define TAMP_BACKUP_MAGIC_NUMBER TAMP_BACKUP_REGISTER(4) #define TAMP_BACKUP_BRANCH_ADDRESS TAMP_BACKUP_REGISTER(5) +/* non secure access */ #define TAMP_BOOT_CONTEXT TAMP_BACKUP_REGISTER(20) +#define TAMP_BOOTCOUNT TAMP_BACKUP_REGISTER(21) #define TAMP_BOOT_MODE_MASK GENMASK(15, 8) #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) +#define TAMP_BOOT_DEBUG_ON BIT(16) + +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 +#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 + +#if CONFIG_STM32_ETZPC +int stm32_fdt_fixup_etzpc(void *fdt); +#endif #endif /* __ASSEMBLY__*/ #endif /* _MACH_STM32_H_ */ 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 000000000000..538958f6864d --- /dev/null +++ b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, 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 +/* SMC reserved for future ST services */ +#define STM32_SMC_RESERVED_ST 0x82000001 + +/* Secure Service access from Non-secure */ +#define STM32_SMC_RCC 0x82001000 +#define STM32_SMC_PWR 0x82001001 +#define STM32_SMC_RTC 0x82001002 +#define STM32_SMC_BSEC 0x82001003 + +/* Register access service use for RCC/RTC/PWR */ +#define STM32_SMC_REG_WRITE 0x1 +#define STM32_SMC_REG_SET 0x2 +#define STM32_SMC_REG_CLEAR 0x3 + +/* 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__ */ diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 41d4b40bcb4f..c5657489fc99 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 diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 6ed2482080c1..c2dff38c368c 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; } diff --git a/arch/arm/mach-stm32mp/pwr_regulator.c b/arch/arm/mach-stm32mp/pwr_regulator.c index 9484645dbdd5..dbfbdcc521f0 100644 --- a/arch/arm/mach-stm32mp/pwr_regulator.c +++ b/arch/arm/mach-stm32mp/pwr_regulator.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -32,13 +33,20 @@ struct stm32mp_pwr_priv { static int stm32mp_pwr_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { +#ifndef CONFIG_STM32MP1_TRUSTED struct stm32mp_pwr_priv *priv = dev_get_priv(dev); +#endif u32 val = *(u32 *)buff; if (len != 4) return -EINVAL; +#ifdef CONFIG_STM32MP1_TRUSTED + return stm32_smc_exec(STM32_SMC_PWR, STM32_SMC_REG_WRITE, + STM32MP_PWR_CR3, val); +#else /* CONFIG_STM32MP1_TRUSTED */ return regmap_write(priv->regmap, STM32MP_PWR_CR3, val); +#endif /* CONFIG_STM32MP1_TRUSTED */ } static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff, diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 790973e8b6e9..fa393ccbfa17 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -7,6 +7,18 @@ #include #include #include +#include +#include + +static int spl_board_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + /* TODO : add download support in SPL without TF-A */ + return -1; +} + +SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_board_load_image); +SPL_LOAD_IMAGE_METHOD("USB", 0, BOOT_DEVICE_USB, spl_board_load_image); u32 spl_boot_device(void) { @@ -22,8 +34,22 @@ 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; } @@ -44,6 +70,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; @@ -80,7 +121,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(); } } diff --git a/arch/arm/mach-stm32mp/stm32-etzpc.c b/arch/arm/mach-stm32mp/stm32-etzpc.c new file mode 100644 index 000000000000..ea6dcca52fdd --- /dev/null +++ b/arch/arm/mach-stm32mp/stm32-etzpc.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +#define ETZPC_DECPROT(n) (0x10 + 4 * (n)) +#define ETZPC_DECPROT_NB 6 + +#define ETZPC_IP_VER 0x3F4 + +#define IP_VER_STM32MP1 0x00000020 + +#define DECPROT_MASK 0x03 +#define NB_PROT_PER_REG 0x10 +#define DECPROT_NB_BITS 2 + +#define DECPROT_SECURED 0x00 +#define DECPROT_WRITE_SECURE 0x01 +#define DECPROT_MCU_ISOLATION 0x02 +#define DECPROT_NON_SECURED 0x03 + +#define ETZPC_RESERVED 0xffffffff + +static const u32 stm32mp1_ip_addr[] = { + 0x5c008000, /* 00 stgenc */ + 0x54000000, /* 01 bkpsram */ + 0x5c003000, /* 02 iwdg1 */ + 0x5c000000, /* 03 usart1 */ + 0x5c001000, /* 04 spi6 */ + 0x5c002000, /* 05 i2c4 */ + ETZPC_RESERVED, /* 06 reserved */ + 0x54003000, /* 07 rng1 */ + 0x54002000, /* 08 hash1 */ + 0x54001000, /* 09 cryp1 */ + 0x5a003000, /* 0A ddrctrl */ + 0x5a004000, /* 0B ddrphyc */ + 0x5c009000, /* 0C i2c6 */ + ETZPC_RESERVED, /* 0D reserved */ + ETZPC_RESERVED, /* 0E reserved */ + ETZPC_RESERVED, /* 0F reserved */ + 0x40000000, /* 10 tim2 */ + 0x40001000, /* 11 tim3 */ + 0x40002000, /* 12 tim4 */ + 0x40003000, /* 13 tim5 */ + 0x40004000, /* 14 tim6 */ + 0x40005000, /* 15 tim7 */ + 0x40006000, /* 16 tim12 */ + 0x40007000, /* 17 tim13 */ + 0x40008000, /* 18 tim14 */ + 0x40009000, /* 19 lptim1 */ + 0x4000a000, /* 1A wwdg1 */ + 0x4000b000, /* 1B spi2 */ + 0x4000c000, /* 1C spi3 */ + 0x4000d000, /* 1D spdifrx */ + 0x4000e000, /* 1E usart2 */ + 0x4000f000, /* 1F usart3 */ + 0x40010000, /* 20 uart4 */ + 0x40011000, /* 21 uart5 */ + 0x40012000, /* 22 i2c1 */ + 0x40013000, /* 23 i2c2 */ + 0x40014000, /* 24 i2c3 */ + 0x40015000, /* 25 i2c5 */ + 0x40016000, /* 26 cec */ + 0x40017000, /* 27 dac */ + 0x40018000, /* 28 uart7 */ + 0x40019000, /* 29 uart8 */ + ETZPC_RESERVED, /* 2A reserved */ + ETZPC_RESERVED, /* 2B reserved */ + 0x4001c000, /* 2C mdios */ + ETZPC_RESERVED, /* 2D reserved */ + ETZPC_RESERVED, /* 2E reserved */ + ETZPC_RESERVED, /* 2F reserved */ + 0x44000000, /* 30 tim1 */ + 0x44001000, /* 31 tim8 */ + ETZPC_RESERVED, /* 32 reserved */ + 0x44003000, /* 33 usart6 */ + 0x44004000, /* 34 spi1 */ + 0x44005000, /* 35 spi4 */ + 0x44006000, /* 36 tim15 */ + 0x44007000, /* 37 tim16 */ + 0x44008000, /* 38 tim17 */ + 0x44009000, /* 39 spi5 */ + 0x4400a000, /* 3A sai1 */ + 0x4400b000, /* 3B sai2 */ + 0x4400c000, /* 3C sai3 */ + 0x4400d000, /* 3D dfsdm */ + 0x4400e000, /* 3E tt_fdcan */ + ETZPC_RESERVED, /* 3F reserved */ + 0x50021000, /* 40 lptim2 */ + 0x50022000, /* 41 lptim3 */ + 0x50023000, /* 42 lptim4 */ + 0x50024000, /* 43 lptim5 */ + 0x50027000, /* 44 sai4 */ + 0x50025000, /* 45 vrefbuf */ + 0x4c006000, /* 46 dcmi */ + 0x4c004000, /* 47 crc2 */ + 0x48003000, /* 48 adc */ + 0x4c002000, /* 49 hash2 */ + 0x4c003000, /* 4A rng2 */ + 0x4c005000, /* 4B cryp2 */ + ETZPC_RESERVED, /* 4C reserved */ + ETZPC_RESERVED, /* 4D reserved */ + ETZPC_RESERVED, /* 4E reserved */ + ETZPC_RESERVED, /* 4F reserved */ + ETZPC_RESERVED, /* 50 sram1 */ + ETZPC_RESERVED, /* 51 sram2 */ + ETZPC_RESERVED, /* 52 sram3 */ + ETZPC_RESERVED, /* 53 sram4 */ + ETZPC_RESERVED, /* 54 retram */ + 0x49000000, /* 55 otg */ + 0x48004000, /* 56 sdmmc3 */ + 0x48005000, /* 57 dlybsd3 */ + 0x48000000, /* 58 dma1 */ + 0x48001000, /* 59 dma2 */ + 0x48002000, /* 5A dmamux */ + 0x58002000, /* 5B fmc */ + 0x58003000, /* 5C qspi */ + 0x58004000, /* 5D dlybq */ + 0x5800a000, /* 5E eth */ + ETZPC_RESERVED, /* 5F reserved */ +}; + +/* fdt helper */ +static bool fdt_disable_subnode_by_address(void *fdt, int offset, u32 addr) +{ + int node; + + for (node = fdt_first_subnode(fdt, offset); + node >= 0; + node = fdt_next_subnode(fdt, node)) { + if (addr == (u32)fdt_getprop(fdt, node, "reg", 0)) { + if (fdtdec_get_is_enabled(fdt, node)) { + fdt_status_disabled(fdt, node); + + return true; + } + return false; + } + } + + return false; +} + +int stm32_fdt_fixup_etzpc(void *fdt) +{ + void *base; + u32 version; + const u32 *array; + int array_size, i; + int soc_node, offset, shift; + u32 addr, status, decprot[ETZPC_DECPROT_NB]; + + base = syscon_get_first_range(STM32MP_SYSCON_ETZPC); + if (IS_ERR(base)) + return PTR_ERR(base); + + version = readl(base + ETZPC_IP_VER); + + switch (version) { + case IP_VER_STM32MP1: + array = stm32mp1_ip_addr; + array_size = ARRAY_SIZE(stm32mp1_ip_addr); + break; + default: + return 0; + } + + for (i = 0; i < ETZPC_DECPROT_NB; i++) + decprot[i] = readl(base + ETZPC_DECPROT(i)); + + soc_node = fdt_path_offset(fdt, "/soc"); + if (soc_node < 0) + return soc_node; + + for (i = 0; i < array_size; i++) { + offset = i / NB_PROT_PER_REG; + shift = (i % NB_PROT_PER_REG) * DECPROT_NB_BITS; + status = (decprot[offset] >> shift) & DECPROT_MASK; + addr = array[i]; + + debug("ETZPC: 0x%08x decprot %d=%d\n", addr, i, status); + + if (addr == ETZPC_RESERVED || + status == DECPROT_NON_SECURED) + continue; + + if (fdt_disable_subnode_by_address(fdt, soc_node, addr)) + printf("ETZPC: 0x%08x node disabled, decprot %d=%d\n", + addr, i, status); + } + + return 0; +} diff --git a/arch/arm/mach-stm32mp/syscon.c b/arch/arm/mach-stm32mp/syscon.c index eb7f435f10ca..242f8340abb4 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 }, { } }; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 57e0dd766317..2505d53fc47b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -712,6 +712,14 @@ sandbox_tee { compatible = "sandbox,tee"; }; + + pinctrl { + compatible = "sandbox,pinctrl"; + }; + + hwspinlock@0 { + compatible = "sandbox,hwspinlock"; + }; }; #include "sandbox_pmic.dtsi" diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index dcb6d5f56835..79e0e1ec026e 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -97,6 +97,7 @@ struct sandbox_state { /* Information about Watchdog */ struct sandbox_wdt_info wdt; + bool hwspinlock; /* Hardware Spinlock status */ ulong next_tag; /* Next address tag to allocate */ struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ }; diff --git a/board/st/stm32mp1/Kconfig b/board/st/stm32mp1/Kconfig index 5ab94151a9aa..92d8f901ff82 100644 --- a/board/st/stm32mp1/Kconfig +++ b/board/st/stm32mp1/Kconfig @@ -9,4 +9,11 @@ config SYS_VENDOR config SYS_CONFIG_NAME default "stm32mp1" +config CMD_STBOARD + bool "stboard - command for OTP board information" + default y + help + This compile the stboard command to + read and write the board in the OTP. + endif diff --git a/board/st/stm32mp1/MAINTAINERS b/board/st/stm32mp1/MAINTAINERS index 48d8fd2c3f2c..6c9710a1cf22 100644 --- a/board/st/stm32mp1/MAINTAINERS +++ b/board/st/stm32mp1/MAINTAINERS @@ -1,8 +1,11 @@ STM32MP1 BOARD M: Patrick Delaunay +M: Christophe Kerello 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_trusted_defconfig +F: configs/stm32mp15_optee_defconfig F: configs/stm32mp15_basic_defconfig -F: arch/arm/dts/stm32mp157* +F: include/configs/stm32mp1.h diff --git a/board/st/stm32mp1/Makefile b/board/st/stm32mp1/Makefile index 8188075b1a39..3c6c035b118a 100644 --- a/board/st/stm32mp1/Makefile +++ b/board/st/stm32mp1/Makefile @@ -7,6 +7,7 @@ ifdef CONFIG_SPL_BUILD obj-y += spl.o else obj-y += stm32mp1.o +obj-$(CONFIG_CMD_STBOARD) += cmd_stboard.o endif obj-y += board.o diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 174e6db1484a..4ebcfb4ad7ce 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -25,17 +25,21 @@ It features: Everything is supported in Linux but U-Boot is limited to: 1. UART 2. SDCard/MMC controller (SDMMC) +3. NAND controller (FMC) +4. NOR controller (QSPI) +5. USB controller (OTG DWC2) And the necessary drivers 1. I2C -2. STPMU1 -2. STPMU1 (PMIC and regulator) +2. STPMIC1 (PMIC and regulator) 3. Clock, Reset, Sysreset 4. Fuse Currently the following boards are supported: + stm32mp157c-ev1 + stm32mp157c-ed1 ++ stm32mp157a-dk1 ++ stm32mp157c-dk2 3. Boot Sequences ================= @@ -45,15 +49,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. @@ -64,12 +75,18 @@ 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 ++ 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 ================== @@ -90,29 +107,30 @@ 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: # make DEVICE_TREE= all - example: - basic boot on ev1 - # export KBUILD_OUTPUT=stm32mp15_basic - # make stm32mp15_basic_defconfig + a) trusted boot on ev1 + # export KBUILD_OUTPUT=stm32mp15_trusted + # make stm32mp15_trusted_defconfig # make DEVICE_TREE=stm32mp157c-ev1 all - basic boot on ed1 + b) basic boot on dk2 # export KBUILD_OUTPUT=stm32mp15_basic # make stm32mp15_basic_defconfig - # make DEVICE_TREE=stm32mp157c-ed1 all + # make DEVICE_TREE=stm32mp157c-dk2 all 6. Output files @@ -122,13 +140,20 @@ 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 6. Switch Setting for Boot Mode =============================== -You can select the boot mode, on the board ed1 with the switch SW1 +You can select the boot mode, +- on the daugther board ed1 with the switch SW1 : BOOT0, BOOT1, BOOT2 +- on board DK1/DK2 with the switch SW1 (BOOT1 forced to 0) ----------------------------------- Boot Mode BOOT2 BOOT1 BOOT0 @@ -142,6 +167,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). @@ -158,14 +193,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 +224,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 3: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 +234,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 @@ -266,3 +306,37 @@ on bank 0 to access to internal OTP: 4 check env update STM32MP> print ethaddr ethaddr=12:34:56:78:9a:bc + +10. Coprocessor firmware +======================== + +U-Boot can boot the coprocessor before the kernel (coprocessor early boot). + +A/ Manuallly by using rproc commands (update the bootcmd) + Configurations + # env set name_copro "stm32mp15_m4.elf" + # env set dev_copro 0 + # env set loadaddr_copro 0xC1000000 + + Load binary from bootfs partition (number 4) on SDCard (mmc 0) + # ext4load mmc 0:4 ${loadaddr_copro} ${name_copro} + => ${filesize} updated with the size of the loaded file + + Start M4 firmware with remote proc command + # rproc init + # rproc load ${dev_copro} ${loadaddr_copro} ${filesize} + # rproc load_rsc ${dev_copro} ${loadaddr_copro} ${filesize} + # rproc start ${dev_copro} + +B/ Automatically by using FIT feature and generic DISTRO bootcmd + + see examples in this directory : + + Generate FIT including kernel + device tree + M4 firmware + with cfg with M4 boot + $> mkimage -f fit_copro_kernel_dtb.its fit_copro_kernel_dtb.itb + + Then using DISTRO configuration file: see extlinux.conf to select + the correct configuration + => stm32mp157c-ev1-m4 + => stm32mp157c-dk2-m4 diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 5f31ea99f597..b6e528878e79 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) @@ -37,64 +37,140 @@ void board_debug_uart_init(void) } #endif -#ifdef CONFIG_PMIC_STPMU1 -int board_ddr_power_init(void) +#ifdef CONFIG_PMIC_STPMIC1 +int board_ddr_power_init(enum ddr_type ddr_type) { struct udevice *dev; + bool buck3_at_1800000v = false; 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 */ + /* No PMIC on power discrete board */ return 0; - /* Set LDO3 to sync mode */ - ret = pmic_reg_read(dev, STPMU1_LDOX_CTRL_REG(STPMU1_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 = pmic_reg_write(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), - ret); - if (ret < 0) - return ret; - - /* Set BUCK2 to 1.35V */ - ret = pmic_clrsetbits(dev, - STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), - STPMU1_BUCK_OUTPUT_MASK, - STPMU1_BUCK2_1350000V); - if (ret < 0) - return ret; - - /* Enable BUCK2 and VREF */ - ret = pmic_clrsetbits(dev, - STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), - STPMU1_BUCK_EN, STPMU1_BUCK_EN); - if (ret < 0) - return ret; - - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); - - ret = pmic_clrsetbits(dev, STPMU1_VREF_CTRL_REG, - STPMU1_VREF_EN, STPMU1_VREF_EN); - if (ret < 0) - return ret; - - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); - - /* Enable LDO3 */ - ret = pmic_clrsetbits(dev, - STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), - STPMU1_LDO_EN, STPMU1_LDO_EN); - if (ret < 0) - return ret; - - mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + switch (ddr_type) { + case STM32MP_DDR3: + /* VTT = Set LDO3 to sync mode */ + ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); + if (ret < 0) + return ret; + + ret &= ~STPMIC1_LDO3_MODE; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL); + + 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_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_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_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VTT = LDO3 */ + ret = pmic_clrsetbits(dev, + STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + break; + + case STM32MP_LPDDR2: + case STM32MP_LPDDR3: + /* + * configure VDD_DDR1 = LDO3 + * Set LDO3 to 1.8V + * + bypass mode if BUCK3 = 1.8V + * + normal mode if BUCK3 != 1.8V + */ + ret = pmic_reg_read(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3)); + if (ret < 0) + return ret; + + if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V) + buck3_at_1800000v = true; + + ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3)); + if (ret < 0) + return ret; + + ret &= ~STPMIC1_LDO3_MODE; + ret &= ~STPMIC1_LDO12356_VOUT_MASK; + ret |= STPMIC1_LDO3_1800000; + if (buck3_at_1800000v) + ret |= STPMIC1_LDO3_MODE; + + ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + ret); + if (ret < 0) + return ret; + + /* VDD_DDR2 : Set BUCK2 to 1.2V */ + ret = pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), + STPMIC1_BUCK_VOUT_MASK, + STPMIC1_BUCK2_1200000V); + if (ret < 0) + return ret; + + /* Enable VDD_DDR1 = LDO3 */ + ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3), + STPMIC1_LDO_ENA, STPMIC1_LDO_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + /* Enable VDD_DDR22 =BUCK2 */ + ret = pmic_clrsetbits(dev, + 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_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, STPMIC1_VREF_ENA); + if (ret < 0) + return ret; + + mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + + break; + + default: + break; + }; return 0; } diff --git a/board/st/stm32mp1/cmd_stboard.c b/board/st/stm32mp1/cmd_stboard.c new file mode 100644 index 000000000000..38b1c1be1e02 --- /dev/null +++ b/board/st/stm32mp1/cmd_stboard.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +static bool check_stboard(u16 board) +{ + int i; + const u16 st_board_id[] = { + 0x1272, + 0x1263, + 0x1264, + 0x1298, + 0x1341, + 0x1497, + }; + + for (i = 0; i < ARRAY_SIZE(st_board_id); i++) + if (board == st_board_id[i]) + return true; + + return false; +} + +static void display_stboard(u32 otp) +{ + printf("Board: MB%04x Var%d Rev.%c-%02d\n", + otp >> 16, + (otp >> 12) & 0xF, + ((otp >> 8) & 0xF) - 1 + 'A', + otp & 0xF); +} + +static int do_stboard(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int ret; + u32 otp; + u8 revision; + unsigned long board, variant, bom; + struct udevice *dev; + int confirmed = argc == 6 && !strcmp(argv[1], "-y"); + + argc -= 1 + confirmed; + argv += 1 + confirmed; + + if (argc != 0 && argc != 4) + return CMD_RET_USAGE; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + + ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD), + &otp, sizeof(otp)); + + if (ret) { + puts("OTP read error"); + return CMD_RET_FAILURE; + } + + if (argc == 0) { + if (!otp) + puts("Board : OTP board FREE\n"); + else + display_stboard(otp); + return CMD_RET_SUCCESS; + } + + if (otp) { + display_stboard(otp); + printf("ERROR: OTP board not FREE\n"); + return CMD_RET_FAILURE; + } + + if (strict_strtoul(argv[0], 16, &board) < 0 || + board == 0 || board > 0xFFFF) { + printf("argument %d invalid: %s\n", 1, argv[0]); + return CMD_RET_USAGE; + } + + if (strict_strtoul(argv[1], 10, &variant) < 0 || + variant == 0 || variant > 15) { + printf("argument %d invalid: %s\n", 2, argv[1]); + return CMD_RET_USAGE; + } + + revision = argv[2][0] - 'A' + 1; + if (strlen(argv[2]) > 1 || revision == 0 || revision > 15) { + printf("argument %d invalid: %s\n", 3, argv[2]); + return CMD_RET_USAGE; + } + + if (strict_strtoul(argv[3], 10, &bom) < 0 || + bom == 0 || bom > 15) { + printf("argument %d invalid: %s\n", 4, argv[3]); + return CMD_RET_USAGE; + } + + otp = (board << 16) | (variant << 12) | (revision << 8) | bom; + display_stboard(otp); + printf("=> OTP[%d] = %08X\n", BSEC_OTP_BOARD, otp); + + if (!check_stboard((u16)board)) { + printf("Unknown board MB%04x\n", (u16)board); + return CMD_RET_FAILURE; + } + if (!confirmed) { + printf("Warning: Programming BOARD in OTP is irreversible!\n"); + printf("Really perform this OTP programming? \n"); + + if (!confirm_yesno()) { + puts("BOARD programming aborted\n"); + return CMD_RET_FAILURE; + } + } + + ret = misc_write(dev, STM32_BSEC_OTP(BSEC_OTP_BOARD), + &otp, sizeof(otp)); + + if (ret) { + puts("BOARD programming error\n"); + return CMD_RET_FAILURE; + } + puts("BOARD programming done\n"); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(stboard, 6, 0, do_stboard, + "read/write board reference in OTP", + "\n" + " Print current board information\n" + "stboard [-y] \n" + " Write board information\n" + " - Board: xxxx, example 1264 for MB1264\n" + " - Variant: 1 ... 15\n" + " - Revision: A...O\n" + " - BOM: 1...15\n"); diff --git a/board/st/stm32mp1/extlinux.conf b/board/st/stm32mp1/extlinux.conf new file mode 100644 index 000000000000..2b4632804df1 --- /dev/null +++ b/board/st/stm32mp1/extlinux.conf @@ -0,0 +1,20 @@ +# Generic Distro Configuration for STM32MP157 +menu title Select the boot mode +TIMEOUT 20 +DEFAULT stm32mp157c-ev1 + +LABEL stm32mp157c-ev1 + KERNEL /fit_kernel_dtb.itb#ev1 + APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200 + +LABEL stm32mp157c-ev1-m4 + KERNEL /fit_copro_kernel_dtb.itb#ev1-m4 + APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200 + +LABEL stm32mp157c-dk2 + KERNEL /fit_kernel_dtb.itb#dk2 + APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200 + +LABEL stm32mp157c-dk2-m4 + KERNEL /fit_copro_kernel_dtb.itb#dk2-m4 + APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200 diff --git a/board/st/stm32mp1/fit_copro_kernel_dtb.its b/board/st/stm32mp1/fit_copro_kernel_dtb.its new file mode 100644 index 000000000000..7582fc35c5a7 --- /dev/null +++ b/board/st/stm32mp1/fit_copro_kernel_dtb.its @@ -0,0 +1,103 @@ +/* + * Compilation: + * mkimage -f fit_copro_kernel_dtb.its fit_copro_kernel_dtb.itb + */ + +/dts-v1/; +/ { + description = "U-Boot fitImage for stm32mp157"; + #address-cells = <1>; + + images { + + copro { + description = "M4 copro"; + data = /incbin/("stm32mp15_m4.elf"); + type = "stm32copro"; + arch = "arm"; + compression = "none"; + load = <0xC0800000>; + hash-1 { + algo = "sha1"; + }; + }; + + kernel { + description = "Linux kernel"; + data = /incbin/("zImage"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "none"; + load = <0xC0008000>; + entry = <0xC0008000>; + hash-1 { + algo = "sha1"; + }; + }; + + fdt-dk2 { + description = "FDT dk2"; + data = /incbin/("stm32mp157c-dk2.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash-1 { + algo = "sha1"; + }; + }; + + fdt-ev1 { + description = "FDT ev1"; + data = /incbin/("stm32mp157c-ev1.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash-1 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "dk2-m4"; + + dk2-m4 { + description = "dk2-m4"; + loadables = "copro"; + kernel = "kernel"; + fdt = "fdt-dk2"; + hash-1 { + algo = "sha1"; + }; + }; + + dk2 { + description = "dk2"; + kernel = "kernel"; + fdt = "fdt-dk2"; + hash-1 { + algo = "sha1"; + }; + }; + + ev1-m4 { + description = "ev1-m4"; + loadables = "copro"; + kernel = "kernel"; + fdt = "fdt-ev1"; + hash-1 { + algo = "sha1"; + }; + }; + + ev1 { + description = "ev1"; + kernel = "kernel"; + fdt = "fdt-ev1"; + hash-1 { + algo = "sha1"; + }; + }; + }; +}; diff --git a/board/st/stm32mp1/fit_kernel_dtb.its b/board/st/stm32mp1/fit_kernel_dtb.its new file mode 100644 index 000000000000..18d03ebf3c03 --- /dev/null +++ b/board/st/stm32mp1/fit_kernel_dtb.its @@ -0,0 +1,82 @@ +/* + * Compilation: + * mkimage -f fit_kernel_dtb.its fit_kernel_dtb.itb + * + * Files in linux build dir: + * - arch/arm/boot/zImage + * - arch/arm/boot/dts/stm32mp157c-dk2.dtb + * - arch/arm/boot/dts/stm32mp157c-ev1.dtb + * + * load mmc 0:4 $kernel_addr_r fit_kernel_dtb.itb + * bootm $kernel_addr_r + * bootm $kernel_addr_r#dk2 + * bootm $kernel_addr_r#ev1 + * + * or use extlinux.conf in this directory + */ + +/dts-v1/; +/ { + description = "U-Boot fitImage for stm32mp157"; + #address-cells = <1>; + + images { + kernel { + description = "Linux kernel"; + data = /incbin/("zImage"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "none"; + load = <0xC0008000>; + entry = <0xC0008000>; + hash-1 { + algo = "sha1"; + }; + }; + + fdt-dk2 { + description = "FDT dk2"; + data = /incbin/("stm32mp157c-dk2.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash-1 { + algo = "sha1"; + }; + }; + + fdt-ev1 { + description = "FDT ev1"; + data = /incbin/("stm32mp157c-ev1.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + hash-1 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "dk2"; + + dk2 { + description = "dk2"; + kernel = "kernel"; + fdt = "fdt-dk2"; + hash-1 { + algo = "sha1"; + }; + }; + + ev1 { + description = "ev1"; + kernel = "kernel"; + fdt = "fdt-ev1"; + hash-1 { + algo = "sha1"; + }; + }; + }; +}; diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c index f3db0d638539..e65ff288ea1b 100644 --- a/board/st/stm32mp1/spl.c +++ b/board/st/stm32mp1/spl.c @@ -9,24 +9,37 @@ #include #include #include -#include #include -#include +#include #include 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_BUCKS_MRST_CR, + STPMIC1_MRST_BUCK(STPMIC1_BUCK3), + STPMIC1_MRST_BUCK(STPMIC1_BUCK3)); + + /* Check if debug is enabled to program PMIC according to the bit */ + if ((readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_DEBUG_ON) && !ret) { + printf("Keep debug unit ON\n"); + + pmic_clrsetbits(dev, STPMIC1_BUCKS_MRST_CR, + STPMIC1_MRST_BUCK_DEBUG, + STPMIC1_MRST_BUCK_DEBUG); + + if (STPMIC1_MRST_LDO_DEBUG) + pmic_clrsetbits(dev, STPMIC1_LDOS_MRST_CR, + STPMIC1_MRST_LDO_DEBUG, + STPMIC1_MRST_LDO_DEBUG); + } #endif } diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 54feca0ecff5..5dc62965b092 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -2,136 +2,351 @@ /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ + #include #include -#include -#include +#include #include +#include +#include +#include #include +#include +#include +#include +#include #include +#include #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_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 */ DECLARE_GLOBAL_DATA_PTR; -#define STM32MP_GUSBCFG 0x40002407 +#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; + 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 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 +} + +bool board_is_dk2(void) +{ + if (of_machine_is_compatible("st,stm32mp157c-dk2")) + return true; -#define STM32MP_GGPIO 0x38 -#define STM32MP_GGPIO_VBUS_SENSING BIT(21) + return false; +} + +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; +} + +#ifdef CONFIG_STM32_SDMMC2 +/* this is a weak define that we are overriding */ +int board_mmc_init(void) +{ + return 0; +} +#endif + +#ifdef CONFIG_STM32_QSPI +void board_qspi_init(void) +{ +} +#endif /* CONFIG_STM32_QSPI */ + +#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) + +/* + * DWC2 registers should be defined in drivers + * OTG: drivers/usb/gadget/dwc2_udc_otg_regs.h + * HOST: ./drivers/usb/host/dwc2.h + */ +#define DWC2_GOTGCTL_OFFSET 0x00 +#define DWC2_GGPIO_OFFSET 0x38 + +#define DWC2_GGPIO_VBUS_SENSING BIT(21) + +#define DWC2_GOTGCTL_AVALIDOVEN BIT(4) +#define DWC2_GOTGCTL_AVALIDOVVAL BIT(5) +#define DWC2_GOTGCTL_BVALIDOVEN BIT(6) +#define DWC2_GOTGCTL_BVALIDOVVAL BIT(7) +#define DWC2_GOTGCTL_BSVLD BIT(19) + +#define STM32MP_GUSBCFG 0x40002407 static struct dwc2_plat_otg_data stm32mp_otg_data = { + .regs_otg = FDT_ADDR_T_NONE, .usb_gusbcfg = STM32MP_GUSBCFG, + .priv = NULL, /* pointer to udevice for stusb1600 when present */ }; static struct reset_ctl usbotg_reset; -int board_usb_init(int index, enum usb_init_type init) +/* STMicroelectronics STUSB1600 Type-C controller */ +#define STUSB1600_CC_CONNECTION_STATUS 0x0E + +/* STUSB1600_CC_CONNECTION_STATUS bitfields */ +#define STUSB1600_CC_ATTACH BIT(0) + +static int stusb1600_init(void) { + struct udevice *dev, *bus; + ofnode node; + int ret; + u32 chip_addr; + + node = ofnode_by_compatible(ofnode_null(), "st,stusb1600"); + if (!ofnode_valid(node)) { + printf("stusb1600 not found\n"); + return -ENODEV; + } + + ret = ofnode_read_u32(node, "reg", &chip_addr); + if (ret) + return -EINVAL; + + ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node), + &bus); + if (ret) { + printf("bus for stusb1600 not found\n"); + return -ENODEV; + } + + ret = dm_i2c_probe(bus, chip_addr, 0, &dev); + if (!ret) + stm32mp_otg_data.priv = dev; + + return ret; +} + +static int stusb1600_cable_connected(void) +{ + struct udevice *stusb1600_dev = stm32mp_otg_data.priv; + u8 status; + + if (dm_i2c_read(stusb1600_dev, + STUSB1600_CC_CONNECTION_STATUS, + &status, 1)) + return 0; + + return status & STUSB1600_CC_ATTACH; +} + +void board_usbotg_init(void) +{ + int node; struct fdtdec_phandle_args args; struct udevice *dev; const void *blob = gd->fdt_blob; struct clk clk; - struct phy phy; - int node; - int phy_provider; - int ret; /* find the usb otg node */ node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2"); if (node < 0) { debug("Not found usb_otg device\n"); - return -ENODEV; + return; } if (!fdtdec_get_is_enabled(blob, node)) { debug("stm32 usbotg is disabled in the device tree\n"); - return -ENODEV; + return; } /* Enable clock */ - ret = fdtdec_parse_phandle_with_args(blob, node, "clocks", - "#clock-cells", 0, 0, &args); - if (ret) { + if (fdtdec_parse_phandle_with_args(blob, node, "clocks", + "#clock-cells", 0, 0, &args)) { debug("usbotg has no clocks defined in the device tree\n"); - return ret; + return; } - ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev); - if (ret) - return ret; + if (uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev)) + return; - if (args.args_count != 1) { - debug("Can't find clock ID in the device tree\n"); - return -ENODATA; - } + if (args.args_count != 1) + return; clk.dev = dev; clk.id = args.args[0]; - ret = clk_enable(&clk); - if (ret) { + if (clk_enable(&clk)) { debug("Failed to enable usbotg clock\n"); - return ret; + return; } /* Reset */ - ret = fdtdec_parse_phandle_with_args(blob, node, "resets", - "#reset-cells", 0, 0, &args); - if (ret) { + if (fdtdec_parse_phandle_with_args(blob, node, "resets", + "#reset-cells", 0, 0, &args)) { debug("usbotg has no resets defined in the device tree\n"); goto clk_err; } - ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev); - if (ret || args.args_count != 1) + if ((uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev)) || + args.args_count != 1) goto clk_err; usbotg_reset.dev = dev; usbotg_reset.id = args.args[0]; - reset_assert(&usbotg_reset); - udelay(2); - reset_deassert(&usbotg_reset); - - /* Get USB PHY */ - ret = fdtdec_parse_phandle_with_args(blob, node, "phys", - "#phy-cells", 0, 0, &args); - if (!ret) { - phy_provider = fdt_parent_offset(blob, args.node); - ret = uclass_get_device_by_of_offset(UCLASS_PHY, - phy_provider, &dev); - if (ret) - goto clk_err; - - phy.dev = dev; - phy.id = fdtdec_get_uint(blob, args.node, "reg", -1); - - ret = generic_phy_power_on(&phy); - if (ret) { - debug("unable to power on the phy\n"); + /* Phy */ + if (!(fdtdec_parse_phandle_with_args(blob, node, "phys", + "#phy-cells", 0, 0, &args))) { + stm32mp_otg_data.phy_of_node = + fdt_parent_offset(blob, args.node); + if (stm32mp_otg_data.phy_of_node <= 0) { + debug("Not found usbo phy device\n"); goto clk_err; } - - ret = generic_phy_init(&phy); - if (ret) { - debug("failed to init usb phy\n"); - goto phy_power_err; - } + stm32mp_otg_data.regs_phy = fdtdec_get_uint(blob, args.node, + "reg", -1); } /* Parse and store data needed for gadget */ stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg"); if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) { debug("usbotg: can't get base address\n"); - ret = -ENODATA; - goto phy_init_err; + goto clk_err; } stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node, @@ -140,59 +355,591 @@ int board_usb_init(int index, enum usb_init_type init) "g-np-tx-fifo-size", 0); stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node, "g-tx-fifo-size", 0); + + if (fdtdec_get_bool(blob, node, "usb1600")) { + stusb1600_init(); + return; + } + /* Enable voltage level detector */ if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply", - NULL, 0, 0, &args))) { + NULL, 0, 0, &args))) if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR, - args.node, &dev)) { - ret = regulator_set_enable(dev, true); - if (ret) { + args.node, &dev)) + if (regulator_set_enable(dev, true)) { debug("Failed to enable usb33d\n"); - goto phy_init_err; + goto clk_err; } - } - } - /* Enable vbus sensing */ - setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO, - STM32MP_GGPIO_VBUS_SENSING); - - return dwc2_udc_probe(&stm32mp_otg_data); -phy_init_err: - generic_phy_exit(&phy); - -phy_power_err: - generic_phy_power_off(&phy); + return; clk_err: clk_disable(&clk); - - return ret; } -int board_usb_cleanup(int index, enum usb_init_type init) +int board_usb_init(int index, enum usb_init_type init) { + if (init == USB_INIT_HOST) + return 0; + + if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) + return -EINVAL; + /* Reset usbotg */ reset_assert(&usbotg_reset); udelay(2); reset_deassert(&usbotg_reset); + /* if the board embed an USB1600 chip */ + if (stm32mp_otg_data.priv) + /* Override A/B session valid bits */ + stm32mp_otg_data.usb_gotgctl = DWC2_GOTGCTL_AVALIDOVEN | + DWC2_GOTGCTL_AVALIDOVVAL | + DWC2_GOTGCTL_BVALIDOVEN | + DWC2_GOTGCTL_BVALIDOVVAL; + else + /* Enable vbus sensing */ + setbits_le32(stm32mp_otg_data.regs_otg + DWC2_GGPIO_OFFSET, + DWC2_GGPIO_VBUS_SENSING); + + return dwc2_udc_probe(&stm32mp_otg_data); +} + +int g_dnl_board_usb_cable_connected(void) +{ + if (stm32mp_otg_data.priv) + return stusb1600_cable_connected(); + + return readl(stm32mp_otg_data.regs_otg + DWC2_GOTGCTL_OFFSET) & + DWC2_GOTGCTL_BSVLD; +} + +#define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11 +int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) +{ + if (!strcmp(name, "usb_dnl_dfu")) + put_unaligned(STM32MP1_G_DNL_DFU_PRODUCT_NUM, &dev->idProduct); + else + put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct); + return 0; } +#endif /* CONFIG_USB_GADGET */ -int board_late_init(void) +static void sysconf_init(void) { + 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); + debug("SYSCFG: init @0x%p\n", 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); + debug("[0x%x] SYSCFG.icnr = 0x%08x (LTDC and GPU)\n", + (u32)syscfg + SYSCFG_ICNR, readl(syscfg + SYSCFG_ICNR)); + + /* disable Pull-Down for boot pin connected to VDD */ + bootr = readl(syscfg + SYSCFG_BOOTR); + bootr |= (bootr & 0x7 << 4); + writel(bootr, syscfg + SYSCFG_BOOTR); + debug("[0x%x] SYSCFG.bootr = 0x%08x\n", + (u32)syscfg + SYSCFG_BOOTR, readl(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 + debug("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n", + (u32)syscfg + SYSCFG_IOCTRLSETR, + readl(syscfg + SYSCFG_IOCTRLSETR)); + + /* 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); + + debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n", + (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR)); +} + +/* board interface eth init */ +/* this is a weak define that we are overriding */ +int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, + bool eth_ref_clk_sel_reg) +{ + u8 *syscfg; + u32 value; + + syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG); + + if (!syscfg) + return -ENODEV; + + switch (interface_type) { + case PHY_INTERFACE_MODE_MII: + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL; + debug("%s: PHY_INTERFACE_MODE_MII\n", __func__); + break; + case PHY_INTERFACE_MODE_GMII: + if (eth_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII | + SYSCFG_PMCSETR_ETH_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII; + debug("%s: PHY_INTERFACE_MODE_GMII\n", __func__); + break; + case PHY_INTERFACE_MODE_RMII: + if (eth_ref_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_RMII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_RMII; + debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__); + break; + case PHY_INTERFACE_MODE_RGMII: + if (eth_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_RGMII | + SYSCFG_PMCSETR_ETH_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_RGMII; + debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__); + break; + default: + debug("%s: Do not manage %d interface\n", + __func__, interface_type); + /* Do not manage others interfaces */ + return -EINVAL; + } + + /* clear and set ETH configuration bits */ + writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL, + syscfg + SYSCFG_PMCCLRR); + writel(value, syscfg + SYSCFG_PMCSETR); + + return 0; +} + +#ifdef CONFIG_LED +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; +} +#endif /* CONFIG_LED */ + +#ifdef CONFIG_ADC +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; + + /* Stop boot process 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; } +#endif /* CONFIG_ADC */ + +#ifdef CONFIG_DM_REGULATOR +/* Fix to make I2C1 usable on DK2 for touchscreen usage in kernel */ +static int dk2_i2c1_fix(void) +{ + ofnode node; + struct gpio_desc hdmi, audio; + int ret = 0; + + node = ofnode_path("/soc/i2c@40012000/hdmi-transmitter@39"); + if (!ofnode_valid(node)) { + pr_debug("%s: no hdmi-transmitter@39 ?\n", __func__); + return -ENOENT; + } + + if (gpio_request_by_name_nodev(node, "reset-gpios", 0, + &hdmi, GPIOD_IS_OUT)) { + pr_debug("%s: could not find reset-gpios\n", + __func__); + return -ENOENT; + } + + node = ofnode_path("/soc/i2c@40012000/cs42l51@4a"); + if (!ofnode_valid(node)) { + pr_debug("%s: no cs42l51@4a ?\n", __func__); + return -ENOENT; + } + + if (gpio_request_by_name_nodev(node, "reset-gpios", 0, + &audio, GPIOD_IS_OUT)) { + pr_debug("%s: could not find reset-gpios\n", + __func__); + return -ENOENT; + } + + /* before power up, insure that HDMI anh AUDIO IC is under reset */ + ret = dm_gpio_set_value(&hdmi, 1); + if (ret) { + pr_err("%s: can't set_value for hdmi_nrst gpio", __func__); + goto error; + } + ret = dm_gpio_set_value(&audio, 1); + if (ret) { + pr_err("%s: can't set_value for audio_nrst gpio", __func__); + goto error; + } + + /* power-up audio IC */ + regulator_autoset_by_name("v1v8_audio", NULL); + + /* power-up HDMI IC */ + regulator_autoset_by_name("v1v2_hdmi", NULL); + regulator_autoset_by_name("v3v3_hdmi", NULL); + +error: + return ret; +} +#endif /* 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(); + if (IS_ENABLED(CONFIG_LED)) led_default_state(); +#ifdef CONFIG_DM_REGULATOR + if (board_is_dk2()) + dk2_i2c1_fix(); + + regulators_enable_boot_on(_DEBUG); +#endif + +#ifdef CONFIG_ADC + board_check_usb_power(); +#endif /* CONFIG_ADC */ + + sysconf_init(); + +#ifdef CONFIG_STM32_SDMMC2 + board_mmc_init(); +#endif /* CONFIG_STM32_SDMMC2 */ + +#ifdef CONFIG_STM32_QSPI + board_qspi_init(); +#endif /* CONFIG_STM32_QSPI */ + +#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) + board_usbotg_init(); +#endif + + return 0; +} + +void board_quiesce_devices(void) +{ +#ifdef CONFIG_LED + setup_led(LEDST_OFF); +#endif +} + +#ifdef CONFIG_SYS_MTDPARTS_RUNTIME +void board_mtdparts_default(const char **mtdids, const char **mtdparts) +{ + struct udevice *dev; + char *s_nand0 = NULL, *s_nor0 = NULL; + static char parts[256]; + static char ids[22]; + + if (!uclass_get_device(UCLASS_MTD, 0, &dev)) + s_nand0 = env_get("mtdparts_nand0"); + + if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) + s_nor0 = env_get("mtdparts_nor0"); + + strcpy(ids, ""); + strcpy(parts, ""); + if (s_nand0 && s_nor0) { + snprintf(ids, sizeof(ids), "nor0=nor0,nand0=nand0"); + snprintf(parts, sizeof(parts), + "mtdparts=nor0:%s;nand0:%s", s_nor0, s_nand0); + } else if (s_nand0) { + snprintf(ids, sizeof(ids), "nand0=nand0"); + snprintf(parts, sizeof(parts), "mtdparts=nand0:%s", s_nand0); + } else if (s_nor0) { + snprintf(ids, sizeof(ids), "nor0=nor0"); + snprintf(parts, sizeof(parts), "mtdparts=nor0:%s", s_nor0); + } + *mtdids = ids; + *mtdparts = parts; + debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts); +} +#endif + +#if defined(CONFIG_OF_BOARD_SETUP) +int ft_board_setup(void *blob, bd_t *bd) +{ + ulong copro_rsc_addr, copro_rsc_size; + int off; + char *s_copro = NULL; +#ifdef CONFIG_FDT_FIXUP_PARTITIONS + struct node_info nodes[] = { + { "st,stm32f469-qspi", MTD_DEV_TYPE_NOR, }, + { "st,stm32mp15-fmc2", MTD_DEV_TYPE_NAND, }, + }; + fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); +#endif + + /* Update DT if coprocessor started */ + off = fdt_path_offset(blob, "/m4"); + if (off > 0) { + s_copro = env_get("copro_state"); + copro_rsc_addr = env_get_hex("copro_rsc_addr", 0); + copro_rsc_size = env_get_hex("copro_rsc_size", 0); + + if (s_copro) { + fdt_setprop_empty(blob, off, "early-booted"); + if (copro_rsc_addr) + fdt_setprop_u32(blob, off, "rsc-address", + copro_rsc_addr); + if (copro_rsc_size) + fdt_setprop_u32(blob, off, "rsc-size", + copro_rsc_size); + } else { + fdt_delprop(blob, off, "early-booted"); + } + } + return 0; } +#endif + +void board_stm32copro_image_process(ulong fw_image, size_t fw_size) +{ + int ret, id = 0; /* Copro id fixed to 0 as only one coproc on mp1 */ + unsigned int rsc_size; + ulong rsc_addr; + + if (!rproc_is_initialized()) + if (rproc_init()) { + printf("Remote Processor %d initialization failed\n", + id); + return; + } + + ret = rproc_load_rsc_table(id, fw_image, fw_size, &rsc_addr, &rsc_size); + if (!ret) { + env_set_hex("copro_rsc_addr", rsc_addr); + env_set_hex("copro_rsc_size", rsc_size); + } + + ret = rproc_load(id, fw_image, fw_size); + printf("Load Remote Processor %d with data@addr=0x%08lx %u bytes:%s\n", + id, fw_image, fw_size, ret ? " Failed!" : " Success!"); + + if (!ret) { + rproc_start(id); + env_set("copro_state", "booted"); + } +} + +U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_STM32COPRO, board_stm32copro_image_process); diff --git a/cmd/Kconfig b/cmd/Kconfig index ad14c9ce7124..3aa10d5a1a57 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -953,6 +953,14 @@ config CMD_PCMCIA about 1990. These devices are typically removable memory or network cards using a standard 68-pin connector. +config CMD_PINMUX + bool "pinmux - show pins muxing" + default y if PINCTRL + help + Parse all available pin-controllers and show pins muxing. This + is useful for debug purpoer to check the pin muxing and to know if + a pin is configured as a GPIO or as an alternate function. + config CMD_POWEROFF bool "poweroff" help diff --git a/cmd/Makefile b/cmd/Makefile index ac4830a692f2..e9ab126e9ab8 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -103,6 +103,7 @@ ifdef CONFIG_PCI obj-$(CONFIG_CMD_PCI) += pci.o endif obj-y += pcmcia.o +obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PXE) += pxe.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o diff --git a/cmd/adc.c b/cmd/adc.c index c8857ed147e7..2d635acbd950 100644 --- a/cmd/adc.c +++ b/cmd/adc.c @@ -35,7 +35,7 @@ static int do_adc_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { struct udevice *dev; - unsigned int data_mask; + unsigned int data_mask, ch_mask; int ret, vss, vdd; if (argc < 2) @@ -49,6 +49,10 @@ static int do_adc_info(cmd_tbl_t *cmdtp, int flag, int argc, printf("ADC Device '%s' :\n", argv[1]); + ret = adc_channel_mask(dev, &ch_mask); + if (!ret) + printf("channel mask: %x\n", ch_mask); + ret = adc_data_mask(dev, &data_mask); if (!ret) printf("data mask: %x\n", data_mask); @@ -67,8 +71,9 @@ static int do_adc_info(cmd_tbl_t *cmdtp, int flag, int argc, static int do_adc_single(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { + struct udevice *dev; unsigned int data; - int ret; + int ret, uV; if (argc < 3) return CMD_RET_USAGE; @@ -81,7 +86,62 @@ static int do_adc_single(cmd_tbl_t *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - printf("%u\n", data); + ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev); + if (!ret && !adc_raw_to_uV(dev, data, &uV)) + printf("%u, %d uV\n", data, uV); + else + printf("%u\n", data); + + return CMD_RET_SUCCESS; +} + +static int do_adc_scan(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct adc_channel ch[ADC_MAX_CHANNEL]; + struct udevice *dev; + unsigned int ch_mask; + int i, chan, ret, uV; + + if (argc < 2) + return CMD_RET_USAGE; + + ret = uclass_get_device_by_name(UCLASS_ADC, argv[1], &dev); + if (ret) { + pr_err("Can't get the ADC %s: %d\n", argv[1], ret); + return CMD_RET_FAILURE; + } + + switch (argc) { + case 3: + ch_mask = simple_strtoul(argv[2], NULL, 0); + if (ch_mask) + break; + case 2: + ret = adc_channel_mask(dev, &ch_mask); + if (ret) { + pr_err("Can't get mask for %s: %d\n", dev->name, ret); + return CMD_RET_FAILURE; + } + break; + } + + ret = adc_channels_single_shot(dev->name, ch_mask, ch); + if (ret) { + pr_err("Can't get single shot for %s (chans mask: 0x%x): %d\n", + dev->name, ch_mask, ret); + return CMD_RET_FAILURE; + } + + for (chan = 0, i = 0; chan < ADC_MAX_CHANNEL; chan++) { + if (!(ch_mask & ADC_CHANNEL(chan))) + continue; + if (!adc_raw_to_uV(dev, ch[i].data, &uV)) + printf("[%02d]: %u, %d uV\n", ch[i].id, ch[i].data, uV); + else + printf("[%02d]: %u\n", ch[i].id, ch[i].data); + i++; + } return CMD_RET_SUCCESS; } @@ -90,6 +150,7 @@ static cmd_tbl_t cmd_adc_sub[] = { U_BOOT_CMD_MKENT(list, 1, 1, do_adc_list, "", ""), U_BOOT_CMD_MKENT(info, 2, 1, do_adc_info, "", ""), U_BOOT_CMD_MKENT(single, 3, 1, do_adc_single, "", ""), + U_BOOT_CMD_MKENT(scan, 3, 1, do_adc_scan, "", ""), }; static int do_adc(cmd_tbl_t *cmdtp, int flag, int argc, @@ -115,6 +176,7 @@ static int do_adc(cmd_tbl_t *cmdtp, int flag, int argc, static char adc_help_text[] = "list - list ADC devices\n" "adc info - Get ADC device info\n" - "adc single - Get Single data of ADC device channel"; + "adc single - Get Single data of ADC device channel\n" + "adc scan [channel mask] - Scan all [or masked] ADC channels"; U_BOOT_CMD(adc, 4, 1, do_adc, "ADC sub-system", adc_help_text); diff --git a/cmd/bmp.c b/cmd/bmp.c index 02bdf48b4d42..b8af784590dd 100644 --- a/cmd/bmp.c +++ b/cmd/bmp.c @@ -124,8 +124,14 @@ static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar break; case 4: addr = simple_strtoul(argv[1], NULL, 16); - x = simple_strtoul(argv[2], NULL, 10); - y = simple_strtoul(argv[3], NULL, 10); + if (!strcmp(argv[2], "m")) + x = BMP_ALIGN_CENTER; + else + x = simple_strtoul(argv[2], NULL, 10); + if (!strcmp(argv[3], "m")) + y = BMP_ALIGN_CENTER; + else + y = simple_strtoul(argv[3], NULL, 10); break; default: return CMD_RET_USAGE; @@ -249,9 +255,11 @@ int bmp_display(ulong addr, int x, int y) if (!ret) { bool align = false; -# ifdef CONFIG_SPLASH_SCREEN_ALIGN - align = true; -# endif /* CONFIG_SPLASH_SCREEN_ALIGN */ + if (CONFIG_IS_ENABLED(SPLASH_SCREEN_ALIGN) || + x == BMP_ALIGN_CENTER || + y == BMP_ALIGN_CENTER) + align = true; + ret = video_bmp_display(dev, addr, x, y, align); } #elif defined(CONFIG_LCD) diff --git a/cmd/pinmux.c b/cmd/pinmux.c new file mode 100644 index 000000000000..6c8ec5164d3c --- /dev/null +++ b/cmd/pinmux.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include + +#define LIMIT_DEVNAME 30 + +static struct udevice *currdev; + +static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *name; + int ret; + + switch (argc) { + case 2: + name = argv[1]; + ret = uclass_get_device_by_name(UCLASS_PINCTRL, name, &currdev); + if (ret) { + printf("Can't get the pin-controller: %s!\n", name); + return CMD_RET_FAILURE; + } + case 1: + if (!currdev) { + printf("Pin-controller device is not set!\n"); + return CMD_RET_USAGE; + } + + printf("dev: %s\n", currdev->name); + } + + return CMD_RET_SUCCESS; +} + +static int show_pinmux(struct udevice *dev) +{ + char pin_name[PINNAME_SIZE]; + char pin_mux[PINMUX_SIZE]; + int pins_count; + int i; + int ret; + + pins_count = pinctrl_get_pins_count(dev); + + if (pins_count == -ENOSYS) { + printf("Ops get_pins_count not supported\n"); + return pins_count; + } + + for (i = 0; i < pins_count; i++) { + ret = pinctrl_get_pin_name(dev, i, pin_name, PINNAME_SIZE); + if (ret == -ENOSYS) { + printf("Ops get_pin_name not supported\n"); + return ret; + } + + ret = pinctrl_get_pin_muxing(dev, i, pin_mux, PINMUX_SIZE); + if (ret) { + printf("Ops get_pin_muxing error (%d)\n", ret); + return ret; + } + + printf("%-*s: %-*s\n", PINNAME_SIZE, pin_name, + PINMUX_SIZE, pin_mux); + } + + return 0; +} + +static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + int ret = CMD_RET_USAGE; + + if (currdev && (argc < 2 || strcmp(argv[1], "-a"))) + return show_pinmux(currdev); + + if (argc < 2 || strcmp(argv[1], "-a")) + return ret; + + uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) { + /* insert a separator between each pin-controller display */ + printf("--------------------------\n"); + printf("%s:\n", dev->name); + ret = show_pinmux(dev); + if (ret < 0) + printf("Can't display pin muxing for %s\n", + dev->name); + } + + return ret; +} + +static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + + printf("| %-*.*s| %-*.*s| %s\n", + LIMIT_DEVNAME, LIMIT_DEVNAME, "Device", + LIMIT_DEVNAME, LIMIT_DEVNAME, "Driver", + "Parent"); + + uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) { + printf("| %-*.*s| %-*.*s| %s\n", + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name, + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->driver->name, + dev->parent->name); + } + + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t pinmux_subcmd[] = { + U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""), + U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""), + U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""), +}; + +static int do_pinmux(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *cmd; + + argc--; + argv++; + + cmd = find_cmd_tbl(argv[0], pinmux_subcmd, ARRAY_SIZE(pinmux_subcmd)); + if (!cmd || argc > cmd->maxargs) + return CMD_RET_USAGE; + + return cmd->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD(pinmux, CONFIG_SYS_MAXARGS, 1, do_pinmux, + "show pin-controller muxing", + "list - list UCLASS_PINCTRL devices\n" + "pinmux dev [pincontroller-name] - select pin-controller device\n" + "pinmux status [-a] - print pin-controller muxing [for all]\n" +) diff --git a/cmd/pxe.c b/cmd/pxe.c index 274555319ba8..e77770237cb1 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include "menu.h" @@ -488,6 +490,7 @@ struct pxe_label { * * title - the name of the menu as given by a 'menu title' line. * default_label - the name of the default label, if any. + * bmp - the bmp file name which is displayed in background * timeout - time in tenths of a second to wait for a user key-press before * booting the default label. * prompt - if 0, don't prompt for a choice unless the timeout period is @@ -498,6 +501,7 @@ struct pxe_label { struct pxe_menu { char *title; char *default_label; + char *bmp; int timeout; int prompt; struct list_head labels; @@ -850,6 +854,7 @@ enum token_type { T_FDTDIR, T_ONTIMEOUT, T_IPAPPEND, + T_BACKGROUND, T_INVALID }; @@ -883,6 +888,7 @@ static const struct token keywords[] = { {"fdtdir", T_FDTDIR}, {"ontimeout", T_ONTIMEOUT,}, {"ipappend", T_IPAPPEND,}, + {"background", T_BACKGROUND,}, {NULL, T_INVALID} }; @@ -1160,6 +1166,10 @@ static int parse_menu(cmd_tbl_t *cmdtp, char **c, struct pxe_menu *cfg, nest_level + 1); break; + case T_BACKGROUND: + err = parse_sliteral(c, &cfg->bmp); + break; + default: printf("Ignoring malformed menu command: %.*s\n", (int)(*c - s), s); @@ -1574,6 +1584,20 @@ static void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg) struct menu *m; int err; +#ifdef CONFIG_CMD_BMP + /* display BMP if available */ + if (cfg->bmp) { + if (get_relfile(cmdtp, cfg->bmp, load_addr)) { + run_command("cls", 0); + bmp_display(load_addr, + BMP_ALIGN_CENTER, BMP_ALIGN_CENTER); + } else { + printf("Skipping background bmp %s for failure\n", + cfg->bmp); + } + } +#endif + m = pxe_menu_to_menu(cfg); if (!m) return; diff --git a/cmd/remoteproc.c b/cmd/remoteproc.c index 81463f36b603..755e9331f43c 100644 --- a/cmd/remoteproc.c +++ b/cmd/remoteproc.c @@ -103,7 +103,7 @@ static int do_remoteproc_list(cmd_tbl_t *cmdtp, int flag, int argc, } /** - * do_remoteproc_load() - Load a remote processor with binary image + * do_remoteproc_load() - Load a remote processor with binary or elf image * @cmdtp: unused * @flag: unused * @argc: argument count for the load function @@ -142,6 +142,53 @@ static int do_remoteproc_load(cmd_tbl_t *cmdtp, int flag, int argc, return ret ? CMD_RET_FAILURE : 0; } +/** + * do_remoteproc_load_rsc_table() - Get resource table from an elf image + * @cmdtp: unused + * @flag: unused + * @argc: argument count for the load function + * @argv: arguments for the load function + * + * Return: 0 if no error, else returns appropriate error value. + */ +static int do_remoteproc_load_rsc_table(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr, size, rsc_addr; + unsigned int rsc_size; + int id, ret; + + if (argc != 4) + return CMD_RET_USAGE; + + id = (int)simple_strtoul(argv[1], NULL, 3); + addr = simple_strtoul(argv[2], NULL, 16); + + size = simple_strtoul(argv[3], NULL, 16); + + if (!size) { + printf("\t Expect some size??\n"); + return CMD_RET_USAGE; + } + + if (!rproc_is_initialized()) { + printf("\tRemote Processors are not initialized\n"); + return CMD_RET_USAGE; + } + + ret = rproc_load_rsc_table(id, addr, size, &rsc_addr, &rsc_size); + if (!ret) { + env_set_hex("copro_rsc_addr", rsc_addr); + env_set_hex("copro_rsc_size", rsc_size); + } + + printf("Remote Processor %d resource table %s : 0x%08lx-0x%x\n", + id, ret ? "Not found" : "Found", ret ? 0 : rsc_addr, + ret ? 0 : rsc_size); + + return ret ? CMD_RET_FAILURE : 0; +} + /** * do_remoteproc_wrapper() - wrapper for various rproc commands * @cmdtp: unused @@ -172,6 +219,9 @@ static int do_remoteproc_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, if (!strcmp(argv[0], "start")) { ret = rproc_start(id); + if (!ret) + env_set("copro_state", "booted"); + } else if (!strcmp(argv[0], "stop")) { ret = rproc_stop(id); } else if (!strcmp(argv[0], "reset")) { @@ -213,6 +263,12 @@ static cmd_tbl_t cmd_remoteproc_sub[] = { "- id: ID of the remote processor(see 'list' cmd)\n" "- addr: Address in memory of the image to loadup\n" "- size: Size of the image to loadup\n"), + U_BOOT_CMD_MKENT(load_rsc, 5, 1, do_remoteproc_load_rsc_table, + "Load resource table address from remote processor provided image", + " [addr] [size]\n" + "- id: ID of the remote processor(see 'list' cmd)\n" + "- addr: Address in memory of the image\n" + "- size: Size of the image\n"), U_BOOT_CMD_MKENT(start, 1, 1, do_remoteproc_wrapper, "Start remote processor", "id - ID of the remote processor (see 'list' cmd)\n"), @@ -272,8 +328,10 @@ U_BOOT_CMD(rproc, 5, 1, do_remoteproc, "\n\tSubcommands:\n" "\tinit - Enumerate and initalize the remote processors\n" "\tlist - list available remote processors\n" - "\tload [addr] [size]- Load the remote processor with binary\n" + "\tload [addr] [size]- Load the remote processor with\n" "\t image stored at address [addr] in memory\n" + "\tload_rsc [addr] [size]- Load resource table from remote\n" + "\t processor provided image at address [addr]\n" "\tstart - Start the remote processor(must be loaded)\n" "\tstop - Stop the remote processor\n" "\treset - Reset the remote processor\n" diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c index 0d551141e0dd..26b41b4c4ee1 100644 --- a/cmd/usb_mass_storage.c +++ b/cmd/usb_mass_storage.c @@ -14,6 +14,7 @@ #include #include #include +#include static int ums_read_sector(struct ums *ums_dev, ulong start, lbaint_t blkcnt, void *buf) @@ -226,6 +227,8 @@ static int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag, rc = CMD_RET_SUCCESS; goto cleanup_register; } + + WATCHDOG_RESET(); } cleanup_register: diff --git a/common/Makefile b/common/Makefile index a2388364d9f9..336bed7ffb46 100644 --- a/common/Makefile +++ b/common/Makefile @@ -116,6 +116,7 @@ endif obj-y += cli.o obj-$(CONFIG_FSL_DDR_INTERACTIVE) += cli_simple.o cli_readline.o +obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += cli_simple.o cli_readline.o obj-$(CONFIG_DFU_OVER_USB) += dfu.o obj-y += command.o obj-$(CONFIG_$(SPL_)LOG) += log.o diff --git a/common/board_f.c b/common/board_f.c index afafec5e4d02..59745d5bf704 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -92,7 +92,7 @@ static int init_func_watchdog_init(void) (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ - defined(CONFIG_IMX_WATCHDOG)) + defined(CONFIG_IMX_WATCHDOG) || defined(CONFIG_STM32MP_WATCHDOG)) hw_watchdog_init(); puts(" Watchdog enabled\n"); # endif @@ -434,7 +434,6 @@ static int reserve_uboot(void) debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, gd->relocaddr); } - gd->start_addr_sp = gd->relocaddr; return 0; diff --git a/common/image.c b/common/image.c index 1c3a7720cbc8..6ace71f61bcc 100644 --- a/common/image.c +++ b/common/image.c @@ -166,6 +166,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" }, { IH_TYPE_PMMC, "pmmc", "TI Power Management Micro-Controller Firmware",}, { IH_TYPE_STM32IMAGE, "stm32image", "STMicroelectronics STM32 Image" }, + { IH_TYPE_STM32COPRO, "stm32copro", "STMicroelectronics STM32 Coprocessor Image"}, { -1, "", "", }, }; diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index 8cd4830a39b8..3cefc9a32703 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -78,11 +78,18 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, /* * Load U-Boot image from SPI flash into RAM */ - +#ifdef CONFIG_DM_SPI_FLASH + /* In DM mode defaults will be taken from DT */ + flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, + CONFIG_SF_DEFAULT_CS, + 0, + 0); +#else flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); +#endif if (!flash) { puts("SPI probe failed.\n"); return -ENODEV; diff --git a/common/usb.c b/common/usb.c index 78178c54c89c..239b10461b04 100644 --- a/common/usb.c +++ b/common/usb.c @@ -233,6 +233,8 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, request, requesttype, value, index, size); dev->status = USB_ST_NOT_PROC; /*not yet processed */ + mdelay(5); + err = submit_control_msg(dev, pipe, data, size, setup_packet); if (err < 0) return err; diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 5a744f47917c..587e2aae0d1b 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -215,3 +215,5 @@ CONFIG_UT_TIME=y CONFIG_UT_DM=y CONFIG_UT_ENV=y CONFIG_UT_OVERLAY=y +CONFIG_DM_HWSPINLOCK=y +CONFIG_HWSPINLOCK_SANDBOX=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 3bf75380890b..ad3424e844f9 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -1,14 +1,18 @@ 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 +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI_SUPPORT=y +# CONFIG_ARMV7_VIRT is not set CONFIG_DISTRO_DEFAULTS=y -CONFIG_NR_DRAM_BANKS=1 +CONFIG_FIT=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3 CONFIG_SPL_I2C_SUPPORT=y +CONFIG_SPL_MTD_SUPPORT=y CONFIG_SPL_POWER_SUPPORT=y CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set @@ -18,48 +22,97 @@ 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 CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SF=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_BMP=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 +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_UBI=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 CONFIG_SYS_I2C_STM32F7=y CONFIG_LED=y CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_STM32_IPCC=y CONFIG_DM_MMC=y CONFIG_STM32_SDMMC2=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_STM32_FMC2=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_DWC_ETH_QOS=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_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_STM32MP1_DDR_INTERACTIVE=y +CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_SERIAL_RX_BUFFER=y -CONFIG_STM32_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_QSPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_GENERIC=y -CONFIG_USB_DWC2=y CONFIG_USB_STORAGE=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 +CONFIG_DM_VIDEO=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y +CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y +CONFIG_VIDEO_STM32=y +CONFIG_VIDEO_STM32_DSI=y +CONFIG_VIDEO_STM32_MAX_XRES=1280 +CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_STM32MP_WATCHDOG=y +CONFIG_FDT_FIXUP_PARTITIONS=y +# CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig new file mode 100644 index 000000000000..a24727c8d624 --- /dev/null +++ b/configs/stm32mp15_optee_defconfig @@ -0,0 +1,105 @@ +CONFIG_ARM=y +CONFIG_ARCH_STM32MP=y +CONFIG_SYS_MALLOC_F_LEN=0x3000 +CONFIG_TARGET_STM32MP1=y +CONFIG_STM32MP1_OPTEE=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +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_MEMTEST=y +CONFIG_CMD_ADC=y +CONFIG_CMD_CLK=y +CONFIG_CMD_DFU=y +CONFIG_CMD_FUSE=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_BMP=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 +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_UBI=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 +CONFIG_SYS_I2C_STM32F7=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_STM32_IPCC=y +CONFIG_DM_MMC=y +CONFIG_STM32_SDMMC2=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_STM32_FMC2=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_DWC_ETH_QOS=y +CONFIG_PHY=y +CONFIG_PHY_STM32_USBPHYC=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_STMFX=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_STPMIC1=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_DM_REGULATOR_STM32_VREFBUF=y +CONFIG_DM_REGULATOR_STPMIC1=y +CONFIG_REMOTEPROC_STM32_COPRO=y +CONFIG_SERIAL_RX_BUFFER=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_QSPI=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_STORAGE=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_DM_VIDEO=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y +CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y +CONFIG_VIDEO_STM32=y +CONFIG_VIDEO_STM32_DSI=y +CONFIG_VIDEO_STM32_MAX_XRES=1280 +CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_STM32MP_WATCHDOG=y +CONFIG_FDT_FIXUP_PARTITIONS=y +# CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig new file mode 100644 index 000000000000..e41506ba9c45 --- /dev/null +++ b/configs/stm32mp15_trusted_defconfig @@ -0,0 +1,104 @@ +CONFIG_ARM=y +CONFIG_ARCH_STM32MP=y +CONFIG_SYS_MALLOC_F_LEN=0x3000 +CONFIG_TARGET_STM32MP1=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +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_MEMTEST=y +CONFIG_CMD_ADC=y +CONFIG_CMD_CLK=y +CONFIG_CMD_DFU=y +CONFIG_CMD_FUSE=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_BMP=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 +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_UBI=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 +CONFIG_SYS_I2C_STM32F7=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_STM32_IPCC=y +CONFIG_DM_MMC=y +CONFIG_STM32_SDMMC2=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_STM32_FMC2=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_DWC_ETH_QOS=y +CONFIG_PHY=y +CONFIG_PHY_STM32_USBPHYC=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_STMFX=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_STPMIC1=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_DM_REGULATOR_STM32_VREFBUF=y +CONFIG_DM_REGULATOR_STPMIC1=y +CONFIG_REMOTEPROC_STM32_COPRO=y +CONFIG_SERIAL_RX_BUFFER=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_QSPI=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_STORAGE=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_DM_VIDEO=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y +CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y +CONFIG_VIDEO_STM32=y +CONFIG_VIDEO_STM32_DSI=y +CONFIG_VIDEO_STM32_MAX_XRES=1280 +CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_STM32MP_WATCHDOG=y +CONFIG_FDT_FIXUP_PARTITIONS=y +# CONFIG_EFI_LOADER is not set diff --git a/doc/device-tree-bindings/arm/stm32.txt b/doc/device-tree-bindings/arm/stm32.txt new file mode 100644 index 000000000000..a871a7809833 --- /dev/null +++ b/doc/device-tree-bindings/arm/stm32.txt @@ -0,0 +1,17 @@ +STMicroelectronics STM32 Platforms Device Tree Bindings + +Each device tree must specify which STM32 SoC it uses, +using one of the following compatible strings: + + st,stm32f429 + st,stm32f469 + st,stm32f746 + st,stm32h743 + st,stm32mp157 + +Required nodes: + +- syscon: some subnode of the STM32 SoC node must be a + system controller node pointing to the control registers, + with the compatible string set to one of these tuples: + "st,stm32-syscfg", "syscon" diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt index 0532d815dae3..b240121d2ac9 100644 --- a/doc/device-tree-bindings/clock/st,stm32-rcc.txt +++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt @@ -10,6 +10,7 @@ Required properties: - compatible: Should be: "st,stm32f42xx-rcc" "st,stm32f469-rcc" + "st,stm32f746-rcc" - reg: should be register base and length as documented in the datasheet - #reset-cells: 1, see below @@ -17,6 +18,9 @@ Required properties: property, containing a phandle to the clock device node, an index selecting between gated clocks and other clocks and an index specifying the clock to use. +- clocks: External oscillator clock phandle + - high speed external clock signal (HSE) + - external I2S clock (I2S_CKIN) Example: @@ -25,6 +29,7 @@ Example: #clock-cells = <2> compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; reg = <0x40023800 0x400>; + clocks = <&clk_hse>, <&clk_i2s_ckin>; }; Specifying gated clocks @@ -66,6 +71,38 @@ The secondary index is bound with the following magic numbers: 0 SYSTICK 1 FCLK + 2 CLK_LSI (low-power clock source) + 3 CLK_LSE (generated from a 32.768 kHz low-speed external + crystal or ceramic resonator) + 4 CLK_HSE_RTC (HSE division factor for RTC clock) + 5 CLK_RTC (real-time clock) + 6 PLL_VCO_I2S (vco frequency of I2S pll) + 7 PLL_VCO_SAI (vco frequency of SAI pll) + 8 CLK_LCD (LCD-TFT) + 9 CLK_I2S (I2S clocks) + 10 CLK_SAI1 (audio clocks) + 11 CLK_SAI2 + 12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor) + 13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor) + + 14 CLK_HSI (Internal ocscillator clock) + 15 CLK_SYSCLK (System Clock) + 16 CLK_HDMI_CEC (HDMI-CEC clock) + 17 CLK_SPDIF (SPDIF-Rx clock) + 18 CLK_USART1 (U(s)arts clocks) + 19 CLK_USART2 + 20 CLK_USART3 + 21 CLK_UART4 + 22 CLK_UART5 + 23 CLK_USART6 + 24 CLK_UART7 + 25 CLK_UART8 + 26 CLK_I2C1 (I2S clocks) + 27 CLK_I2C2 + 28 CLK_I2C3 + 29 CLK_I2C4 + 30 CLK_LPTIMER (LPTimer1 clock) +) Example: diff --git a/doc/device-tree-bindings/clock/st,stm32mp1-rcc.txt b/doc/device-tree-bindings/clock/st,stm32mp1-rcc.txt new file mode 100644 index 000000000000..fb9495ea582c --- /dev/null +++ b/doc/device-tree-bindings/clock/st,stm32mp1-rcc.txt @@ -0,0 +1,60 @@ +STMicroelectronics STM32 Peripheral Reset Clock Controller +========================================================== + +The RCC IP is both a reset and a clock controller. + +RCC makes also power management (resume/supend and wakeup interrupt). + +Please also refer to reset.txt for common reset controller binding usage. + +Please also refer to clock-bindings.txt for common clock controller +binding usage. + + +Required properties: +- compatible: "st,stm32mp1-rcc", "syscon" +- reg: should be register base and length as documented in the datasheet +- #clock-cells: 1, device nodes should specify the clock in their + "clocks" property, containing a phandle to the clock device node, + an index specifying the clock to use. +- #reset-cells: Shall be 1 +- interrupts: Should contain a general interrupt line and a interrupt line + to the wake-up of processor (CSTOP). + +Example: + rcc: rcc@50000000 { + compatible = "st,stm32mp1-rcc", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + interrupts = , + ; + }; + +Specifying clocks +================= + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/stm32mp1-clks.h header and can be used in device +tree sources. + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. + +For example on STM32MP1, for LTDC reset: + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset + = 0x180 / 4 * 32 + 0 = 3072 + +The list of valid indices for STM32MP1 is available in: +include/dt-bindings/reset-controller/stm32mp1-resets.h + +This file implements defines like: +#define LTDC_R 3072 diff --git a/doc/device-tree-bindings/i2c/i2c-stm32.txt b/doc/device-tree-bindings/i2c/i2c-stm32.txt index df03743ace53..352dba530655 100644 --- a/doc/device-tree-bindings/i2c/i2c-stm32.txt +++ b/doc/device-tree-bindings/i2c/i2c-stm32.txt @@ -1,30 +1,102 @@ -* I2C controller embedded in STMicroelectronis STM32 platforms +* I2C controller embedded in STMicroelectronics STM32 I2C platform Required properties : -- compatible : Must be "st,stm32f7-i2c" +- compatible : Must be one of the following + - "st,stm32f4-i2c" + - "st,stm32f7-i2c" - reg : Offset and length of the register set for the device -- resets: Must contain the phandle to the reset controller -- clocks: Must contain the input clock of the I2C instance +- interrupts : Must contain the interrupt id for I2C event and then the + interrupt id for I2C error. +- resets: Must contain the phandle to the reset controller. +- clocks: Must contain the input clock of the I2C instance. - A pinctrl state named "default" must be defined to set pins in mode of - operation for I2C transfer + operation for I2C transfer. An optional pinctrl state named "sleep" has to + be defined as well as to put I2C in low power mode in suspend mode. - #address-cells = <1>; - #size-cells = <0>; Optional properties : - clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, - the default 100 kHz frequency will be used. As only Normal, Fast and Fast+ - modes are implemented, possible values are 100000, 400000 and 1000000. + the default 100 kHz frequency will be used. + For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are + 100000 and 400000. + For STM32F7 SoC, Standard-mode, Fast-mode and Fast-mode Plus are supported, + possible values are 100000, 400000 and 1000000. +- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board + (default: 25) +- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board + (default: 10) + I2C Timings are derived from these 2 values +- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG + whether Fast Mode Plus speed is selected by slave. + 1st cell : phandle to syscfg + 2nd cell : register offset within SYSCFG + 3rd cell : register bitmask for FMP bit Example : - i2c1: i2c@40005400 { - compatible = "st,stm32f7-i2c"; + i2c@40005400 { + compatible = "st,stm32f4-i2c"; + #address-cells = <1>; + #size-cells = <0>; reg = <0x40005400 0x400>; - resets = <&rcc 181>; - clocks = <&clk_pclk1>; + interrupts = <31>, + <32>; + resets = <&rcc 277>; + clocks = <&rcc 0 149>; + pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - clock-frequency = <400000>; + }; + + i2c@40005400 { + compatible = "st,stm32f7-i2c"; #address-cells = <1>; #size-cells = <0>; + reg = <0x40005400 0x400>; + interrupts = <31>, + <32>; + resets = <&rcc STM32F7_APB1_RESET(I2C1)>; + clocks = <&rcc 1 CLK_I2C1>; + pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; + pinctrl-1 = <&i2c1_sda_pin_sleep>, <&i2c1_scl_pin_sleep>; + pinctrl-names = "default", "sleep"; + st,syscfg-fmp = <&syscfg 0x4 0x1>; + }; + +* I2C Devices + +An I2C device connected onto STM32 I2C controller must use a format described by +i2c.txt file. + +Required properties : +- compatible + Device driver compatible name +- reg + I2C slave addresses (see i2c.txt for more details) + +Optional properties : +- wakeup-source + device can be used as a wakeup source. Valid only if device is a + master. +- interrupt-names + should be set as "wakeup" if a dedicated wakeup source is used. + Imply "wakeup-source" property +- interrupts + defined dedicated IRQ wakeup source from controller. + + i2c@40005400 { + camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + }; + }; + + i2c@40005400 { + eeprom@64 { + compatible = "linux,slave-24c02"; + reg = <0x40000064>; + wakeup-source; + interrupt-names = "wakeup"; + interrupts-extended = <&exti 25 1>; + }; }; diff --git a/doc/device-tree-bindings/mfd/stpmic1.txt b/doc/device-tree-bindings/mfd/stpmic1.txt new file mode 100644 index 000000000000..eb4d692e605d --- /dev/null +++ b/doc/device-tree-bindings/mfd/stpmic1.txt @@ -0,0 +1,138 @@ +* STMicroelectronics STPMIC1 Power Management IC + +Required parent device properties: +- compatible: "st,stpmic1" +- reg: the I2C slave address for the stpmic1 chip +- interrupts-extended: interrupt lines to use: second irq is for wakeup. +- #interrupt-cells: should be 2. +- interrupt-controller: describes the STPMIC1 as an interrupt + controller (has its own domain). interrupt number are the following: + /* Interrupt Register 1 (0x50 for latch) */ + IT_SWOUT_R=0 + IT_SWOUT_F=1 + IT_VBUS_OTG_R=2 + IT_VBUS_OTG_F=3 + IT_WAKEUP_R=4 + IT_WAKEUP_F=5 + IT_PONKEY_R=6 + IT_PONKEY_F=7 + /* Interrupt Register 2 (0x51 for latch) */ + IT_OVP_BOOST=8 + IT_OCP_BOOST=9 + IT_OCP_SWOUT=10 + IT_OCP_OTG=11 + IT_CURLIM_BUCK4=12 + IT_CURLIM_BUCK3=13 + IT_CURLIM_BUCK2=14 + IT_CURLIM_BUCK1=15 + /* Interrupt Register 3 (0x52 for latch) */ + IT_SHORT_SWOUT=16 + IT_SHORT_SWOTG=17 + IT_CURLIM_LDO6=18 + IT_CURLIM_LDO5=19 + IT_CURLIM_LDO4=20 + IT_CURLIM_LDO3=21 + IT_CURLIM_LDO2=22 + IT_CURLIM_LDO1=23 + /* Interrupt Register 3 (0x52 for latch) */ + IT_SWIN_R=24 + IT_SWIN_F=25 + IT_RESERVED_1=26 + IT_RESERVED_2=27 + IT_VINLOW_R=28 + IT_VINLOW_F=29 + IT_TWARN_R=30 + IT_TWARN_F=31 + +Optional parent device properties: +- st,main_control_register: + -bit 1: Power cycling will be performed on turn OFF condition + -bit 2: PWRCTRL is functional + -bit 3: PWRCTRL active high +- st,pads_pull_register: + -bit 1: WAKEUP pull down is not active + -bit 2: PWRCTRL pull up is active + -bit 3: PWRCTRL pull down is active + -bit 4: WAKEUP detector is disabled +- st,vin_control_register: + -bit 0: VINLOW monitoring is enabled + -bit [1...3]: VINLOW rising threshold + 000 VINOK_f + 50mV + 001 VINOK_f + 100mV + 010 VINOK_f + 150mV + 011 VINOK_f + 200mV + 100 VINOK_f + 250mV + 101 VINOK_f + 300mV + 110 VINOK_f + 350mV + 111 VINOK_f + 400mV + -bit [4...5]: VINLOW hyst + 00 100mV + 01 200mV + 10 300mV + 11 400mV + -bit 6: SW_OUT detector is disabled + -bit 7: SW_IN detector is enabled. +- st,usb_control_register: + -bit 3: SW_OUT current limit + 0: 600mA + 1: 1.1A + -bit 4: VBUS_OTG discharge is enabled + -bit 5: SW_OUT discharge is enabled + -bit 6: VBUS_OTG detection is enabled + -bit 7: BOOST_OVP is disabled + + +stpmic1 consists is a varied group of sub-devices: + +Device Description +------ ------------ +stpmic1-onkey : On key +stpmic1-regulators : Regulators +stpmic1-wdt : Watchdog + +each sub-device bindings is be described in associated driver +documentation section. + +Example: + +pmic: stpmic1@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupts = <0 2>; + interrupts-extended = <&intc GIC_SPI 149 IRQ_TYPE_NONE>, + <&exti 55 1>; + st,version_status = <0x10>; + st,main_control_register=<0x0c>; + interrupt-controller; + #interrupt-cells = <2>; + onkey { + compatible = "st,stpmic1-onkey"; + interrupt-parent = <&pmic>; + interrupts = <7 0>,<6 1>; + st,onkey-pwroff-enabled; + st,onkey-press-seconds = <10>; + }; + + watchdog { + compatible = "st,stpmic1-wdt"; + }; + + regulators { + compatible = "st,stpmic1-regulators"; + + vdd_core: regulator@0 { + regulator-compatible = "buck1"; + regulator-name = "vdd_core"; + regulator-boot-on; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1200000>; + }; + vdd: regulator@1 { + regulator-compatible = "buck3"; + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-pull-down; + }; + }; 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 000000000000..68eebb65b043 --- /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 + +* NAND device bindings: + +Required properties: +- reg: describes the CS lines assigned to the NAND device. + +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>; + }; + }; diff --git a/doc/device-tree-bindings/mtd/stm32-quadspi.txt b/doc/device-tree-bindings/mtd/stm32-quadspi.txt new file mode 100644 index 000000000000..ddd18c135148 --- /dev/null +++ b/doc/device-tree-bindings/mtd/stm32-quadspi.txt @@ -0,0 +1,43 @@ +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI) + +Required properties: +- compatible: should be "st,stm32f469-qspi" +- reg: the first contains the register location and length. + the second contains the memory mapping address and length +- reg-names: should contain the reg names "qspi" "qspi_mm" +- interrupts: should contain the interrupt for the device +- clocks: the phandle of the clock needed by the QSPI controller +- A pinctrl must be defined to set pins in mode of operation for QSPI transfer + +Optional properties: +- resets: must contain the phandle to the reset controller. + +A spi flash must be a child of the nor_flash node and could have some +properties. Also see jedec,spi-nor.txt. + +Required properties: +- reg: chip-Select number (QSPI controller may connect 2 nor flashes) +- spi-max-frequency: max frequency of spi bus + +Optional property: +- spi-rx-bus-width: see ../spi/spi-bus.txt for the description + +Example: + +qspi: spi@a0001000 { + compatible = "st,stm32f469-qspi"; + reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = <91>; + resets = <&rcc STM32F4_AHB3_RESET(QSPI)>; + clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0>; + + flash@0 { + reg = <0>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; + ... + }; +}; diff --git a/doc/device-tree-bindings/net/snps,dwc-qos-ethernet.txt b/doc/device-tree-bindings/net/snps,dwc-qos-ethernet.txt index d93f71ce8346..21d27aa4c68c 100644 --- a/doc/device-tree-bindings/net/snps,dwc-qos-ethernet.txt +++ b/doc/device-tree-bindings/net/snps,dwc-qos-ethernet.txt @@ -1,5 +1,8 @@ * Synopsys DWC Ethernet QoS IP version 4.10 driver (GMAC) +This binding is deprecated, but it continues to be supported, but new +features should be preferably added to the stmmac binding document. + This binding supports the Synopsys Designware Ethernet QoS (Quality Of Service) IP block. The IP supports multiple options for bus type, clocking and reset structure, and feature list. Consequently, a number of properties and list diff --git a/doc/device-tree-bindings/net/stm32-dwmac.txt b/doc/device-tree-bindings/net/stm32-dwmac.txt new file mode 100644 index 000000000000..73773ec58ba4 --- /dev/null +++ b/doc/device-tree-bindings/net/stm32-dwmac.txt @@ -0,0 +1,62 @@ +STMicroelectronics STM32 / MCU DWMAC glue layer controller + +This file documents platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +The device node has following properties. + +Required properties: +- compatible: For MCU family should be "st,stm32-dwmac" to select glue, and + "snps,dwmac-3.50a" to select IP version. + For MPU family should be "st,stm32mp1-dwmac" to select + glue, and "snps,dwmac-4.20a" to select IP version. +- clocks: Must contain a phandle for each entry in clock-names. +- clock-names: Should be "stmmaceth" for the host clock. + Should be "mac-clk-tx" for the MAC TX clock. + Should be "mac-clk-rx" for the MAC RX clock. + For MPU family need to add also "ethstp" for power mode clock and, + "syscfg-clk" for SYSCFG clock. +- interrupt-names: Should contain a list of interrupt names corresponding to + the interrupts in the interrupts property, if available. + Should be "macirq" for the main MAC IRQ + Should be "eth_wake_irq" for the IT which wake up system +- st,syscon : Should be phandle/offset pair. The phandle to the syscon node which + encompases the glue register, and the offset of the control register. + +Optional properties: +- clock-names: For MPU family "mac-clk-ck" for PHY without quartz +- st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz +- st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz + + --------------------------------------------------------------------------------------- + | PHY_MODE | Normal | PHY wo crystal| PHY wo crystal |No 125Mhz from PHY| + | | | 25MHz | 50MHz | | + --------------------------------------------------------------------------------------- + | MII | - | eth-ck | n/a | n/a | + | | | | | | + --------------------------------------------------------------------------------------- + | GMII | - | eth-ck | n/a | n/a | + | | | | | | + --------------------------------------------------------------------------------------- + | RGMII | - | eth-ck | n/a | eth-ck (no pin) | + | | | | | st,eth_clk_sel | + --------------------------------------------------------------------------------------- + | RMII | - | eth-ck | eth-ck | n/a | + | | | | st,eth_ref_clk_sel | | + --------------------------------------------------------------------------------------- + +Example: + + ethernet@40028000 { + compatible = "st,stm32-dwmac", "snps,dwmac-3.50a"; + reg = <0x40028000 0x8000>; + reg-names = "stmmaceth"; + interrupts = <0 61 0>, <0 62 0>; + interrupt-names = "macirq", "eth_wake_irq"; + clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx"; + clocks = <&rcc 0 25>, <&rcc 0 26>, <&rcc 0 27>; + st,syscon = <&syscfg 0x4>; + snps,pbl = <8>; + snps,mixed-burst; + dma-ranges; + }; diff --git a/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt b/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt index 725ae71ae653..cc44bf46c245 100644 --- a/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt +++ b/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt @@ -23,8 +23,12 @@ Required properties: - compatible: must be "st,stm32mp1-usbphyc" - reg: address and length of the usb phy control register set - clocks: phandle + clock specifier for the PLL phy clock +- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY +- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY +- vdd3v3-supply: phandle to the regulator providing 3V3 power to the PHY - #address-cells: number of address cells for phys sub-nodes, must be <1> - #size-cells: number of size cells for phys sub-nodes, must be <0> +- #clock-cells: number of clock cells for ck_usbo_48m consumer, must be <0> Optional properties: - assigned-clocks: phandle + clock specifier for the PLL phy clock @@ -34,40 +38,79 @@ Optional properties: Required nodes: one sub-node per port the controller provides. Phy sub-nodes -============== +============= Required properties: - reg: phy port index -- phy-supply: phandle to the regulator providing 3V3 power to the PHY, - see phy-bindings.txt in the same directory. -- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY -- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY - #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY port#1 and must be <1> for PHY port#2, to select USB controller +Optional properties: +- st,phy-tuning : phandle to the usb phy tuning node, see Phy tuning node below + +Phy tuning node +=============== + +It may be necessary to adjust the phy settings to compensate parasitics, which +can be due to USB connector/receptacle, routing, ESD protection component, ... + +Here is the list of all optional parameters to tune the interface of the phy +(HS for High-Speed, FS for Full-Speed, LS for Low-Speed) + +Optional properties: +- st,current-boost: <1> current boosting of 1mA + <2> current boosting of 2mA +- st,no-lsfs-fb-cap: disables the LS/FS feedback capacitor +- st,hs-slew-ctrl: slows the HS driver slew rate by 10% +- st,hs-dc-level: <0> decreases the HS driver DC level by 5 to 7mV + <1> increases the HS driver DC level by 5 to 7mV + <2> increases the HS driver DC level by 10 to 14mV +- st,fs-rftime-tuning: enables the FS rise/fall tuning option +- st,hs-rftime-reduction: enables the HS rise/fall reduction feature +- st,hs-current-trim: controls HS driver current trimming for choke +- st,hs-impedance-trim: controls HS driver impedance tuning for choke +- st,squelch-level: adjusts the squelch DC threshold value +- st,hs-rx-gain-eq: enables the HS Rx gain equalizer +- st,hs-rx-offset: adjusts the HS Rx offset +- st,no-hs-ftime-ctrl: disables the HS fall time control of single + ended signals during pre-emphasis +- st,no-lsfs-sc: disables the short circuit protection in LS/FS driver +- st,hs-tx-staggering: enables the basic staggering in HS Tx mode + Example: + usb_phy_tuning: usb-phy-tuning { + st,current-boost = <2>; + st,no-lfs-fb-cap; + st,hs-dc-level = <2>; + st,hs-rftime-reduction; + st,hs-current-trim = <5>; + st,hs-impedance-trim = <0>; + st,squelch-level = <1>; + st,no-hs-ftime-ctrl; + st,hs-tx-staggering; + }; + usbphyc: usb-phy@5a006000 { compatible = "st,stm32mp1-usbphyc"; reg = <0x5a006000 0x1000>; clocks = <&rcc_clk USBPHY_K>; resets = <&rcc_rst USBPHY_R>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18>; + vdd3v3-supply = <&vdd_usb>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <0>; usbphyc_port0: usb-phy@0 { reg = <0>; - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18> #phy-cells = <0>; }; usbphyc_port1: usb-phy@1 { reg = <1>; - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18> #phy-cells = <1>; + st,phy-tuning = <&usb_phy_tuning>; }; }; diff --git a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt index c41ae91f7ab0..1a5d1e2ce642 100644 --- a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt +++ b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt @@ -8,8 +8,13 @@ controllers onto these pads. Pin controller node: Required properies: - compatible: value should be one of the following: - (a) "st,stm32f429-pinctrl" - (b) "st,stm32f746-pinctrl" + "st,stm32f429-pinctrl" + "st,stm32f469-pinctrl" + "st,stm32f746-pinctrl" + "st,stm32f769-pinctrl" + "st,stm32h743-pinctrl" + "st,stm32mp157-pinctrl" + "st,stm32mp157-z-pinctrl" - #address-cells: The value of this property must be 1 - #size-cells : The value of this property must be 1 - ranges : defines mapping between pin controller node (parent) to @@ -32,13 +37,30 @@ Required properties: Optional properties: - reset: : Reference to the reset controller - - interrupt-parent: phandle of the interrupt parent to which the external - GPIO interrupts are forwarded to. - - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node - which includes IRQ mux selection register, and the offset of the IRQ mux - selection register. + - st,syscfg: Should be phandle/offset/mask. + -The phandle to the syscon node which includes IRQ mux selection register. + -The offset of the IRQ mux selection register + -The field mask of IRQ mux, needed if different of 0xf. + - gpio-ranges: Define a dedicated mapping between a pin-controller and + a gpio controller. Format is <&phandle a b c> with: + -(phandle): phandle of pin-controller. + -(a): gpio base offset in range. + -(b): pin base offset in range. + -(c): gpio count in range + This entry has to be used either if there are holes inside a bank: + GPIOB0/B1/B2/B14/B15 (see example 2) + or if banks are not contiguous: + GPIOA/B/C/E... + NOTE: If "gpio-ranges" is used for a gpio controller, all gpio-controller + have to use a "gpio-ranges" entry. + More details in Documentation/devicetree/bindings/gpio/gpio.txt. + - st,bank-ioport: should correspond to the EXTI IOport selection (EXTI line + used to select GPIOs as interrupts). + - st,package: Indicates the SOC package used. + More details in include/dt-bindings/pinctrl/stm32-pinfunc.h + - hwlocks: reference to a phandle of a hardware spinlock provider node. -Example: +Example 1: #include ... @@ -60,6 +82,43 @@ Example: pin-functions nodes follow... }; +Example 2: +#include +... + + pinctrl: pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32f429-pinctrl"; + ranges = <0 0x40020000 0x3000>; + pins-are-numbered; + + gpioa: gpio@40020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOA"; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@40020400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOB"; + ngpios = 4; + gpio-ranges = <&pinctrl 0 16 3>, + <&pinctrl 14 30 2>; + }; + + + ... + pin-functions nodes follow... + }; + + Contents of function subnode node: ---------------------------------- Subnode format @@ -83,14 +142,31 @@ Required properties: - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11) - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15) - function: The function number, can be: - * 0 : GPIO IN + * 0 : GPIO * 1 : Alternate Function 0 * 2 : Alternate Function 1 * 3 : Alternate Function 2 * ... * 16 : Alternate Function 15 * 17 : Analog - * 18 : GPIO OUT + + To simplify the usage, macro is available to generate "pinmux" field. + This macro is available here: + - include/dt-bindings/pinctrl/stm32-pinfunc.h + + Some examples of using macro: + /* GPIO A9 set as alernate function 2 */ + ... { + pinmux = ; + }; + /* GPIO A9 set as GPIO */ + ... { + pinmux = ; + }; + /* GPIO A9 set as analog */ + ... { + pinmux = ; + }; Optional properties: - GENERIC_PINCONFIG: is the generic pinconfig options to use. @@ -114,13 +190,13 @@ pin-controller { ... usart1_pins_a: usart1@0 { pins1 { - pinmux = ; + pinmux = ; bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { - pinmux = ; + pinmux = ; bias-disable; }; }; @@ -129,5 +205,4 @@ pin-controller { &usart1 { pinctrl-0 = <&usart1_pins_a>; pinctrl-names = "default"; - status = "okay"; }; diff --git a/doc/device-tree-bindings/power/st,stm32mp1-pwr.txt b/doc/device-tree-bindings/power/st,stm32mp1-pwr.txt new file mode 100644 index 000000000000..ccdaffc70e7a --- /dev/null +++ b/doc/device-tree-bindings/power/st,stm32mp1-pwr.txt @@ -0,0 +1,52 @@ +STMicroelectronics STM32MP1 Power Management Controller +======================================================= + +The PWR IP is responsible for handling the power related resources such as +clocks, power supplies and resets. It provides 6 wake-up pins that are handled +by an interrupt-controller. Wake-up pin can be used to wake-up from STANDBY SoC state. + +Required properties: +- compatible should be: "st,stm32mp1-pwr" +- reg: should be register base and length as documented in the + datasheet +- interrupts: contains the reference to the gic wake-up pin interrupt +- interrupt-controller; Enable interrupt controller for wake-up pins. +- #interrupt-cells = <3> + +Optional Properties: +- pwr-supply: main soc power supply + +Interrupt consumers have to specify 3 cells: + - cell 1: wake-up pin id from 0 to 5 + - cell 2: IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_RISING + - cell 3: Pull config: 0 = No Pull, 1=Pull Up, 2=Pull Down + + +Example: + + pwr: pwr@50001000 { + compatible = "st,stm32mp1-pwr", "simple-mfd"; + reg = <0x50001000 0x400>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + + pwr-supply = <&vdd>; + }; + + +Example of interrupt user: +gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@4 { + label = "WakeUp4"; + linux,code = ; + interrupt-parent = <&pwr>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING 1>; + status = "okay"; + wakeup-source; + }; +}; diff --git a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt index 3028636c4511..e5b1bb5e04f5 100644 --- a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt +++ b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt @@ -16,7 +16,7 @@ included in STM32 Cube tool info attributes: ---------------- - st,mem-name : name for DDR configuration, simple string for information -- st,mem-speed : DDR expected speed for the setting in MHz +- st,mem-speed : DDR expected speed for the setting in kHz - st,mem-size : DDR mem size in byte @@ -173,7 +173,7 @@ Example: "ddrphycapb"; st,mem-name = "DDR3 2x4Gb 533MHz"; - st,mem-speed = <533>; + st,mem-speed = <533000>; st,mem-size = <0x40000000>; st,ctl-reg = < diff --git a/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt new file mode 100644 index 000000000000..cee27d52edcd --- /dev/null +++ b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt @@ -0,0 +1,31 @@ +STM32MP1 POWER Regulators +------------------------- + +Required properties: +- compatible: Must be "st,stm32mp1,pwr-reg" +- list of child nodes that specify the regulator + initialization data for defined regulators. The definition for each of + these nodes is defined using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. +- st,tzcr: syscon of Trust Zone Configuration Register. Usefull to know if we + are in secure mode. + st,tzcr = & ; + +Example: + + pwr-regulators@c { + compatible = "st,stm32mp1,pwr-reg"; + st,tzcr = <&rcc 0x0 0x1>; + + reg11: reg11 { + regulator-name = "reg11"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + reg18: reg18 { + regulator-name = "reg18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; diff --git a/doc/device-tree-bindings/serial/st,stm32-usart.txt b/doc/device-tree-bindings/serial/st,stm32-usart.txt new file mode 100644 index 000000000000..08b499045a38 --- /dev/null +++ b/doc/device-tree-bindings/serial/st,stm32-usart.txt @@ -0,0 +1,88 @@ +* STMicroelectronics STM32 USART + +Required properties: +- compatible: can be either: + - "st,stm32-uart", + - "st,stm32f7-uart", + - "st,stm32h7-uart". + depending is compatible with stm32(f4), stm32f7 or stm32h7. +- reg: The address and length of the peripheral registers space +- interrupts: + - The interrupt line for the USART instance, + - An optional wake-up interrupt. +- interrupt-names: Contains "event" for the USART interrupt line. +- clocks: The input clock of the USART instance + +Optional properties: +- resets: Must contain the phandle to the reset controller. +- pinctrl-names: Set to "default". An additional "sleep" state can be defined + to set pins in sleep state when in low power. In case the device is used as + a wakeup source, "idle" state is defined in order to keep RX pin active. + For a console device, an optional state "no_console_suspend" can be defined + to enable console messages during suspend. Typically, "no_console_suspend" and + "default" states can refer to the same pin configuration. +- pinctrl-n: Phandle(s) pointing to pin configuration nodes. + For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt +- st,hw-flow-ctrl: bool flag to enable hardware flow control. +- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: see rs485.txt. +- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt +- dma-names: "rx" and/or "tx" +- wakeup-source: bool flag to indicate this device has wakeup capabilities +- interrupt-names : Should contain "wakeup" if optional wake-up interrupt is + used. + +Note for dma using: +- "tx" dma can be used without any constraint since it uses single +dma transfers. +- "rx" dma using requires some attention: + 1) if you cannot anticipate the length of your received packets + and if your usart device embeds an internal fifo, then DON'T use + dma mode. + 2) if you enable dma mode WITHOUT mdma intermediate copy (cf. + stm32-dma.txt), then the availability of the received data will + depend on the dma driver policy and it may be delayed until dma + internal fifo is full. The usart driver will see this checking + the dma residue when rx interrupt (RXNE or RTO) occurs. + 3) if you enable dma mode WITH mdma intermediate copy (cf. + stm32-dma.txt) then the usart driver will never see the dma + residue becoming smaller than RX_BUF_P but it will get its + rx dma complete callback called when the cyclic transfer period + (RX_BUF_P) is reached. +The three possibilities above are ordered from the most cpu time +consuming one to the least one. The counterpart of this optimisation +is the reception granularity achievable by the usart driver, from +one byte up to RX_BUF_P. + +Examples: +usart4: serial@40004c00 { + compatible = "st,stm32-uart"; + reg = <0x40004c00 0x400>; + interrupts = <52>; + clocks = <&clk_pclk1>; + pinctrl-names = "default", "sleep", "idle", "no_console_suspend"; + pinctrl-0 = <&pinctrl_usart4>; + pinctrl-1 = <&pinctrl_usart4_sleep>; + pinctrl-2 = <&pinctrl_usart4_idle>; + pinctrl-3 = <&pinctrl_usart4>; +}; + +usart2: serial@40004400 { + compatible = "st,stm32-uart"; + reg = <0x40004400 0x400>; + interrupts = <38>; + clocks = <&clk_pclk1>; + st,hw-flow-ctrl; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>; +}; + +usart1: serial@40011000 { + compatible = "st,stm32-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&rcc 0 164>; + dmas = <&dma2 2 4 0x414 0x0>, + <&dma2 7 4 0x414 0x0>; + dma-names = "rx", "tx"; +}; diff --git a/doc/device-tree-bindings/watchdog/st,stm32-iwdg.txt b/doc/device-tree-bindings/watchdog/st,stm32-iwdg.txt new file mode 100644 index 000000000000..d8f4430b0a13 --- /dev/null +++ b/doc/device-tree-bindings/watchdog/st,stm32-iwdg.txt @@ -0,0 +1,26 @@ +STM32 Independent WatchDoG (IWDG) +--------------------------------- + +Required properties: +- compatible: Should be either: + - "st,stm32-iwdg" + - "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "lsi", "pclk" for st,stm32mp1-iwdg + +Optional Properties: +- timeout-sec: Watchdog timeout value in seconds. + +Example: + +iwdg: watchdog@40003000 { + compatible = "st,stm32-iwdg"; + reg = <0x40003000 0x400>; + clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; diff --git a/drivers/Kconfig b/drivers/Kconfig index 927a2b87f6a7..7e6ca7cd3e2c 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -40,6 +40,8 @@ source "drivers/fpga/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/hwspinlock/Kconfig" + source "drivers/i2c/Kconfig" source "drivers/input/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index fb38b6754134..0ef56fb416c4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -111,4 +111,5 @@ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/ endif diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index 738c1eabdc34..27b2654e3e48 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,18 @@ int adc_data_mask(struct udevice *dev, unsigned int *data_mask) return 0; } +int adc_channel_mask(struct udevice *dev, unsigned int *channel_mask) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + + if (!uc_pdata) + return -ENOSYS; + + *channel_mask = uc_pdata->channel_mask; + + return 0; +} + int adc_stop(struct udevice *dev) { const struct adc_ops *ops = dev_get_driver_ops(dev); @@ -264,8 +277,13 @@ static int adc_vdd_platdata_update(struct udevice *dev) * will bind before its supply regulator device, then the below 'get' * will return an error. */ - if (!uc_pdata->vdd_supply) - return 0; + if (!uc_pdata->vdd_supply) { + /* Only get vdd_supply once */ + ret = device_get_supply_regulator(dev, "vdd-supply", + &uc_pdata->vdd_supply); + if (ret) + return ret; + } ret = regulator_get_value(uc_pdata->vdd_supply); if (ret < 0) @@ -281,8 +299,12 @@ static int adc_vss_platdata_update(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); int ret; - if (!uc_pdata->vss_supply) - return 0; + if (!uc_pdata->vss_supply) { + ret = device_get_supply_regulator(dev, "vss-supply", + &uc_pdata->vss_supply); + if (ret) + return ret; + } ret = regulator_get_value(uc_pdata->vss_supply); if (ret < 0) @@ -329,6 +351,30 @@ int adc_vss_value(struct udevice *dev, int *uV) return 0; } +int adc_raw_to_uV(struct udevice *dev, unsigned int raw, int *uV) +{ + unsigned int data_mask; + int ret, val, vref; + u64 raw64 = raw; + + ret = adc_vdd_value(dev, &vref); + if (ret) + return ret; + + if (!adc_vss_value(dev, &val)) + vref -= val; + + ret = adc_data_mask(dev, &data_mask); + if (ret) + return ret; + + raw64 *= vref; + do_div(raw64, data_mask); + *uV = raw64; + + return 0; +} + static int adc_vdd_platdata_set(struct udevice *dev) { struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 6a8c7b754fa1..79f834b77b1f 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -12,13 +12,19 @@ #include #include #include +#include +#include #include #include +DECLARE_GLOBAL_DATA_PTR; + +#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 @@ -104,6 +110,7 @@ #define RCC_MP_APB2ENSETR 0XA08 #define RCC_MP_APB3ENSETR 0xA10 #define RCC_MP_AHB2ENSETR 0xA18 +#define RCC_MP_AHB3ENSETR 0xA20 #define RCC_MP_AHB4ENSETR 0xA28 /* used for most of SELR register */ @@ -240,7 +247,6 @@ enum stm32mp1_parent_id { _LSI, _LSE, _I2S_CKIN, - _USB_PHY_48, NB_OSC, /* other parent source */ @@ -272,6 +278,7 @@ enum stm32mp1_parent_id { _CK_MPU, _CK_MCU, _DSI_PHY, + _USB_PHY_48, _PARENT_NB, _UNKNOWN_ID = 0xff, }; @@ -377,6 +384,7 @@ struct stm32mp1_clk_gate { u8 set_clr; u8 sel; u8 fixed; + bool secure; }; struct stm32mp1_clk_sel { @@ -421,6 +429,7 @@ struct stm32mp1_clk_priv { .set_clr = 0, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ + .secure = 0, \ } #define STM32MP1_CLK_F(off, b, idx, f) \ @@ -431,6 +440,7 @@ struct stm32mp1_clk_priv { .set_clr = 0, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ + .secure = 0, \ } #define STM32MP1_CLK_SET_CLR(off, b, idx, s) \ @@ -441,6 +451,7 @@ struct stm32mp1_clk_priv { .set_clr = 1, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ + .secure = 0, \ } #define STM32MP1_CLK_SET_CLR_F(off, b, idx, f) \ @@ -451,6 +462,18 @@ struct stm32mp1_clk_priv { .set_clr = 1, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ + .secure = 0, \ + } + +#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s) \ + { \ + .offset = (off), \ + .bit = (b), \ + .index = (idx), \ + .set_clr = 1, \ + .sel = (s), \ + .fixed = _UNKNOWN_ID, \ + .secure = 1, \ } #define STM32MP1_CLK_PARENT(idx, off, s, m, p) \ @@ -526,14 +549,17 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), + STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), + STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2), STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 5, ADC12_K, _ADC12_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB3ENSETR, 11, HSEM, _UNKNOWN_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB3ENSETR, 12, IPCC, _UNKNOWN_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), @@ -546,7 +572,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), + STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK, _ETH_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL), @@ -662,8 +688,8 @@ static const u8 stm32mp1_axi_div[8] = { 1, 2, 3, 4, 4, 4, 4, 4 }; -#ifdef DEBUG -static const char * const stm32mp1_clk_parent_name[_PARENT_NB] = { +static const __maybe_unused +char * const stm32mp1_clk_parent_name[_PARENT_NB] = { [_HSI] = "HSI", [_HSE] = "HSE", [_CSI] = "CSI", @@ -701,7 +727,8 @@ static const char * const stm32mp1_clk_parent_name[_PARENT_NB] = { [_DSI_PHY] = "DSI_PHY_PLL", }; -static const char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { +static const __maybe_unused +char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_I2C12_SEL] = "I2C12", [_I2C35_SEL] = "I2C35", [_I2C46_SEL] = "I2C46", @@ -720,7 +747,6 @@ static const char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", }; -#endif static const struct stm32mp1_clk_data stm32mp1_data = { .gate = stm32mp1_clk_gate, @@ -736,9 +762,6 @@ static ulong stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, int idx) return 0; } - debug("%s: clk id %d = %x : %ld kHz\n", __func__, idx, - (u32)priv->osc[idx], priv->osc[idx] / 1000); - return priv->osc[idx]; } @@ -839,8 +862,6 @@ static ulong pll_get_fref_ck(struct stm32mp1_clk_priv *priv, src = selr & RCC_SELR_SRC_MASK; refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]); - debug("PLL%d : selr=%x refclk = %d kHz\n", - pll_id, selr, (u32)(refclk / 1000)); return refclk; } @@ -865,9 +886,6 @@ static ulong pll_get_fvco(struct stm32mp1_clk_priv *priv, divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; - debug("PLL%d : cfgr1=%x fracr=%x DIVN=%d DIVM=%d\n", - pll_id, cfgr1, fracr, divn, divm); - refclk = pll_get_fref_ck(priv, pll_id); /* with FRACV : @@ -884,7 +902,6 @@ static ulong pll_get_fvco(struct stm32mp1_clk_priv *priv, } else { fvco = (ulong)(refclk * (divn + 1) / (divm + 1)); } - debug("PLL%d : %s = %ld\n", pll_id, __func__, fvco); return fvco; } @@ -897,17 +914,12 @@ static ulong stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, ulong dfout; u32 cfgr2; - debug("%s(%d, %d)\n", __func__, pll_id, div_id); if (div_id >= _DIV_NB) return 0; cfgr2 = readl(priv->base + pll[pll_id].pllxcfgr2); divy = (cfgr2 >> RCC_PLLNCFGR2_SHIFT(div_id)) & RCC_PLLNCFGR2_DIVX_MASK; - - debug("PLL%d : cfgr2=%x DIVY=%d\n", pll_id, cfgr2, divy); - dfout = pll_get_fvco(priv, pll_id) / (divy + 1); - debug(" => dfout = %d kHz\n", (u32)(dfout / 1000)); return dfout; } @@ -918,8 +930,8 @@ static ulong stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) ulong clock = 0; switch (p) { - case _CK_MPU: /* MPU sub system */ + case _CK_MPU: reg = readl(priv->base + RCC_MPCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MPCKSELR_HSI: @@ -1076,7 +1088,7 @@ static ulong stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) break; /* other */ case _USB_PHY_48: - clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48); + clock = 48000000; break; case _DSI_PHY: { @@ -1114,7 +1126,13 @@ static int stm32mp1_clk_enable(struct clk *clk) return i; if (gate[i].set_clr) - writel(BIT(gate[i].bit), priv->base + gate[i].offset); +#ifdef CONFIG_STM32MP1_TRUSTED + if (gate[i].secure) + stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE, + gate[i].offset, BIT(gate[i].bit)); + else +#endif /* CONFIG_STM32MP1_TRUSTED */ + writel(BIT(gate[i].bit), priv->base + gate[i].offset); else setbits_le32(priv->base + gate[i].offset, BIT(gate[i].bit)); @@ -1133,9 +1151,16 @@ static int stm32mp1_clk_disable(struct clk *clk) return i; if (gate[i].set_clr) - writel(BIT(gate[i].bit), - priv->base + gate[i].offset - + RCC_MP_ENCLRR_OFFSET); +#ifdef CONFIG_STM32MP1_TRUSTED + if (gate[i].secure) + stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE, + gate[i].offset + RCC_MP_ENCLRR_OFFSET, + BIT(gate[i].bit)); + else +#endif /* CONFIG_STM32MP1_TRUSTED */ + writel(BIT(gate[i].bit), + priv->base + gate[i].offset + + RCC_MP_ENCLRR_OFFSET); else clrbits_le32(priv->base + gate[i].offset, BIT(gate[i].bit)); @@ -1176,10 +1201,7 @@ static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset, static void stm32mp1_hs_ocs_set(int enable, fdt_addr_t rcc, u32 mask_on) { - if (enable) - setbits_le32(rcc + RCC_OCENSETR, mask_on); - else - setbits_le32(rcc + RCC_OCENCLRR, mask_on); + writel(mask_on, rcc + (enable ? RCC_OCENSETR : RCC_OCENCLRR)); } static int stm32mp1_osc_wait(int enable, fdt_addr_t rcc, u32 offset, @@ -1250,20 +1272,20 @@ static void stm32mp1_lsi_set(fdt_addr_t rcc, int enable) static void stm32mp1_hse_enable(fdt_addr_t rcc, int bypass, int digbyp, int css) { if (digbyp) - setbits_le32(rcc + RCC_OCENSETR, RCC_OCENR_DIGBYP); + writel(RCC_OCENR_DIGBYP, rcc + RCC_OCENSETR); if (bypass || digbyp) - setbits_le32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP); + writel(RCC_OCENR_HSEBYP, rcc + RCC_OCENSETR); stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON); stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY); if (css) - setbits_le32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON); + writel(RCC_OCENR_HSECSSON, rcc + RCC_OCENSETR); } static void stm32mp1_csi_set(fdt_addr_t rcc, int enable) { - stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION); + stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_CSION); stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY); } @@ -1439,6 +1461,71 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg) writel(pllxcsg, priv->base + pll[pll_id].pllxcsgr); } +static __maybe_unused int pll_set_rate(struct udevice *dev, + int pll_id, + int div_id, + unsigned long clk_rate) +{ + struct stm32mp1_clk_priv *priv = dev_get_priv(dev); + unsigned int pllcfg[PLLCFG_NB]; + ofnode plloff; + char name[12]; + const struct stm32mp1_clk_pll *pll = priv->data->pll; + enum stm32mp1_plltype type = pll[pll_id].plltype; + int divm, divn, divy; + int ret; + ulong fck_ref; + u32 fracv; + u64 value; + + if (div_id > _DIV_NB) + return -EINVAL; + + sprintf(name, "st,pll@%d", pll_id); + plloff = dev_read_subnode(dev, name); + if (!ofnode_valid(plloff)) + return -FDT_ERR_NOTFOUND; + + ret = ofnode_read_u32_array(plloff, "cfg", + pllcfg, PLLCFG_NB); + if (ret < 0) + return -FDT_ERR_NOTFOUND; + + fck_ref = pll_get_fref_ck(priv, pll_id); + + divm = pllcfg[PLLCFG_M]; + /* select output divider = 0: for _DIV_P, 1:_DIV_Q 2:_DIV_R */ + divy = pllcfg[PLLCFG_P + div_id]; + + /* For: PLL1 & PLL2 => VCO is * 2 but ck_pll_y is also / 2 + * So same final result than PLL2 et 4 + * with FRACV + * Fck_pll_y = Fck_ref * ((DIVN + 1) + FRACV / 2^13) + * / (DIVy + 1) * (DIVM + 1) + * value = (DIVN + 1) * 2^13 + FRACV / 2^13 + * = Fck_pll_y (DIVy + 1) * (DIVM + 1) * 2^13 / Fck_ref + */ + value = ((u64)clk_rate * (divy + 1) * (divm + 1)) << 13; + value = lldiv(value, fck_ref); + + divn = (value >> 13) - 1; + if (divn < DIVN_MIN || + divn > stm32mp1_pll[type].divn_max) { + pr_err("divn invalid = %d", divn); + return -EINVAL; + } + fracv = value - ((divn + 1) << 13); + pllcfg[PLLCFG_N] = divn; + + /* reconfigure PLL */ + pll_stop(priv, pll_id); + pll_config(priv, pll_id, pllcfg, fracv); + pll_start(priv, pll_id); + pll_output(priv, pll_id, pllcfg[PLLCFG_O]); + + return 0; +} + static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc) { u32 address = priv->base + (clksrc >> 4); @@ -1468,10 +1555,15 @@ static void stgen_config(struct stm32mp1_clk_priv *priv) rate = stm32mp1_clk_get(priv, p); if (cntfid0 != rate) { + u64 counter; + pr_debug("System Generic Counter (STGEN) update\n"); clrbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN); - writel(0x0, stgenc + STGENC_CNTCVL); - writel(0x0, stgenc + STGENC_CNTCVU); + counter = (u64)readl(stgenc + STGENC_CNTCVL); + counter |= ((u64)(readl(stgenc + STGENC_CNTCVU))) << 32; + counter = lldiv(counter * (u64)rate, cntfid0); + writel((u32)counter, stgenc + STGENC_CNTCVL); + writel((u32)(counter >> 32), stgenc + STGENC_CNTCVU); writel(rate, stgenc + STGENC_CNTFID0); setbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN); @@ -1479,9 +1571,6 @@ static void stgen_config(struct stm32mp1_clk_priv *priv) /* need to update gd->arch.timer_rate_hz with new frequency */ timer_init(); - pr_debug("gd->arch.timer_rate_hz = %x\n", - (u32)gd->arch.timer_rate_hz); - pr_debug("Tick = %x\n", (u32)(get_ticks())); } } @@ -1787,7 +1876,6 @@ static int pll_set_output_rate(struct udevice *dev, if (div > 128) div = 128; - debug("fvco = %ld, clk_rate = %ld, div=%d\n", fvco, clk_rate, div); /* stop the requested output */ clrbits_le32(pllxcr, 0x1 << div_id << RCC_PLLNCR_DIVEN_SHIFT); /* change divider */ @@ -1806,6 +1894,11 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate) int p; switch (clk->id) { +#if defined(STM32MP1_CLOCK_TREE_INIT) && \ + defined(CONFIG_STM32MP1_DDR_INTERACTIVE) + case DDRPHYC: + break; +#endif case LTDC_PX: case DSI_PX: break; @@ -1815,10 +1908,27 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate) } p = stm32mp1_clk_get_parent(priv, clk->id); +#ifdef DEBUG + debug("%s: parent = %d:%s\n", __func__, p, stm32mp1_clk_parent_name[p]); +#endif if (p < 0) return -EINVAL; switch (p) { +#if defined(STM32MP1_CLOCK_TREE_INIT) && \ + defined(CONFIG_STM32MP1_DDR_INTERACTIVE) + case _PLL2_R: /* DDRPHYC */ + { + /* only for change DDR clock in interactive mode */ + ulong result; + + set_clksrc(priv, CLK_AXI_HSI); + result = pll_set_rate(clk->dev, _PLL2, _DIV_R, clk_rate); + set_clksrc(priv, CLK_AXI_PLL2P); + return result; + } +#endif + case _PLL4_Q: /* for LTDC_PX and DSI_PX case */ return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate); @@ -1856,7 +1966,7 @@ static void stm32mp1_osc_init(struct udevice *dev) [_HSE] = "clk-hse", [_CSI] = "clk-csi", [_I2S_CKIN] = "i2s_ckin", - [_USB_PHY_48] = "ck_usbo_48m"}; + }; for (i = 0; i < NB_OSC; i++) { stm32mp1_osc_clk_init(name[i], priv, i); @@ -1864,6 +1974,54 @@ static void stm32mp1_osc_init(struct udevice *dev) } } +static void __maybe_unused stm32mp1_clk_dump(struct stm32mp1_clk_priv *priv) +{ + char buf[32]; + int i, s, p; + + printf("Clocks:\n"); + for (i = 0; i < _PARENT_NB; i++) { + printf("- %s : %s MHz\n", + stm32mp1_clk_parent_name[i], + strmhz(buf, stm32mp1_clk_get(priv, i))); + } + printf("Source Clocks:\n"); + for (i = 0; i < _PARENT_SEL_NB; i++) { + p = (readl(priv->base + priv->data->sel[i].offset) >> + priv->data->sel[i].src) & priv->data->sel[i].msk; + if (p < priv->data->sel[i].nb_parent) { + s = priv->data->sel[i].parent[p]; + printf("- %s(%d) => parent %s(%d)\n", + stm32mp1_clk_parent_sel_name[i], i, + stm32mp1_clk_parent_name[s], s); + } else { + printf("- %s(%d) => parent index %d is invalid\n", + stm32mp1_clk_parent_sel_name[i], i, p); + } + } +} + +#ifdef CONFIG_CMD_CLK +int soc_clk_dump(void) +{ + struct udevice *dev; + struct stm32mp1_clk_priv *priv; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_CLK, + DM_GET_DRIVER(stm32mp1_clock), + &dev); + if (ret) + return ret; + + priv = dev_get_priv(dev); + + stm32mp1_clk_dump(priv); + + return 0; +} +#endif + static int stm32mp1_clk_probe(struct udevice *dev) { int result = 0; @@ -1887,6 +2045,33 @@ static int stm32mp1_clk_probe(struct udevice *dev) result = stm32mp1_clktree(dev); #endif +#ifndef CONFIG_SPL_BUILD +#if defined(DEBUG) + /* display debug information for probe after relocation */ + if (gd->flags & GD_FLG_RELOC) + stm32mp1_clk_dump(priv); +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) + if (gd->flags & GD_FLG_RELOC) { + char buf[32]; + + printf("Clocks:\n"); + printf("- MPU : %s MHz\n", + strmhz(buf, stm32mp1_clk_get(priv, _CK_MPU))); + printf("- MCU : %s MHz\n", + strmhz(buf, stm32mp1_clk_get(priv, _CK_MCU))); + printf("- AXI : %s MHz\n", + strmhz(buf, stm32mp1_clk_get(priv, _ACLK))); + printf("- PER : %s MHz\n", + strmhz(buf, stm32mp1_clk_get(priv, _CK_PER))); + /* DDRPHYC father */ + printf("- DDR : %s MHz\n", + strmhz(buf, stm32mp1_clk_get(priv, _PLL2_R))); + } +#endif /* CONFIG_DISPLAY_CPUINFO */ +#endif + return result; } diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index 303e166a69c1..85d827497a9b 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -123,52 +123,49 @@ U_BOOT_DRIVER(generic_syscon) = { * The syscon node can be bound to another driver, but still works * as a syscon provider. */ -static LIST_HEAD(syscon_list); - -struct syscon { - ofnode node; - struct regmap *regmap; - struct list_head list; -}; - -static struct syscon *of_syscon_register(ofnode node) +struct regmap *syscon_node_to_regmap(ofnode node) { - struct syscon *syscon; + struct udevice *dev, *parent; + ofnode ofnode = node; int ret; + if (!uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev)) + return syscon_get_regmap(dev); + if (!ofnode_device_is_compatible(node, "syscon")) return ERR_PTR(-EINVAL); - syscon = malloc(sizeof(*syscon)); - if (!syscon) - return ERR_PTR(-ENOMEM); + if (device_find_global_by_ofnode(ofnode, &parent)) + parent = dm_root(); - ret = regmap_init_mem(node, &syscon->regmap); - if (ret) { - free(syscon); + /* force bound to syscon class */ + ret = device_bind_driver_to_node(parent, "syscon", + ofnode_get_name(node), + node, &dev); + if (ret) return ERR_PTR(ret); - } - list_add_tail(&syscon->list, &syscon_list); + ret = device_probe(dev); + if (ret) + return ERR_PTR(ret); - return syscon; + return syscon_get_regmap(dev); } -struct regmap *syscon_node_to_regmap(ofnode node) +struct regmap *syscon_phandle_to_regmap(struct udevice *parent, + const char *name) { - struct syscon *entry, *syscon = NULL; - - list_for_each_entry(entry, &syscon_list, list) - if (ofnode_equal(entry->node, node)) { - syscon = entry; - break; - } + u32 phandle; + ofnode node; + int err; - if (!syscon) - syscon = of_syscon_register(node); + err = ofnode_read_u32(dev_ofnode(parent), name, &phandle); + if (err) + return ERR_PTR(err); - if (IS_ERR(syscon)) - return ERR_CAST(syscon); + node = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(node)) + return ERR_PTR(-EINVAL); - return syscon->regmap; + return syscon_node_to_regmap(node); } diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 3113d6a56ba3..a4452bd9b313 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -562,6 +562,19 @@ int uclass_next_device(struct udevice **devp) return uclass_get_device_tail(dev, ret, devp); } +int uclass_next_device_err(struct udevice **devp) +{ + int ret; + + ret = uclass_next_device(devp); + if (ret) + return ret; + else if (!*devp) + return -ENODEV; + + return 0; +} + int uclass_first_device_check(enum uclass_id id, struct udevice **devp) { int ret; diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 4692736c9d24..edbe8179d826 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -46,5 +46,10 @@ config DFU_SF This option enables using DFU to read and write to SPI flash based storage. +config DFU_VIRT + bool "Virtual back end for DFU" + help + This option enables using DFU to read and write to virtual partition. + endif endmenu diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile index 56f9b0c5f49d..830eab3127e0 100644 --- a/drivers/dfu/Makefile +++ b/drivers/dfu/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_DFU_NAND) += dfu_nand.o obj-$(CONFIG_DFU_RAM) += dfu_ram.o obj-$(CONFIG_DFU_SF) += dfu_sf.o obj-$(CONFIG_DFU_TFTP) += dfu_tftp.o +obj-$(CONFIG_DFU_VIRT) += dfu_virt.o diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 318949529b30..f7919b4d19fe 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -21,6 +21,22 @@ static int dfu_alt_num; static int alt_num_cnt; static struct hash_algo *dfu_hash_algo; +/* + * The purpose of the dfu_flush_callback() function is to + * provide callback for dfu user + */ +__weak void dfu_flush_callback(struct dfu_entity *dfu) +{ +} + +/* + * The purpose of the dfu_flush_callback() function is to + * provide callback for dfu user + */ +__weak void dfu_initiated_callback(struct dfu_entity *dfu) +{ +} + /* * The purpose of the dfu_usb_get_reset() function is to * provide information if after USB_DETACH request @@ -82,6 +98,7 @@ int dfu_init_env_entities(char *interface, char *devstr) static unsigned char *dfu_buf; static unsigned long dfu_buf_size; +static enum dfu_device_type dfu_buf_device_type; unsigned char *dfu_free_buf(void) { @@ -99,6 +116,10 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu) { char *s; + /* manage several entity with several contraint */ + if (dfu_buf && dfu->dev_type != dfu_buf_device_type) + dfu_free_buf(); + if (dfu_buf != NULL) return dfu_buf; @@ -117,6 +138,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu) printf("%s: Could not memalign 0x%lx bytes\n", __func__, dfu_buf_size); + dfu_buf_device_type = dfu->dev_type; return dfu_buf; } @@ -204,6 +226,7 @@ int dfu_transaction_initiate(struct dfu_entity *dfu, bool read) } dfu->inited = 1; + dfu_initiated_callback(dfu); return 0; } @@ -223,6 +246,8 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) printf("\nDFU complete %s: 0x%08x\n", dfu_hash_algo->name, dfu->crc); + dfu_flush_callback(dfu); + dfu_transaction_cleanup(dfu); return ret; @@ -337,6 +362,8 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size) debug("%s: Read error!\n", __func__); return ret; } + if (dfu->b_left == 0) + break; dfu->offset += dfu->b_left; dfu->r_left -= dfu->b_left; @@ -389,7 +416,8 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, { char *st; - debug("%s: %s interface: %s dev: %s\n", __func__, s, interface, devstr); + debug("%s: %s interface: %s dev: %s\n", + __func__, s, interface, devstr); st = strsep(&s, " "); strcpy(dfu->name, st); @@ -410,11 +438,15 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, } else if (strcmp(interface, "sf") == 0) { if (dfu_fill_entity_sf(dfu, devstr, s)) return -1; + } else if (strcmp(interface, "virt") == 0) { + if (dfu_fill_entity_virt(dfu, devstr, s)) + return -1; } else { printf("%s: Device %s not (yet) supported!\n", __func__, interface); return -1; } + dfu_get_buf(dfu); return 0; @@ -438,13 +470,12 @@ void dfu_free_entities(void) alt_num_cnt = 0; } -int dfu_config_entities(char *env, char *interface, char *devstr) +int dfu_alt_init(int num, struct dfu_entity **dfu) { - struct dfu_entity *dfu; - int i, ret; char *s; + int ret; - dfu_alt_num = dfu_find_alt_num(env); + dfu_alt_num = num; debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num); dfu_hash_algo = NULL; @@ -455,21 +486,47 @@ int dfu_config_entities(char *env, char *interface, char *devstr) pr_err("Hash algorithm %s not supported\n", s); } - dfu = calloc(sizeof(*dfu), dfu_alt_num); + *dfu = calloc(sizeof(struct dfu_entity), dfu_alt_num); if (!dfu) return -1; - for (i = 0; i < dfu_alt_num; i++) { + return 0; +} +int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s) +{ + struct dfu_entity *p_dfu; + int ret; + + if (alt_num_cnt >= dfu_alt_num) + return -1; + + p_dfu = &dfu[alt_num_cnt]; + ret = dfu_fill_entity(p_dfu, s, alt_num_cnt, interface, devstr); + if (ret) + return -1; + + list_add_tail(&p_dfu->list, &dfu_list); + alt_num_cnt++; + return 0; +} + +int dfu_config_entities(char *env, char *interface, char *devstr) +{ + struct dfu_entity *dfu; + int i, ret; + char *s; + + ret = dfu_alt_init(dfu_find_alt_num(env), &dfu); + if (ret) + return -1; + + for (i = 0; i < dfu_alt_num; i++) { s = strsep(&env, ";"); - ret = dfu_fill_entity(&dfu[i], s, alt_num_cnt, interface, - devstr); + ret = dfu_alt_add(dfu, interface, devstr, s); if (ret) { /* We will free "dfu" in dfu_free_entities() */ return -1; } - - list_add_tail(&dfu[i].list, &dfu_list); - alt_num_cnt++; } return 0; @@ -477,7 +534,8 @@ int dfu_config_entities(char *env, char *interface, char *devstr) const char *dfu_get_dev_type(enum dfu_device_type t) { - const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM", "SF" }; + const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM", "SF", + "VIRT"}; return dev_t[t]; } diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index 066e7670d1b9..65edba385d5f 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size) { @@ -19,7 +21,7 @@ static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size) } static int dfu_read_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf, - long *len) + long *len) { return spi_flash_read(dfu->data.sf.dev, dfu->data.sf.start + offset, *len, buf); @@ -32,7 +34,7 @@ static u64 find_sector(struct dfu_entity *dfu, u64 start, u64 offset) } static int dfu_write_medium_sf(struct dfu_entity *dfu, - u64 offset, void *buf, long *len) + u64 offset, void *buf, long *len) { int ret; @@ -52,11 +54,32 @@ static int dfu_write_medium_sf(struct dfu_entity *dfu, static int dfu_flush_medium_sf(struct dfu_entity *dfu) { + u64 off, length; + + if (!dfu->data.sf.ubi) + return 0; + + /* in case of ubi partition, erase rest of the partition */ + off = find_sector(dfu, dfu->data.sf.start, dfu->offset); + /* last write ended with unaligned length jump to next */ + if (off != dfu->data.sf.start + dfu->offset) + off += dfu->data.sf.dev->sector_size; + length = dfu->data.sf.start + dfu->data.sf.size - off; + if (length) + return spi_flash_erase(dfu->data.sf.dev, off, length); + return 0; } static unsigned int dfu_polltimeout_sf(struct dfu_entity *dfu) { + /* + * Currently, Poll Timeout != 0 is only needed on nor + * ubi partition, as the not used sectors need an erase + */ + if (dfu->data.sf.ubi) + return DFU_MANIFEST_POLL_TIMEOUT; + return DFU_DEFAULT_POLL_TIMEOUT; } @@ -133,6 +156,33 @@ int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr, char *s) dfu->data.sf.start = simple_strtoul(s, &s, 16); s++; dfu->data.sf.size = simple_strtoul(s, &s, 16); + } else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) { + char mtd_id[32]; + struct mtd_device *mtd_dev; + u8 part_num; + struct part_info *pi; + int ret, dev, part; + + dfu->layout = DFU_RAW_ADDR; + + dev = simple_strtoul(s, &s, 10); + s++; + part = simple_strtoul(s, &s, 10); + + sprintf(mtd_id, "%s%d,%d", "nor", dev, part - 1); + printf("using id '%s'\n", mtd_id); + + mtdparts_init(); + + ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi); + if (ret != 0) { + printf("Could not locate '%s'\n", mtd_id); + return -1; + } + dfu->data.sf.start = pi->offset; + dfu->data.sf.size = pi->size; + if (!strcmp(st, "partubi")) + dfu->data.sf.ubi = 1; } else { printf("%s: Memory layout (%s) not supported!\n", __func__, st); spi_flash_free(dfu->data.sf.dev); diff --git a/drivers/dfu/dfu_virt.c b/drivers/dfu/dfu_virt.c new file mode 100644 index 000000000000..035d71f6a3d6 --- /dev/null +++ b/drivers/dfu/dfu_virt.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include + +/* TODO : weak or function to implement ? */ +int __weak dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len) +{ + debug("%s: off=0x%llx, len=0x%x\n", __func__, offset, (u32)*len); + return 0; +} + +int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) +{ + *size = 0; + + return 0; +} + +int __weak dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len) +{ + debug("%s: off=0x%llx, len=0x%x\n", __func__, offset, (u32)*len); + *len = 0; + return 0; +} + +int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, char *s) +{ + debug("%s: devstr = %s\n", __func__, devstr); + dfu->dev_type = DFU_DEV_VIRT; + dfu->layout = DFU_RAW_ADDR; + dfu->data.virt.dev_num = simple_strtoul(devstr, NULL, 10); + dfu->write_medium = dfu_write_medium_virt; + dfu->get_medium_size = dfu_get_medium_size_virt; + dfu->read_medium = dfu_read_medium_virt; + + dfu->inited = 0; + + return 0; +} diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index 4c0786fff88d..7fff64ec15e0 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -15,17 +15,45 @@ #include #include -#define STM32_GPIOS_PER_BANK 16 #define MODE_BITS(gpio_pin) (gpio_pin * 2) #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) +/* + * convert gpio offset to gpio index due to potential gpio + * holes into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } + } + /* shouldn't happen */ + return -EINVAL; +} + static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); @@ -37,12 +65,20 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); - writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } @@ -51,33 +87,75 @@ static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; - return readl(®s->idr) & BIT(offset) ? 1 : 0; + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + return readl(®s->idr) & BIT(idx) ? 1 : 0; } static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } +static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; + u32 mode; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + mode = (readl(®s->moder) & mask) >> bits_index; + if (mode == STM32_GPIO_MODE_OUT) + return GPIOF_OUTPUT; + if (mode == STM32_GPIO_MODE_IN) + return GPIOF_INPUT; + if (mode == STM32_GPIO_MODE_AN) + return GPIOF_UNUSED; + + return GPIOF_FUNC; +} + static const struct dm_gpio_ops gpio_stm32_ops = { .direction_input = stm32_gpio_direction_input, .direction_output = stm32_gpio_direction_output, .get_value = stm32_gpio_get_value, .set_value = stm32_gpio_set_value, + .get_function = stm32_gpio_get_function, }; static int gpio_stm32_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + struct clk clk; fdt_addr_t addr; const char *name; + int ret; + int i; addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) @@ -88,14 +166,25 @@ static int gpio_stm32_probe(struct udevice *dev) if (!name) return -EINVAL; uc_priv->bank_name = name; - uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", - STM32_GPIOS_PER_BANK); - debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs, - uc_priv->bank_name); -#ifdef CONFIG_CLK - struct clk clk; - int ret; + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); + + uc_priv->gpio_count += args.args[2]; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } + + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range); + ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; @@ -107,7 +196,6 @@ static int gpio_stm32_probe(struct udevice *dev) return ret; } debug("clock enabled for device %s\n", dev->name); -#endif return 0; } diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig new file mode 100644 index 000000000000..96d4f5d6ca33 --- /dev/null +++ b/drivers/hwspinlock/Kconfig @@ -0,0 +1,24 @@ +menu "Hardware Spinlock Support" + +config DM_HWSPINLOCK + bool "Enable U-Boot hardware spinlock support" + help + This option enables U-Boot hardware spinlock support + +config HWSPINLOCK_SANDBOX + bool "Enable Hardware Spinlock support for Sandbox" + depends on SANDBOX && DM_HWSPINLOCK + help + Enable hardware spinlock support in Sandbox. This is a dummy device that + can be probed and support all the methods of HWSPINLOCK, but does not + really do anything. + +config HWSPINLOCK_STM32 + bool "Enable Hardware Spinlock support for STM32" + depends on ARCH_STM32MP && DM_HWSPINLOCK + help + Enable hardware spinlock support in STM32MP. Hardware spinlocks are + hardware mutex which provide a synchronisation mechanism for the + various processors on the SoC. + +endmenu diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile new file mode 100644 index 000000000000..289b12a25666 --- /dev/null +++ b/drivers/hwspinlock/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +# +# Copyright (C) 2018, STMicroelectronics - All Rights Reserved + +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o +obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o diff --git a/drivers/hwspinlock/hwspinlock-uclass.c b/drivers/hwspinlock/hwspinlock-uclass.c new file mode 100644 index 000000000000..195f079707cd --- /dev/null +++ b/drivers/hwspinlock/hwspinlock-uclass.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +static inline const struct hwspinlock_ops * +hwspinlock_dev_ops(struct udevice *dev) +{ + return (const struct hwspinlock_ops *)dev->driver->ops; +} + +static int hwspinlock_of_xlate_default(struct hwspinlock *hws, + struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + hws->id = args->args[0]; + else + hws->id = 0; + + return 0; +} + +int hwspinlock_get_by_index(struct udevice *dev, int index, + struct hwspinlock *hws) +{ + int ret; + struct ofnode_phandle_args args; + struct udevice *dev_hws; + const struct hwspinlock_ops *ops; + + assert(hws); + hws->dev = NULL; + + ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1, + index, &args); + if (ret) { + dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK, + args.node, &dev_hws); + if (ret) { + dev_dbg(dev, + "%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } + + hws->dev = dev_hws; + + ops = hwspinlock_dev_ops(dev_hws); + + if (ops->of_xlate) + ret = ops->of_xlate(hws, &args); + else + ret = hwspinlock_of_xlate_default(hws, &args); + if (ret) + dev_dbg(dev, "of_xlate() failed: %d\n", ret); + + return ret; +} + +int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout) +{ + const struct hwspinlock_ops *ops; + ulong start; + int ret; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->lock) + return -ENOSYS; + + start = get_timer(0); + do { + ret = ops->lock(hws->dev, hws->id); + if (!ret) + return ret; + + if (ops->relax) + ops->relax(hws->dev); + } while (get_timer(start) < timeout); + + return -ETIMEDOUT; +} + +int hwspinlock_unlock(struct hwspinlock *hws) +{ + const struct hwspinlock_ops *ops; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->unlock) + return -ENOSYS; + + return ops->unlock(hws->dev, hws->id); +} + +static int hwspinlock_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct hwspinlock_ops *ops = device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->lock) + ops->lock += gd->reloc_off; + if (ops->unlock) + ops->unlock += gd->reloc_off; + if (ops->relax) + ops->relax += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + +UCLASS_DRIVER(hwspinlock) = { + .id = UCLASS_HWSPINLOCK, + .name = "hwspinlock", + .post_bind = hwspinlock_post_bind, +}; diff --git a/drivers/hwspinlock/sandbox_hwspinlock.c b/drivers/hwspinlock/sandbox_hwspinlock.c new file mode 100644 index 000000000000..be920f5f99df --- /dev/null +++ b/drivers/hwspinlock/sandbox_hwspinlock.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include + +static int sandbox_lock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (state->hwspinlock) + return -1; + + state->hwspinlock = true; + + return 0; +} + +static int sandbox_unlock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (!state->hwspinlock) + return -1; + + state->hwspinlock = false; + + return 0; +} + +static const struct hwspinlock_ops sandbox_hwspinlock_ops = { + .lock = sandbox_lock, + .unlock = sandbox_unlock, +}; + +static const struct udevice_id sandbox_hwspinlock_ids[] = { + { .compatible = "sandbox,hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_sandbox) = { + .name = "hwspinlock_sandbox", + .id = UCLASS_HWSPINLOCK, + .of_match = sandbox_hwspinlock_ids, + .ops = &sandbox_hwspinlock_ops, +}; diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c new file mode 100644 index 000000000000..b8f3b1632f33 --- /dev/null +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include + +#define STM32_MUTEX_COREID BIT(8) +#define STM32_MUTEX_LOCK_BIT BIT(31) +#define STM32_MUTEX_NUM_LOCKS 32 + +static int stm32mp1_lock(struct udevice *dev, int index) +{ + fdt_addr_t *base = dev_get_priv(dev); + u32 status; + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + status = readl(*base + index * sizeof(u32)); + if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EBUSY; + + writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, + *base + index * sizeof(u32)); + + status = readl(*base + index * sizeof(u32)); + if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EINVAL; + + return 0; +} + +static int stm32mp1_unlock(struct udevice *dev, int index) +{ + fdt_addr_t *base = dev_get_priv(dev); + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + writel(STM32_MUTEX_COREID, *base + index * sizeof(u32)); + + return 0; +} + +static int stm32mp1_hwspinlock_probe(struct udevice *dev) +{ + fdt_addr_t *base = dev_get_priv(dev); + struct clk clk; + int ret; + + *base = dev_read_addr(dev); + if (*base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + return ret; +} + +static const struct hwspinlock_ops stm32mp1_hwspinlock_ops = { + .lock = stm32mp1_lock, + .unlock = stm32mp1_unlock, +}; + +static const struct udevice_id stm32mp1_hwspinlock_ids[] = { + { .compatible = "st,stm32-hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_stm32mp1) = { + .name = "hwspinlock_stm32mp1", + .id = UCLASS_HWSPINLOCK, + .of_match = stm32mp1_hwspinlock_ids, + .ops = &stm32mp1_hwspinlock_ops, + .probe = stm32mp1_hwspinlock_probe, + .priv_auto_alloc_size = sizeof(fdt_addr_t), +}; diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 36ec610c8ec6..50c4fd0de23a 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -58,7 +58,7 @@ struct stm32_i2c_regs { #define STM32_I2C_CR2_ADD10 BIT(11) #define STM32_I2C_CR2_RD_WRN BIT(10) #define STM32_I2C_CR2_SADD10_MASK GENMASK(9, 0) -#define STM32_I2C_CR2_SADD10(n) ((n & STM32_I2C_CR2_SADD10_MASK)) +#define STM32_I2C_CR2_SADD10(n) (n & STM32_I2C_CR2_SADD10_MASK) #define STM32_I2C_CR2_SADD7_MASK GENMASK(7, 1) #define STM32_I2C_CR2_SADD7(n) ((n & 0x7f) << 1) #define STM32_I2C_CR2_RESET_MASK (STM32_I2C_CR2_HEAD10R \ @@ -197,7 +197,7 @@ struct stm32_i2c_priv { int speed; }; -static struct stm32_i2c_spec i2c_specs[] = { +static const struct stm32_i2c_spec i2c_specs[] = { [STM32_I2C_SPEED_STANDARD] = { .rate = STANDARD_RATE, .rate_min = 8000, @@ -236,7 +236,7 @@ static struct stm32_i2c_spec i2c_specs[] = { }, }; -static struct stm32_i2c_setup stm32f7_setup = { +static const struct stm32_i2c_setup stm32f7_setup = { .rise_time = STM32_I2C_RISE_TIME_DEFAULT, .fall_time = STM32_I2C_FALL_TIME_DEFAULT, .dnf = STM32_I2C_DNF_DEFAULT, @@ -255,7 +255,7 @@ static int stm32_i2c_check_device_busy(struct stm32_i2c_priv *i2c_priv) } static void stm32_i2c_message_start(struct stm32_i2c_priv *i2c_priv, - struct i2c_msg *msg, bool stop) + struct i2c_msg *msg, bool stop) { struct stm32_i2c_regs *regs = i2c_priv->regs; u32 cr2 = readl(®s->cr2); @@ -299,7 +299,7 @@ static void stm32_i2c_message_start(struct stm32_i2c_priv *i2c_priv, */ static void stm32_i2c_handle_reload(struct stm32_i2c_priv *i2c_priv, - struct i2c_msg *msg, bool stop) + struct i2c_msg *msg, bool stop) { struct stm32_i2c_regs *regs = i2c_priv->regs; u32 cr2 = readl(®s->cr2); @@ -317,7 +317,7 @@ static void stm32_i2c_handle_reload(struct stm32_i2c_priv *i2c_priv, } static int stm32_i2c_wait_flags(struct stm32_i2c_priv *i2c_priv, - u32 flags, u32 *status) + u32 flags, u32 *status) { struct stm32_i2c_regs *regs = i2c_priv->regs; u32 time_start = get_timer(0); @@ -392,7 +392,7 @@ static int stm32_i2c_check_end_of_message(struct stm32_i2c_priv *i2c_priv) } static int stm32_i2c_message_xfer(struct stm32_i2c_priv *i2c_priv, - struct i2c_msg *msg, bool stop) + struct i2c_msg *msg, bool stop) { struct stm32_i2c_regs *regs = i2c_priv->regs; u32 status; @@ -465,7 +465,7 @@ static int stm32_i2c_message_xfer(struct stm32_i2c_priv *i2c_priv, } static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, - int nmsgs) + int nmsgs) { struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus); int ret; @@ -500,7 +500,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, af_delay_max = setup->analog_filter ? STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0; - sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min - + sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - @@ -540,8 +540,12 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, p_prev = p; list_add_tail(&v->node, solutions); + break; } } + + if (p_prev == p) + break; } } @@ -594,6 +598,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, for (l = 0; l < STM32_SCLL_MAX; l++) { u32 tscl_l = (l + 1) * prescaler + tsync; + if ((tscl_l < i2c_specs[setup->speed].l_min) || (i2cclk >= ((tscl_l - af_delay_min - dnf_delay) / 4))) { @@ -634,8 +639,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, } static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, - struct stm32_i2c_setup *setup, - struct stm32_i2c_timings *output) + struct stm32_i2c_setup *setup, + struct stm32_i2c_timings *output) { struct stm32_i2c_timings *v, *_v; struct list_head solutions; @@ -643,28 +648,28 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, if (setup->speed >= STM32_I2C_SPEED_END) { pr_err("%s: speed out of bound {%d/%d}\n", __func__, - setup->speed, STM32_I2C_SPEED_END - 1); + setup->speed, STM32_I2C_SPEED_END - 1); return -EINVAL; } if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || (setup->fall_time > i2c_specs[setup->speed].fall_max)) { pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", - __func__, - setup->rise_time, i2c_specs[setup->speed].rise_max, - setup->fall_time, i2c_specs[setup->speed].fall_max); + __func__, + setup->rise_time, i2c_specs[setup->speed].rise_max, + setup->fall_time, i2c_specs[setup->speed].fall_max); return -EINVAL; } if (setup->dnf > STM32_I2C_DNF_MAX) { pr_err("%s: DNF out of bound %d/%d\n", __func__, - setup->dnf, STM32_I2C_DNF_MAX); + setup->dnf, STM32_I2C_DNF_MAX); return -EINVAL; } if (setup->speed_freq > i2c_specs[setup->speed].rate) { pr_err("%s: Freq {%d/%d}\n", __func__, - setup->speed_freq, i2c_specs[setup->speed].rate); + setup->speed_freq, i2c_specs[setup->speed].rate); return -EINVAL; } @@ -693,7 +698,7 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, } static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, - struct stm32_i2c_timings *timing) + struct stm32_i2c_timings *timing) { struct stm32_i2c_setup *setup = i2c_priv->setup; int ret = 0; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 2836ee4a7b0a..82a8a87ff226 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -24,6 +24,13 @@ config TEGRA_HSP This enables support for the NVIDIA Tegra HSP Hw module, which implements doorbells, mailboxes, semaphores, and shared interrupts. +config STM32_IPCC + bool "Enable STM32 IPCC controller support" + depends on DM_MAILBOX && ARCH_STM32MP + help + This enables support for the STM32MP IPCC Hw module, which + implements doorbells and shared interrupts between 2 processors. + config K3_SEC_PROXY bool "Texas Instruments K3 Secure Proxy Driver" depends on DM_MAILBOX && ARCH_K3 diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index cd237698ba61..a753cc4e6806 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o +obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.o diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c new file mode 100644 index 000000000000..dfcea9153800 --- /dev/null +++ b/drivers/mailbox/stm32-ipcc.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +/* + * IPCC has one set of registers per CPU + * IPCC_PROC_OFFST allows to define cpu registers set base address + * according to assigned cpu_id. + * In register name, X (Y) means either C1 (C2) or C2 (C1) depending + * of cpu offset. + */ + +#define IPCC_PROC_OFFST 0x010 + +#define IPCC_XCR 0x000 +#define XCR_RXOIE BIT(0) +#define XCR_TXOIE BIT(16) + +#define IPCC_XMR 0x004 +#define IPCC_XSCR 0x008 +#define IPCC_XTOYSR 0x00c + +#define IPCC_HWCFGR 0x3f0 +#define IPCFGR_CHAN_MASK GENMASK(7, 0) + +#define IPCC_VER 0x3f4 +#define VER_MINREV_MASK GENMASK(3, 0) +#define VER_MAJREV_MASK GENMASK(7, 4) + +#define RX_BIT_MASK GENMASK(15, 0) +#define RX_BIT_CHAN(chan) BIT(chan) +#define TX_BIT_SHIFT 16 +#define TX_BIT_MASK GENMASK(31, 16) +#define TX_BIT_CHAN(chan) BIT(TX_BIT_SHIFT + (chan)) + +#define STM32_MAX_PROCS 2 + +enum { + IPCC_IRQ_RX, + IPCC_IRQ_TX, + IPCC_IRQ_NUM, +}; + +struct stm32_ipcc { + void __iomem *reg_base; + void __iomem *reg_proc; + struct clk clk; + u32 proc_id; + u32 n_chans; +}; + +static int stm32_ipcc_request(struct mbox_chan *chan) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + + debug("%s(chan=%p)\n", __func__, chan); + + if (chan->id >= ipcc->n_chans) { + debug("%s failed to request channel: %ld\n", + __func__, chan->id); + return -EINVAL; + } + + return 0; +} + +static int stm32_ipcc_free(struct mbox_chan *chan) +{ + debug("%s(chan=%p)\n", __func__, chan); + + return 0; +} + +static int stm32_ipcc_send(struct mbox_chan *chan, const void *data) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + /* set channel n occupied */ + setbits_le32(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan->id)); + + return 0; +} + +static int stm32_ipcc_recv(struct mbox_chan *chan, void *data) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + u32 val; + int proc_offset; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + /* read 'channel occupied' status from other proc */ + proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST; + val = readl(ipcc->reg_proc + proc_offset + IPCC_XTOYSR); + + if (!(val & BIT(chan->id))) + return -ENODATA; + + setbits_le32(ipcc->reg_proc + IPCC_XSCR, RX_BIT_CHAN(chan->id)); + + return 0; +} + +static int stm32_ipcc_probe(struct udevice *dev) +{ + struct stm32_ipcc *ipcc = dev_get_priv(dev); + fdt_addr_t addr; + const fdt32_t *cell; + int len, ret; + + debug("%s(dev=%p)\n", __func__, dev); + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + ipcc->reg_base = (void __iomem *)addr; + + /* proc_id */ + cell = dev_read_prop(dev, "st,proc_id", &len); + if (len < sizeof(fdt32_t)) { + dev_dbg(dev, "Missing st,proc_id\n"); + return -EINVAL; + } + + ipcc->proc_id = fdtdec_get_number(cell, 1); + + if (ipcc->proc_id >= STM32_MAX_PROCS) { + dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id); + return -EINVAL; + } + + ipcc->reg_proc = ipcc->reg_base + ipcc->proc_id * IPCC_PROC_OFFST; + + ret = clk_get_by_index(dev, 0, &ipcc->clk); + if (ret) + return ret; + + ret = clk_enable(&ipcc->clk); + if (ret) + goto clk_free; + + /* get channe number */ + ipcc->n_chans = readl(ipcc->reg_base + IPCC_HWCFGR); + ipcc->n_chans &= IPCFGR_CHAN_MASK; + + /* mask and enable rx/tx irq */ + setbits_le32(ipcc->reg_proc + IPCC_XMR, RX_BIT_MASK | TX_BIT_MASK); + setbits_le32(ipcc->reg_proc + IPCC_XCR, XCR_RXOIE | XCR_TXOIE); + + return 0; + +clk_free: + clk_free(&ipcc->clk); + + return ret; +} + +static const struct udevice_id stm32_ipcc_ids[] = { + { .compatible = "st,stm32mp1-ipcc" }, + { } +}; + +struct mbox_ops stm32_ipcc_mbox_ops = { + .request = stm32_ipcc_request, + .free = stm32_ipcc_free, + .send = stm32_ipcc_send, + .recv = stm32_ipcc_recv, +}; + +U_BOOT_DRIVER(stm32_ipcc) = { + .name = "stm32_ipcc", + .id = UCLASS_MAILBOX, + .of_match = stm32_ipcc_ids, + .probe = stm32_ipcc_probe, + .priv_auto_alloc_size = sizeof(struct stm32_ipcc), + .ops = &stm32_ipcc_mbox_ops, +}; diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 2d661351a17c..842871fb033e 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 @@ -31,6 +33,13 @@ int fuse_read(u32 bank, u32 word, u32 *val) val, 4); 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; @@ -56,6 +65,12 @@ int fuse_prog(u32 bank, u32 word, u32 val) &val, 4); 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; @@ -80,6 +95,13 @@ int fuse_sense(u32 bank, u32 word, u32 *val) ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4); 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; @@ -105,6 +127,12 @@ int fuse_override(u32 bank, u32 word, u32 val) &val, 4); 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/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index b8acc33c76d0..1a3f5615b279 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -79,7 +79,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) u32 start_rem, blkcnt_rem; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; - int timeout = 1000; + int timeout = 2000; if (!mmc) return -1; diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index a36612dd937e..ed31ca126e93 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -190,6 +190,7 @@ struct stm32_sdmmc2_ctx { #define SDMMC_IDMACTRL_IDMAEN BIT(0) #define SDMMC_CMD_TIMEOUT 0xFFFFFFFF +#define SDMMC_BUSYD0END_TIMEOUT_US 1000000 static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, struct mmc_data *data, @@ -209,9 +210,6 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, idmabase0 = (u32)data->src; } - /* Set the SDMMC Data TimeOut value */ - writel(SDMMC_CMD_TIMEOUT, priv->base + SDMMC_DTIMER); - /* Set the SDMMC DataLength value */ writel(ctx->data_length, priv->base + SDMMC_DLEN); @@ -236,8 +234,11 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, } static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv, - struct mmc_cmd *cmd, u32 cmd_param) + struct mmc_cmd *cmd, u32 cmd_param, + struct stm32_sdmmc2_ctx *ctx) { + u32 timeout = 0; + if (readl(priv->base + SDMMC_CMD) & SDMMC_CMD_CPSMEN) writel(0, priv->base + SDMMC_CMD); @@ -251,6 +252,26 @@ static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv, cmd_param |= SDMMC_CMD_WAITRESP_1; } + /* + * SDMMC_DTIME must be set in two case: + * - on data transfert. + * - on busy request. + * If not done or too short, the dtimeout flag occurs and DPSM stays + * enabled/busy and waits for abort (stop transmission cmd). + * Next data command is not possible whereas DPSM is activated. + */ + if (ctx->data_length) { + timeout = SDMMC_CMD_TIMEOUT; + } else { + writel(0, priv->base + SDMMC_DCTRL); + + if (cmd->resp_type & MMC_RSP_BUSY) + timeout = SDMMC_CMD_TIMEOUT; + } + + /* Set the SDMMC Data TimeOut value */ + writel(timeout, priv->base + SDMMC_DTIMER); + /* Clear flags */ writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); @@ -309,6 +330,31 @@ static int stm32_sdmmc2_end_cmd(struct stm32_sdmmc2_priv *priv, cmd->response[2] = readl(priv->base + SDMMC_RESP3); cmd->response[3] = readl(priv->base + SDMMC_RESP4); } + + /* Wait for BUSYD0END flag if busy status is detected */ + if (cmd->resp_type & MMC_RSP_BUSY && + status & SDMMC_STA_BUSYD0) { + mask = SDMMC_STA_DTIMEOUT | SDMMC_STA_BUSYD0END; + + /* Polling status register */ + ret = readl_poll_timeout(priv->base + SDMMC_STA, + status, status & mask, + SDMMC_BUSYD0END_TIMEOUT_US); + + if (ret < 0) { + debug("%s: timeout reading SDMMC_STA\n", + __func__); + ctx->dpsm_abort = true; + return ret; + } + + if (status & SDMMC_STA_DTIMEOUT) { + debug("%s: error SDMMC_STA_DTIMEOUT (0x%x)\n", + __func__, status); + ctx->dpsm_abort = true; + return -ETIMEDOUT; + } + } } return 0; @@ -395,7 +441,7 @@ static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, stm32_sdmmc2_start_data(priv, data, &ctx); } - stm32_sdmmc2_start_cmd(priv, cmd, cmdat); + stm32_sdmmc2_start_cmd(priv, cmd, cmdat, &ctx); debug("%s: send cmd %d data: 0x%x @ 0x%x\n", __func__, cmd->cmdidx, @@ -425,7 +471,10 @@ static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, debug("%s: send STOP command to abort dpsm treatments\n", __func__); - stm32_sdmmc2_start_cmd(priv, &stop_cmd, SDMMC_CMD_CMDSTOP); + ctx.data_length = 0; + + stm32_sdmmc2_start_cmd(priv, &stop_cmd, + SDMMC_CMD_CMDSTOP, &ctx); stm32_sdmmc2_end_cmd(priv, &stop_cmd, &ctx); writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); @@ -585,11 +634,11 @@ static int stm32_sdmmc2_probe(struct udevice *dev) if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; - if (dev_read_bool(dev, "st,negedge")) + if (dev_read_bool(dev, "st,neg-edge")) priv->clk_reg_msk |= SDMMC_CLKCR_NEGEDGE; - if (dev_read_bool(dev, "st,dirpol")) + if (dev_read_bool(dev, "st,sig-dir")) priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL; - if (dev_read_bool(dev, "st,pin-ckin")) + if (dev_read_bool(dev, "st,use-ckin")) priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN; ret = clk_get_by_index(dev, 0, &priv->clk); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 008f7b4b4ba1..041957463fff 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -243,6 +243,17 @@ config SYS_NAND_BUSWIDTH_16BIT not available while configuring controller. So a static CONFIG_NAND_xx is needed to know the device's bus-width in advance. +config NAND_STM32_FMC2 + bool "STM32 FMC2 NAND driver" + depends on ARCH_STM32MP && OF_CONTROL && MTD + 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. + if SPL config SYS_NAND_U_BOOT_LOCATIONS diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index c61e3f38391a..b10e718d150c 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/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index 4009d6412352..d457c543c774 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -52,6 +52,10 @@ struct nand_flash_dev nand_flash_ids[] = { {"TC58NVG3S0F 8G 3.3V 8-bit", { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) }, + {"S34ML16G2 8G 3.3V 8-bit", + { .id = {0x01, 0xd3, 0xd1, 0x95, 0x5a} }, + SZ_2K, SZ_1K, SZ_128K, 0, 5, 128, NAND_ECC_INFO(4, SZ_512), + 4 }, {"TC58NVG5D2 32G 3.3V 8-bit", { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, 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 000000000000..6f6f5e6ae9f9 --- /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) 2018, STMicroelectronics - All Rights Reserved + * Author: Christophe Kerello + */ + +#include +#include +#include +#include +#include +#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 0xf0 +#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); +} + +/* Clear interrupt 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); +} + +/* 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); +} + +/* 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 -ETIMEDOUT; + } + + 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 that the BCH encoder parity is available */ + ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr, + bchisr & FMC2_BCHISR_EPBRF, 10000); + if (ret < 0) { + pr_err("Bch timeout\n"); + return -ETIMEDOUT; + } + + /* Read parity bits (write) or syndrome (read) */ + 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 that the BCH encoder syndrome is available */ + ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr, + bchisr & FMC2_BCHISR_DERF, 10000); + if (ret < 0) { + pr_err("Bch timeout\n"); + return -ETIMEDOUT; + } + + 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 */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return max_bitflips; +} + +/* 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 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 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 in Hamming by default */ + 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 */ + 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 function */ +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); +} + +/* 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, chip_cs; + + 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 (chip_cs = 0; chip_cs < nand->ncs; chip_cs++) { + if (cs[chip_cs] > FMC2_MAX_CE) { + pr_err("Invalid reg value: %d\n", + nand->cs_used[chip_cs]); + return -EINVAL; + } + + if (fmc2->cs_assigned & BIT(cs[chip_cs])) { + pr_err("Cs already assigned: %d\n", + nand->cs_used[chip_cs]); + return -EINVAL; + } + + fmc2->cs_assigned |= BIT(cs[chip_cs]); + nand->cs_used[chip_cs] = cs[chip_cs]; + } + + nand->chip.flash_node = ofnode_to_offset(node); + + return 0; +} + +static int stm32_fmc2_parse_children(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_children(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 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 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 + 1; + 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); +} diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index a87bacd4ac72..3bd68690203e 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -357,6 +358,8 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) offset += erase_size; len -= erase_size; + + WATCHDOG_RESET(); } #ifdef CONFIG_SPI_FLASH_BAR @@ -419,6 +422,8 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, } offset += chunk_len; + + WATCHDOG_RESET(); } #ifdef CONFIG_SPI_FLASH_BAR @@ -525,6 +530,8 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, offset += read_len; len -= read_len; data += read_len; + + WATCHDOG_RESET(); } #ifdef CONFIG_SPI_FLASH_BAR @@ -769,6 +776,8 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, cmd_len = 1; offset += 2; + + WATCHDOG_RESET(); } if (!ret) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9f1c5af46e99..072b8c80b141 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -26,7 +26,6 @@ * supports a single RGMII PHY. This configuration also has SW control over * all clock and reset signals to the HW block. */ - #include #include #include @@ -95,6 +94,7 @@ struct eqos_mac_regs { #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff @@ -108,6 +108,7 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 @@ -260,6 +261,28 @@ struct eqos_desc { struct eqos_config { bool reg_access_always_ok; + int mdio_wait; + int config_mac; + int config_mac_mdio; + int (*interface)(struct udevice *); + struct eqos_ops *ops; +}; + +struct eqos_ops { + void (*eqos_inval_desc)(void *desc); + void (*eqos_flush_desc)(void *desc); + void (*eqos_inval_buffer)(void *buf, size_t size); + void (*eqos_flush_buffer)(void *buf, size_t size); + int (*eqos_probe_resources)(struct udevice *); + int (*eqos_remove_resources)(struct udevice *); + int (*eqos_stop_resets)(struct udevice *); + int (*eqos_start_resets)(struct udevice *); + void (*eqos_stop_clks)(struct udevice *); + int (*eqos_start_clks)(struct udevice *); + int (*eqos_calibrate_pads)(struct udevice *); + int (*eqos_disable_calibration)(struct udevice *); + int (*eqos_set_tx_clk_speed)(struct udevice *); + ulong (*eqos_get_tick_clk_rate)(struct udevice *); }; struct eqos_priv { @@ -276,6 +299,7 @@ struct eqos_priv { struct clk clk_rx; struct clk clk_ptp_ref; struct clk clk_tx; + struct clk clk_ck; struct clk clk_slave_bus; struct mii_dev *mii; struct phy_device *phy; @@ -327,7 +351,7 @@ static void eqos_free_descs(void *descs) #endif } -static void eqos_inval_desc(void *desc) +static void eqos_inval_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); @@ -338,14 +362,36 @@ static void eqos_inval_desc(void *desc) #endif } -static void eqos_flush_desc(void *desc) +static void eqos_inval_desc_stm32(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +#endif +} + +static void eqos_flush_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE); #endif } -static void eqos_inval_buffer(void *buf, size_t size) +static void eqos_flush_desc_stm32(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +#endif +} + +static void eqos_inval_buffer_tegra186(void *buf, size_t size) { unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); @@ -353,11 +399,29 @@ static void eqos_inval_buffer(void *buf, size_t size) invalidate_dcache_range(start, end); } -static void eqos_flush_buffer(void *buf, size_t size) +static void eqos_inval_buffer_stm32(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void eqos_flush_buffer_tegra186(void *buf, size_t size) { flush_cache((unsigned long)buf, size); } +static void eqos_flush_buffer_stm32(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +} + static int eqos_mdio_wait_idle(struct eqos_priv *eqos) { return wait_for_bit_le32(&eqos->mac_regs->mdio_address, @@ -386,14 +450,14 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_READ << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -432,14 +496,14 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_WRITE << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -509,6 +573,53 @@ static int eqos_start_clks_tegra186(struct udevice *dev) return ret; } +static int eqos_start_clks_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = clk_enable(&eqos->clk_master_bus); + if (ret < 0) { + pr_err("clk_enable(clk_master_bus) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_rx); + if (ret < 0) { + pr_err("clk_enable(clk_rx) failed: %d", ret); + goto err_disable_clk_master_bus; + } + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + pr_err("clk_enable(clk_tx) failed: %d", ret); + goto err_disable_clk_rx; + } + + if (clk_valid(&eqos->clk_ck)) { + ret = clk_enable(&eqos->clk_ck); + if (ret < 0) { + pr_err("clk_enable(clk_ck) failed: %d", ret); + goto err_disable_clk_tx; + } + } + + debug("%s: OK\n", __func__); + return 0; + +err_disable_clk_tx: + clk_disable(&eqos->clk_tx); +err_disable_clk_rx: + clk_disable(&eqos->clk_rx); +err_disable_clk_master_bus: + clk_disable(&eqos->clk_master_bus); +err: + debug("%s: FAILED: %d\n", __func__, ret); + return ret; +} + void eqos_stop_clks_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -524,6 +635,21 @@ void eqos_stop_clks_tegra186(struct udevice *dev) debug("%s: OK\n", __func__); } +void eqos_stop_clks_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_disable(&eqos->clk_tx); + clk_disable(&eqos->clk_rx); + clk_disable(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_disable(&eqos->clk_ck); + + debug("%s: OK\n", __func__); +} + static int eqos_start_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -563,6 +689,11 @@ static int eqos_start_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_start_resets_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_stop_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -573,6 +704,11 @@ static int eqos_stop_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_stop_resets_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_calibrate_pads_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -632,6 +768,23 @@ static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev) return clk_get_rate(&eqos->clk_slave_bus); } +static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + return clk_get_rate(&eqos->clk_master_bus); +} + +static int eqos_calibrate_pads_stm32(struct udevice *dev) +{ + return 0; +} + +static int eqos_disable_calibration_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_set_full_duplex(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -726,6 +879,11 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) return 0; } +static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_adjust_link(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -766,23 +924,23 @@ static int eqos_adjust_link(struct udevice *dev) } if (en_calibration) { - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", + ret); return ret; } } else { - ret = eqos_disable_calibration_tegra186(dev); + ret = eqos->config->ops->eqos_disable_calibration(dev); if (ret < 0) { - pr_err("eqos_disable_calibration_tegra186() failed: %d", - ret); + pr_err("eqos_disable_calibration() failed: %d", + ret); return ret; } } - - ret = eqos_set_tx_clk_speed_tegra186(dev); + ret = eqos->config->ops->eqos_set_tx_clk_speed(dev); if (ret < 0) { - pr_err("eqos_set_tx_clk_speed_tegra186() failed: %d", ret); + pr_err("eqos_set_tx_clk_speed() failed: %d", ret); return ret; } @@ -846,18 +1004,12 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; - ret = eqos_start_clks_tegra186(dev); + ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { - pr_err("eqos_start_clks_tegra186() failed: %d", ret); + pr_err("eqos_start_resets() failed: %d", ret); goto err; } - ret = eqos_start_resets_tegra186(dev); - if (ret < 0) { - pr_err("eqos_start_resets_tegra186() failed: %d", ret); - goto err_stop_clks; - } - udelay(10); eqos->reg_access_ok = true; @@ -869,26 +1021,16 @@ static int eqos_start(struct udevice *dev) goto err_stop_resets; } - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", ret); goto err_stop_resets; } + rate = eqos->config->ops->eqos_get_tick_clk_rate(dev); - rate = eqos_get_tick_clk_rate_tegra186(dev); val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); - eqos->phy = phy_connect(eqos->mii, 0, dev, 0); - if (!eqos->phy) { - pr_err("phy_connect() failed"); - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; - } ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -993,7 +1135,7 @@ static int eqos_start(struct udevice *dev) clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, - EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB << + eqos->config->config_mac << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); /* Set TX flow control parameters */ @@ -1074,7 +1216,7 @@ static int eqos_start(struct udevice *dev) (i * EQOS_MAX_PACKET_SIZE)); rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; } - flush_cache((unsigned long)eqos->descs, EQOS_DESCRIPTORS_SIZE); + eqos->config->ops->eqos_flush_desc(eqos->descs); writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); @@ -1115,9 +1257,7 @@ static int eqos_start(struct udevice *dev) phy_shutdown(eqos->phy); eqos->phy = NULL; err_stop_resets: - eqos_stop_resets_tegra186(dev); -err_stop_clks: - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); err: pr_err("FAILED: %d", ret); return ret; @@ -1168,12 +1308,7 @@ void eqos_stop(struct udevice *dev) clrbits_le32(&eqos->dma_regs->ch0_rx_control, EQOS_DMA_CH0_RX_CONTROL_SR); - if (eqos->phy) { - phy_shutdown(eqos->phy); - eqos->phy = NULL; - } - eqos_stop_resets_tegra186(dev); - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); debug("%s: OK\n", __func__); } @@ -1188,7 +1323,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) length); memcpy(eqos->tx_dma_buf, packet, length); - eqos_flush_buffer(eqos->tx_dma_buf, length); + eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length); tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]); eqos->tx_desc_idx++; @@ -1203,12 +1338,12 @@ int eqos_send(struct udevice *dev, void *packet, int length) */ mb(); tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; - eqos_flush_desc(tx_desc); + eqos->config->ops->eqos_flush_desc(tx_desc); writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer); for (i = 0; i < 1000000; i++) { - eqos_inval_desc(tx_desc); + eqos->config->ops->eqos_inval_desc(tx_desc); if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN)) return 0; udelay(1); @@ -1238,7 +1373,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) length = rx_desc->des3 & 0x7fff; debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length); - eqos_inval_buffer(*packetp, length); + eqos->config->ops->eqos_inval_buffer(*packetp, length); return length; } @@ -1269,7 +1404,7 @@ int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) */ mb(); rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; - eqos_flush_desc(rx_desc); + eqos->config->ops->eqos_flush_desc(rx_desc); writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); @@ -1304,7 +1439,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_descs; } - debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); + debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE); if (!eqos->rx_dma_buf) { @@ -1312,7 +1447,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_tx_dma_buf; } - debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); + debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); if (!eqos->rx_pkt) { @@ -1424,6 +1559,99 @@ static int eqos_probe_resources_tegra186(struct udevice *dev) return ret; } +/* board-specific Ethernet Interface initializations. */ +__weak int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, + bool eth_ref_clk_sel_reg) +{ + return 0; +} + +static int eqos_probe_resources_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + int interface; + bool eth_clk_sel_reg = false; + bool eth_ref_clk_sel_reg = false; + + + debug("%s(dev=%p):\n", __func__, dev); + + interface = eqos->config->interface(dev); + + if (interface == -1) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + /* Gigabit Ethernet 125MHz clock selection. */ + eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel"); + + /* Ethernet 50Mhz RMII clock selection */ + eth_ref_clk_sel_reg = + dev_read_bool(dev, "st,eth_ref_clk_sel"); + + ret = board_interface_eth_init(interface, eth_clk_sel_reg, + eth_ref_clk_sel_reg); + if (ret) + return -EINVAL; + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + pr_err("clk_get_by_name(master_bus) failed: %d", ret); + goto err_probe; + } + + ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx); + if (ret) { + pr_err("clk_get_by_name(rx) failed: %d", ret); + goto err_free_clk_master_bus; + } + + ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx); + if (ret) { + pr_err("clk_get_by_name(tx) failed: %d", ret); + goto err_free_clk_rx; + } + + /* Get ETH_CLK clocks (optional) */ + ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck); + if (ret) + pr_warn("No phy clock provided %d", ret); + + debug("%s: OK\n", __func__); + return 0; + +err_free_clk_rx: + clk_free(&eqos->clk_rx); +err_free_clk_master_bus: + clk_free(&eqos->clk_master_bus); +err_probe: + + debug("%s: returns %d\n", __func__, ret); + return ret; +} + +static int eqos_get_interface_stm32(struct udevice *dev) +{ + const char *phy_mode; + int interface = -1; + + debug("%s(dev=%p):\n", __func__, dev); + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + interface = phy_get_interface_by_name(phy_mode); + + return interface; +} + +static int eqos_get_interface_tegra186(struct udevice *dev) +{ + return 0; +} + static int eqos_remove_resources_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1442,6 +1670,22 @@ static int eqos_remove_resources_tegra186(struct udevice *dev) return 0; } +static int eqos_remove_resources_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_free(&eqos->clk_tx); + clk_free(&eqos->clk_rx); + clk_free(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_free(&eqos->clk_ck); + + debug("%s: OK\n", __func__); + return 0; +} + static int eqos_probe(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1468,9 +1712,9 @@ static int eqos_probe(struct udevice *dev) return ret; } - ret = eqos_probe_resources_tegra186(dev); + ret = eqos->config->ops->eqos_probe_resources(dev); if (ret < 0) { - pr_err("eqos_probe_resources_tegra186() failed: %d", ret); + pr_err("eqos_probe_resources() failed: %d", ret); goto err_remove_resources_core; } @@ -1490,13 +1734,38 @@ static int eqos_probe(struct udevice *dev) goto err_free_mdio; } + // Bring up PHY + ret = eqos->config->ops->eqos_start_clks(dev); + if (ret < 0) { + pr_err("eqos_start_clks() failed: %d", ret); + goto err_free_mdio; + } + + eqos->phy = phy_connect(eqos->mii, 0, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } + debug("%s: OK\n", __func__); return 0; +err_shutdown_phy: + phy_shutdown(eqos->phy); + eqos->phy = NULL; +err_stop_resets: + eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); err_free_mdio: mdio_free(eqos->mii); err_remove_resources_tegra: - eqos_remove_resources_tegra186(dev); + eqos->config->ops->eqos_remove_resources(dev); err_remove_resources_core: eqos_remove_resources_core(dev); @@ -1512,7 +1781,16 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); - eqos_remove_resources_tegra186(dev); + + if (eqos->phy) { + phy_shutdown(eqos->phy); + eqos->phy = NULL; + } + + eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); + eqos->config->ops->eqos_remove_resources(dev); + eqos_probe_resources_core(dev); debug("%s: OK\n", __func__); @@ -1528,8 +1806,56 @@ static const struct eth_ops eqos_ops = { .write_hwaddr = eqos_write_hwaddr, }; +static struct eqos_ops eqos_tegra186_ops = { + .eqos_inval_desc = eqos_inval_desc_tegra186, + .eqos_flush_desc = eqos_flush_desc_tegra186, + .eqos_inval_buffer = eqos_inval_buffer_tegra186, + .eqos_flush_buffer = eqos_flush_buffer_tegra186, + .eqos_probe_resources = eqos_probe_resources_tegra186, + .eqos_remove_resources = eqos_remove_resources_tegra186, + .eqos_stop_resets = eqos_stop_resets_tegra186, + .eqos_start_resets = eqos_start_resets_tegra186, + .eqos_stop_clks = eqos_stop_clks_tegra186, + .eqos_start_clks = eqos_start_clks_tegra186, + .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, + .eqos_disable_calibration = eqos_disable_calibration_tegra186, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 +}; + static const struct eqos_config eqos_tegra186_config = { .reg_access_always_ok = false, + .mdio_wait = 10, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, + .interface = eqos_get_interface_tegra186, + .ops = &eqos_tegra186_ops +}; + +static struct eqos_ops eqos_stm32_ops = { + .eqos_inval_desc = eqos_inval_desc_stm32, + .eqos_flush_desc = eqos_flush_desc_stm32, + .eqos_inval_buffer = eqos_inval_buffer_stm32, + .eqos_flush_buffer = eqos_flush_buffer_stm32, + .eqos_probe_resources = eqos_probe_resources_stm32, + .eqos_remove_resources = eqos_remove_resources_stm32, + .eqos_stop_resets = eqos_stop_resets_stm32, + .eqos_start_resets = eqos_start_resets_stm32, + .eqos_stop_clks = eqos_stop_clks_stm32, + .eqos_start_clks = eqos_start_clks_stm32, + .eqos_calibrate_pads = eqos_calibrate_pads_stm32, + .eqos_disable_calibration = eqos_disable_calibration_stm32, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 +}; + +static const struct eqos_config eqos_stm32_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .interface = eqos_get_interface_stm32, + .ops = &eqos_stm32_ops }; static const struct udevice_id eqos_ids[] = { @@ -1537,6 +1863,11 @@ static const struct udevice_id eqos_ids[] = { .compatible = "nvidia,tegra186-eqos", .data = (ulong)&eqos_tegra186_config }, + { + .compatible = "snps,dwmac-4.20a", + .data = (ulong)&eqos_stm32_config + }, + { } }; diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 8e98b4b627bf..22937d89860d 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -37,7 +37,8 @@ #define MAX_PHYS 2 -#define PLL_LOCK_TIME_US 100 +/* max 100 us for PLL lock and 100 us for PHY init */ +#define PLL_INIT_TIME_US 200 #define PLL_PWR_DOWN_TIME_US 5 #define PLL_FVCO 2880 /* in MHz */ #define PLL_INFF_MIN_RATE 19200000 /* in Hz */ @@ -51,13 +52,11 @@ struct pll_params { struct stm32_usbphyc { fdt_addr_t base; struct clk clk; + struct udevice *vdda1v1; + struct udevice *vdda1v8; + struct udevice *vdd3v3; struct stm32_usbphyc_phy { - struct udevice *vdd; - struct udevice *vdda1v1; - struct udevice *vdda1v8; - int index; bool init; - bool powered; } phys[MAX_PHYS]; }; @@ -129,18 +128,6 @@ static bool stm32_usbphyc_is_init(struct stm32_usbphyc *usbphyc) return false; } -static bool stm32_usbphyc_is_powered(struct stm32_usbphyc *usbphyc) -{ - int i; - - for (i = 0; i < MAX_PHYS; i++) { - if (usbphyc->phys[i].powered) - return true; - } - - return false; -} - static int stm32_usbphyc_phy_init(struct phy *phy) { struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); @@ -154,6 +141,24 @@ static int stm32_usbphyc_phy_init(struct phy *phy) if (pllen && stm32_usbphyc_is_init(usbphyc)) goto initialized; + if (usbphyc->vdda1v1) { + ret = regulator_set_enable(usbphyc->vdda1v1, true); + if (ret) + return ret; + } + + if (usbphyc->vdda1v8) { + ret = regulator_set_enable(usbphyc->vdda1v8, true); + if (ret) + return ret; + } + + if (usbphyc->vdd3v3) { + ret = regulator_set_enable(usbphyc->vdd3v3, true); + if (ret) + return ret; + } + if (pllen) { clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); udelay(PLL_PWR_DOWN_TIME_US); @@ -165,11 +170,8 @@ static int stm32_usbphyc_phy_init(struct phy *phy) setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); - /* - * We must wait PLL_LOCK_TIME_US before checking that PLLEN - * bit is still set - */ - udelay(PLL_LOCK_TIME_US); + /* We must wait PLL_INIT_TIME_US before using PHY */ + udelay(PLL_INIT_TIME_US); if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)) return -EIO; @@ -184,6 +186,7 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) { struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + int ret; pr_debug("%s phy ID = %lu\n", __func__, phy->id); usbphyc_phy->init = false; @@ -202,65 +205,20 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN) return -EIO; - - return 0; -} - -static int stm32_usbphyc_phy_power_on(struct phy *phy) -{ - struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); - struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; - int ret; - - pr_debug("%s phy ID = %lu\n", __func__, phy->id); - if (usbphyc_phy->vdda1v1) { - ret = regulator_set_enable(usbphyc_phy->vdda1v1, true); - if (ret) - return ret; - } - - if (usbphyc_phy->vdda1v8) { - ret = regulator_set_enable(usbphyc_phy->vdda1v8, true); - if (ret) - return ret; - } - if (usbphyc_phy->vdd) { - ret = regulator_set_enable(usbphyc_phy->vdd, true); - if (ret) - return ret; - } - - usbphyc_phy->powered = true; - - return 0; -} - -static int stm32_usbphyc_phy_power_off(struct phy *phy) -{ - struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); - struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; - int ret; - - pr_debug("%s phy ID = %lu\n", __func__, phy->id); - usbphyc_phy->powered = false; - - if (stm32_usbphyc_is_powered(usbphyc)) - return 0; - - if (usbphyc_phy->vdda1v1) { - ret = regulator_set_enable(usbphyc_phy->vdda1v1, false); + if (usbphyc->vdda1v1) { + ret = regulator_set_enable(usbphyc->vdda1v1, false); if (ret) return ret; } - if (usbphyc_phy->vdda1v8) { - ret = regulator_set_enable(usbphyc_phy->vdda1v8, false); + if (usbphyc->vdda1v8) { + ret = regulator_set_enable(usbphyc->vdda1v8, false); if (ret) return ret; } - if (usbphyc_phy->vdd) { - ret = regulator_set_enable(usbphyc_phy->vdd, false); + if (usbphyc->vdd3v3) { + ret = regulator_set_enable(usbphyc->vdd3v3, false); if (ret) return ret; } @@ -268,49 +226,23 @@ static int stm32_usbphyc_phy_power_off(struct phy *phy) return 0; } -static int stm32_usbphyc_get_regulator(struct udevice *dev, ofnode node, - char *supply_name, - struct udevice **regulator) -{ - struct ofnode_phandle_args regulator_phandle; - int ret; - - ret = ofnode_parse_phandle_with_args(node, supply_name, - NULL, 0, 0, - ®ulator_phandle); - if (ret) { - dev_err(dev, "Can't find %s property (%d)\n", supply_name, ret); - return ret; - } - - ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, - regulator_phandle.node, - regulator); - - if (ret) { - dev_err(dev, "Can't get %s regulator (%d)\n", supply_name, ret); - return ret; - } - - return 0; -} - static int stm32_usbphyc_of_xlate(struct phy *phy, struct ofnode_phandle_args *args) { - if (args->args_count > 1) { - pr_debug("%s: invalid args_count: %d\n", __func__, - args->args_count); - return -EINVAL; - } + if (args->args_count < 1) + return -ENODEV; if (args->args[0] >= MAX_PHYS) return -ENODEV; - if (args->args_count) - phy->id = args->args[0]; - else - phy->id = 0; + phy->id = args->args[0]; + + if ((phy->id == 0 && args->args_count != 1) || + (phy->id == 1 && args->args_count != 2)) { + dev_err(dev, "invalid number of cells for phy port%ld\n", + phy->id); + return -EINVAL; + } return 0; } @@ -318,8 +250,6 @@ static int stm32_usbphyc_of_xlate(struct phy *phy, static const struct phy_ops stm32_usbphyc_phy_ops = { .init = stm32_usbphyc_phy_init, .exit = stm32_usbphyc_phy_exit, - .power_on = stm32_usbphyc_phy_power_on, - .power_off = stm32_usbphyc_phy_power_off, .of_xlate = stm32_usbphyc_of_xlate, }; @@ -327,7 +257,6 @@ static int stm32_usbphyc_probe(struct udevice *dev) { struct stm32_usbphyc *usbphyc = dev_get_priv(dev); struct reset_ctl reset; - ofnode node; int i, ret; usbphyc->base = dev_read_addr(dev); @@ -351,35 +280,31 @@ static int stm32_usbphyc_probe(struct udevice *dev) reset_deassert(&reset); } - /* - * parse all PHY subnodes in order to populate regulator associated - * to each PHY port - */ - node = dev_read_first_subnode(dev); - for (i = 0; i < MAX_PHYS; i++) { - struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i; - - usbphyc_phy->index = i; - usbphyc_phy->init = false; - usbphyc_phy->powered = false; - ret = stm32_usbphyc_get_regulator(dev, node, "phy-supply", - &usbphyc_phy->vdd); - if (ret) - return ret; - - ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v1-supply", - &usbphyc_phy->vdda1v1); - if (ret) - return ret; + /* get usbphyc regulator */ + ret = device_get_supply_regulator(dev, "vdda1v1-supply", + &usbphyc->vdda1v1); + if (ret) { + dev_err(dev, "Can't get vdda1v1-supply regulator\n"); + return ret; + } - ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v8-supply", - &usbphyc_phy->vdda1v8); - if (ret) - return ret; + ret = device_get_supply_regulator(dev, "vdda1v8-supply", + &usbphyc->vdda1v8); + if (ret) { + dev_err(dev, "Can't get vdda1v8-supply regulator\n"); + return ret; + } - node = dev_read_next_subnode(node); + ret = device_get_supply_regulator(dev, "vdd3v3-supply", + &usbphyc->vdd3v3); + if (ret) { + dev_err(dev, "Can't get vdd3v3-supply regulator\n"); + return ret; } + for (i = 0; i < MAX_PHYS; i++) + usbphyc->phys[i].init = false; + /* Check if second port has to be used for host controller */ if (dev_read_bool(dev, "st,port2-switch-to-host")) setbits_le32(usbphyc->base + STM32_USBPHYC_MISC, SWITHOST); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ad0b8daba622..546613dff731 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -289,6 +289,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 a3a6c6d163b3..d2725f6ca134 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -20,4 +20,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-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c index 755ac08bdf72..0786afe747fc 100644 --- a/drivers/pinctrl/pinctrl-sandbox.c +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -17,6 +17,14 @@ static const char * const sandbox_pins[] = { "W1" }; +static const char * const sandbox_pins_muxing[] = { + "I2C SCL", + "I2C SDA", + "Uart TX", + "Uart RX", + "1-wire gpio", +}; + static const char * const sandbox_groups[] = { "i2c", "serial_a", @@ -56,6 +64,15 @@ static const char *sandbox_get_pin_name(struct udevice *dev, unsigned selector) return sandbox_pins[selector]; } +static int sandbox_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + snprintf(buf, size, "%s", sandbox_pins_muxing[selector]); + + return 0; +} + static int sandbox_get_groups_count(struct udevice *dev) { return ARRAY_SIZE(sandbox_groups); @@ -123,6 +140,7 @@ static int sandbox_pinconf_group_set(struct udevice *dev, const struct pinctrl_ops sandbox_pinctrl_ops = { .get_pins_count = sandbox_get_pins_count, .get_pin_name = sandbox_get_pin_name, + .get_pin_muxing = sandbox_get_pin_muxing, .get_groups_count = sandbox_get_groups_count, .get_group_name = sandbox_get_group_name, .get_functions_count = sandbox_get_functions_count, diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c new file mode 100644 index 000000000000..9b5009aaf83c --- /dev/null +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -0,0 +1,414 @@ +// 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_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, +#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, +}; diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index c38bb212ed74..3608f100dac6 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -127,6 +127,9 @@ static int pinconfig_post_bind(struct udevice *dev) ofnode_get_property(node, "compatible", &ret); if (ret >= 0) continue; + /* If this node has "gpio-controller" property, skip */ + if (ofnode_read_bool(node, "gpio-controller")) + continue; if (ret != -FDT_ERR_NOTFOUND) return ret; @@ -183,7 +186,7 @@ static int pinctrl_select_state_simple(struct udevice *dev) * is the correct one. This is most likely OK as there is * usually only one pinctrl device on the system. */ - ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); + ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev); if (ret) return ret; @@ -249,6 +252,40 @@ int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index) return ops->get_gpio_mux(dev, banknum, index); } +int pinctrl_get_pins_count(struct udevice *dev) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->get_pins_count) + return -ENOSYS; + + return ops->get_pins_count(dev); +} + +int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf, + int size) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->get_pin_name) + return -ENOSYS; + + snprintf(buf, size, ops->get_pin_name(dev, selector)); + + return 0; +} + +int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf, + int size) +{ + struct pinctrl_ops *ops = pinctrl_get_ops(dev); + + if (!ops->get_pin_muxing) + return -ENOSYS; + + return ops->get_pin_muxing(dev, selector, buf, size); +} + /** * pinconfig_post_bind() - post binding for PINCTRL uclass * Recursively bind child nodes as pinconfig devices in case of full pinctrl. diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 31285cdd5784..eb7799ddfda5 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,9 +1,10 @@ #include #include -#include +#include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -14,17 +15,241 @@ DECLARE_GLOBAL_DATA_PTR; #define OTYPE_MSK 1 #define AFR_MASK 0xF +struct stm32_pinctrl_priv { + struct hwspinlock hws; + int pinctrl_ngpios; + struct list_head gpio_dev; +}; + +#ifndef CONFIG_SPL_BUILD +struct stm32_gpio_bank { + struct udevice *gpio_dev; + struct list_head list; +}; + +static char pin_name[PINNAME_SIZE]; +#define PINMUX_MODE_COUNT 5 +static const char * const pinmux_mode[PINMUX_MODE_COUNT] = { + "gpio input", + "gpio output", + "analog", + "unknown", + "alt function", +}; + +static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + u32 af; + u32 alt_shift = (offset % 8) * 4; + u32 alt_index = offset / 8; + + af = (readl(®s->afr[alt_index]) & + GENMASK(alt_shift + 3, alt_shift)) >> alt_shift; + + return af; +} + +static int stm32_populate_gpio_dev_list(struct udevice *dev) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + struct udevice *gpio_dev; + struct udevice *child; + struct stm32_gpio_bank *gpio_bank; + int ret; + + /* + * parse pin-controller sub-nodes (ie gpio bank nodes) and fill + * a list with all gpio device reference which belongs to the + * current pin-controller. This list is used to find pin_name and + * pin muxing + */ + list_for_each_entry(child, &dev->child_head, sibling_node) { + ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, + &gpio_dev); + if (ret < 0) + continue; + + gpio_bank = malloc(sizeof(*gpio_bank)); + if (!gpio_bank) { + dev_err(dev, "Not enough memory\n"); + return -ENOMEM; + } + + gpio_bank->gpio_dev = gpio_dev; + list_add_tail(&gpio_bank->list, &priv->gpio_dev); + } + + return 0; +} + +static int stm32_pinctrl_get_pins_count(struct udevice *dev) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv; + struct stm32_gpio_bank *gpio_bank; + + /* + * if get_pins_count has already been executed once on this + * pin-controller, no need to run it again + */ + if (priv->pinctrl_ngpios) + return priv->pinctrl_ngpios; + + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); + /* + * walk through all banks to retrieve the pin-controller + * pins number + */ + list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { + uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); + + priv->pinctrl_ngpios += uc_priv->gpio_count; + } + + return priv->pinctrl_ngpios; +} + +static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, + unsigned int selector, + unsigned int *idx) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + struct stm32_gpio_bank *gpio_bank; + struct gpio_dev_priv *uc_priv; + int pin_count = 0; + + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); + + /* look up for the bank which owns the requested pin */ + list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { + uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); + + if (selector < (pin_count + uc_priv->gpio_count)) { + /* + * we found the bank, convert pin selector to + * gpio bank index + */ + *idx = stm32_offset_to_index(gpio_bank->gpio_dev, + selector - pin_count); + if (*idx < 0) + return NULL; + + return gpio_bank->gpio_dev; + } + pin_count += uc_priv->gpio_count; + } + + return NULL; +} + +static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct gpio_dev_priv *uc_priv; + struct udevice *gpio_dev; + unsigned int gpio_idx; + + /* look up for the bank which owns the requested pin */ + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); + if (!gpio_dev) { + snprintf(pin_name, PINNAME_SIZE, "Error"); + } else { + uc_priv = dev_get_uclass_priv(gpio_dev); + + snprintf(pin_name, PINNAME_SIZE, "%s%d", + uc_priv->bank_name, + gpio_idx); + } + + return pin_name; +} + +static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, + int size) +{ + struct udevice *gpio_dev; + const char *label; + int mode; + int af_num; + unsigned int gpio_idx; + + /* look up for the bank which owns the requested pin */ + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); + + if (!gpio_dev) + return -ENODEV; + + mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label); + + dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n", + selector, gpio_idx, mode); + + + switch (mode) { + case GPIOF_UNKNOWN: + /* should never happen */ + return -EINVAL; + case GPIOF_UNUSED: + snprintf(buf, size, "%s", pinmux_mode[mode]); + break; + case GPIOF_FUNC: + af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx); + snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num); + break; + case GPIOF_OUTPUT: + case GPIOF_INPUT: + snprintf(buf, size, "%s %s", + pinmux_mode[mode], label ? label : ""); + break; + } + + return 0; +} +#endif + +int stm32_pinctrl_probe(struct udevice *dev) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + int err; + + /* hwspinlock property is optional, just log the error */ + err = hwspinlock_get_by_index(dev, 0, &priv->hws); + if (err) + debug("%s: hwspinlock_get_by_index may have failed (%d)\n", + __func__, err); + + INIT_LIST_HEAD(&priv->gpio_dev); + + return 0; +} + static int stm32_gpio_config(struct gpio_desc *desc, const struct stm32_gpio_ctl *ctl) { struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); struct stm32_gpio_regs *regs = priv->regs; + struct stm32_pinctrl_priv *pinctrl_priv; + int ret; u32 index; if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 || ctl->pupd > 2 || ctl->speed > 3) return -EINVAL; + pinctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); + + ret = hwspinlock_lock_timeout(&pinctrl_priv->hws, 10); + if (ret == -ETIME) { + dev_err(desc->dev, "HWSpinlock timeout\n"); + return ret; + } + index = (desc->offset & 0x07) * 4; clrsetbits_le32(®s->afr[desc->offset >> 3], AFR_MASK << index, ctl->af << index); @@ -39,6 +264,8 @@ static int stm32_gpio_config(struct gpio_desc *desc, index = desc->offset; clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); + hwspinlock_unlock(&pinctrl_priv->hws); + return 0; } @@ -100,9 +327,9 @@ static int stm32_pinctrl_config(int offset) int rv, len; /* - * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for - * usart1) of pin controller phandle "pinctrl-0" - * */ + * check for "pinmux" property in each subnode of pin controller + * phandle "pinctrl-0" (e.g. pins1 and pins2 for usart1) + */ fdt_for_each_subnode(offset, gd->fdt_blob, offset) { struct stm32_gpio_dsc gpio_dsc; struct stm32_gpio_ctl gpio_ctl; @@ -182,6 +409,11 @@ static struct pinctrl_ops stm32_pinctrl_ops = { #else /* PINCTRL_FULL */ .set_state_simple = stm32_pinctrl_set_state_simple, #endif /* PINCTRL_FULL */ +#ifndef CONFIG_SPL_BUILD + .get_pin_name = stm32_pinctrl_get_pin_name, + .get_pins_count = stm32_pinctrl_get_pins_count, + .get_pin_muxing = stm32_pinctrl_get_pin_muxing, +#endif }; static const struct udevice_id stm32_pinctrl_ids[] = { @@ -195,9 +427,11 @@ static const struct udevice_id stm32_pinctrl_ids[] = { }; U_BOOT_DRIVER(pinctrl_stm32) = { - .name = "pinctrl_stm32", - .id = UCLASS_PINCTRL, - .of_match = stm32_pinctrl_ids, - .ops = &stm32_pinctrl_ops, - .bind = dm_scan_fdt_dev, + .name = "pinctrl_stm32", + .id = UCLASS_PINCTRL, + .of_match = stm32_pinctrl_ids, + .ops = &stm32_pinctrl_ops, + .bind = dm_scan_fdt_dev, + .probe = stm32_pinctrl_probe, + .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), }; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index cba48e12da46..6b8f5b4e7ed0 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -217,10 +217,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 29ca4429332a..4ba6bf647aff 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -22,7 +22,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_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 new file mode 100644 index 000000000000..18f46fcc2c03 --- /dev/null +++ b/drivers/power/pmic/stpmic1.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STPMIC1_NUM_OF_REGS 0x100 + +#if CONFIG_IS_ENABLED(DM_REGULATOR) +#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, +}; + +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 /* DM_REGULATOR */ + +DECLARE_GLOBAL_DATA_PTR; + +static int stpmic1_reg_count(struct udevice *dev) +{ + return STPMIC1_NUM_OF_REGS; +} + +static int stpmic1_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 stpmic1_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 stpmic1_bind(struct udevice *dev) +{ +#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!"); + return -ENXIO; + } + dev_dbg(dev, "found regulators subnode\n"); + + children = pmic_bind_children(dev, regulators_node, + stpmic1_children_info); + if (!children) + 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; +} + +static struct dm_pmic_ops stpmic1_ops = { + .reg_count = stpmic1_reg_count, + .read = stpmic1_read, + .write = stpmic1_write, +}; + +static const struct udevice_id stpmic1_ids[] = { + { .compatible = "st,stpmic1" }, + { } +}; + +U_BOOT_DRIVER(pmic_stpmic1) = { + .name = "stpmic1_pmic", + .id = UCLASS_PMIC, + .of_match = stpmic1_ids, + .bind = stpmic1_bind, + .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) +{ + 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 diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c deleted file mode 100644 index 82351b661370..000000000000 --- 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!"); - 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/Kconfig b/drivers/power/regulator/Kconfig index 2561a8a85616..268f7cafeb03 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -221,11 +221,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 a5f5683d6e94..7a8888a9ae9f 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -23,4 +23,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_STPMIC1) += stpmic1.o diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index a99aa783107e..872e39483e3f 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -35,7 +35,9 @@ static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) /* Set type to fixed */ uc_pdata->type = REGULATOR_TYPE_FIXED; - if (dev_read_bool(dev, "enable-active-high")) + if (!dev_read_bool(dev, "enable-active-high")) + flags |= GPIOD_ACTIVE_LOW; + if (uc_pdata->boot_on) flags |= GPIOD_IS_OUT_ACTIVE; /* Get fixed regulator optional enable GPIO desc */ diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4da8e43259fc..4511625ff251 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -106,10 +106,15 @@ int regulator_get_enable(struct udevice *dev) int regulator_set_enable(struct udevice *dev, bool enable) { const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + struct dm_regulator_uclass_platdata *uc_pdata; if (!ops || !ops->set_enable) return -ENOSYS; + uc_pdata = dev_get_uclass_platdata(dev); + if (!enable && uc_pdata->always_on) + return -EACCES; + return ops->set_enable(dev, enable); } diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c new file mode 100644 index 000000000000..50ef2a21d181 --- /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 stpmic1_range { + int min_uv; + int min_sel; + int max_sel; + int step; +}; + +struct stpmic1_output { + const struct stpmic1_range *ranges; + int nbranges; +}; + +#define STPMIC1_MODE(_id, _val, _name) { \ + .id = _id, \ + .register_value = _val, \ + .name = _name, \ +} + +#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 STPMIC1_OUTPUT(_ranges, _nbranges) { \ + .ranges = _ranges, \ + .nbranges = _nbranges, \ +} + +static int stpmic1_output_find_uv(int sel, + const struct stpmic1_output *output) +{ + const struct stpmic1_range *range; + int i; + + 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; + } + + return -EINVAL; +} + +static int stpmic1_output_find_sel(int uv, + const struct stpmic1_output *output) +{ + const struct stpmic1_range *range; + int i; + + for (i = 0, range = output->ranges; + i < output->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 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 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 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 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 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[] = { + 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_MAIN_CR(buck)); + if (sel < 0) + return sel; + + sel &= STPMIC1_BUCK_VOUT_MASK; + sel >>= STPMIC1_BUCK_VOUT_SHIFT; + + return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]); +} + +static int stpmic1_buck_get_value(struct udevice *dev) +{ + return stpmic1_buck_get_uv(dev->parent, dev->driver_data - 1); +} + +static int stpmic1_buck_set_value(struct udevice *dev, int uv) +{ + int sel, buck = dev->driver_data - 1; + + sel = stpmic1_output_find_sel(uv, &buck_voltage_range[buck]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMIC1_BUCKX_MAIN_CR(buck), + STPMIC1_BUCK_VOUT_MASK, + sel << STPMIC1_BUCK_VOUT_SHIFT); +} + +static int stpmic1_buck_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMIC1_BUCK_ENA ? true : false; +} + +static int stpmic1_buck_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + 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 (stpmic1_buck_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + 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, + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1), + STPMIC1_BUCK_ENA, enable ? STPMIC1_BUCK_ENA : 0); + mdelay(delay); + + return ret; +} + +static int stpmic1_buck_get_mode(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1)); + if (ret < 0) + return ret; + + 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_MAIN_CR(dev->driver_data - 1), + STPMIC1_BUCK_PREG_MODE, + mode ? STPMIC1_BUCK_PREG_MODE : 0); +} + +static int stpmic1_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMIC1_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 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(stpmic1_buck) = { + .name = "stpmic1_buck", + .id = UCLASS_REGULATOR, + .ops = &stpmic1_buck_ops, + .probe = stpmic1_buck_probe, +}; + +/* + * LDO regulators + */ + +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 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 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 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 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[] = { + 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 stpmic1_ldo_get_value(struct udevice *dev) +{ + int sel, ldo = dev->driver_data - 1; + + sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo)); + if (sel < 0) + return sel; + + /* ldo4 => 3,3V */ + if (ldo == STPMIC1_LDO4) + return STPMIC1_LDO4_UV; + + sel &= STPMIC1_LDO12356_VOUT_MASK; + sel >>= STPMIC1_LDO12356_VOUT_SHIFT; + + /* ldo3, sel = 31 => BUCK2/2 */ + if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL) + return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2; + + return stpmic1_output_find_uv(sel, &ldo_voltage_range[ldo]); +} + +static int stpmic1_ldo_set_value(struct udevice *dev, int uv) +{ + int sel, ldo = dev->driver_data - 1; + + /* ldo4 => not possible */ + if (ldo == STPMIC1_LDO4) + return -EINVAL; + + sel = stpmic1_output_find_sel(uv, &ldo_voltage_range[ldo]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMIC1_LDOX_MAIN_CR(ldo), + STPMIC1_LDO12356_VOUT_MASK, + sel << STPMIC1_LDO12356_VOUT_SHIFT); +} + +static int stpmic1_ldo_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMIC1_LDO_ENA ? true : false; +} + +static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + 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 (stpmic1_ldo_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + 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, + STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1), + STPMIC1_LDO_ENA, enable ? STPMIC1_LDO_ENA : 0); + mdelay(delay); + + return ret; +} + +static int stpmic1_ldo_get_mode(struct udevice *dev) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMIC1_LDO3) + return -EINVAL; + + 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_VOUT_MASK; + ret >>= STPMIC1_LDO12356_VOUT_SHIFT; + + return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE : + STPMIC1_LDO_MODE_NORMAL; +} + +static int stpmic1_ldo_set_mode(struct udevice *dev, int mode) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMIC1_LDO3) + return -EINVAL; + + 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_VOUT_MASK; + ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT; + case STPMIC1_LDO_MODE_NORMAL: + ret &= ~STPMIC1_LDO3_MODE; + break; + case STPMIC1_LDO_MODE_BYPASS: + ret |= STPMIC1_LDO3_MODE; + break; + } + + return pmic_reg_write(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo), ret); +} + +static int stpmic1_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + 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 == STPMIC1_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 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(stpmic1_ldo) = { + .name = "stpmic1_ldo", + .id = UCLASS_REGULATOR, + .ops = &stpmic1_ldo_ops, + .probe = stpmic1_ldo_probe, +}; + +/* + * VREF DDR regulator + */ + +static int stpmic1_vref_ddr_get_value(struct udevice *dev) +{ + /* BUCK2/2 */ + return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2; +} + +static int stpmic1_vref_ddr_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMIC1_REFDDR_MAIN_CR); + if (ret < 0) + return false; + + return ret & STPMIC1_VREF_ENA ? true : false; +} + +static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable) +{ + 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 (stpmic1_vref_ddr_get_enable(dev) == enable) + return 0; + + ret = pmic_clrsetbits(dev->parent, STPMIC1_REFDDR_MAIN_CR, + STPMIC1_VREF_ENA, enable ? STPMIC1_VREF_ENA : 0); + mdelay(delay); + + return ret; +} + +static int stpmic1_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 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(stpmic1_vref_ddr) = { + .name = "stpmic1_vref_ddr", + .id = UCLASS_REGULATOR, + .ops = &stpmic1_vref_ddr_ops, + .probe = stpmic1_vref_ddr_probe, +}; + +/* + * BOOST regulator + */ + +static int stpmic1_boost_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); + if (ret < 0) + return 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_BST_SW_CR); + if (ret < 0) + return ret; + + if (!enable && ret & STPMIC1_PWR_SW_ON) + return -EINVAL; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(ret & STPMIC1_BST_ON) == enable) + return 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); + + return ret; +} + +static int stpmic1_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 stpmic1_boost_ops = { + .get_enable = stpmic1_boost_get_enable, + .set_enable = stpmic1_boost_set_enable, +}; + +U_BOOT_DRIVER(stpmic1_boost) = { + .name = "stpmic1_boost", + .id = UCLASS_REGULATOR, + .ops = &stpmic1_boost_ops, + .probe = stpmic1_boost_probe, +}; + +/* + * USB power switch + */ + +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_BST_SW_CR); + if (ret < 0) + return false; + + return ret & mask ? true : false; +} + +static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable) +{ + uint mask = 1 << dev->driver_data; + int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS : + STPMIC1_DEFAULT_STOP_DELAY_MS; + int ret; + + ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR); + 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 & 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_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_BST_SW_CR, + mask, enable ? mask : 0); + mdelay(delay); + + return ret; +} + +static int stpmic1_pwr_sw_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMIC1_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 stpmic1_pwr_sw_ops = { + .get_enable = stpmic1_pwr_sw_get_enable, + .set_enable = stpmic1_pwr_sw_set_enable, +}; + +U_BOOT_DRIVER(stpmic1_pwr_sw) = { + .name = "stpmic1_pwr_sw", + .id = UCLASS_REGULATOR, + .ops = &stpmic1_pwr_sw_ops, + .probe = stpmic1_pwr_sw_probe, +}; diff --git a/drivers/power/regulator/stpmu1.c b/drivers/power/regulator/stpmu1.c deleted file mode 100644 index 6eb2420b6bcb..000000000000 --- a/drivers/power/regulator/stpmu1.c +++ /dev/null @@ -1,671 +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(600000, 0, 30, 25000), - STPMU1_RANGE(1350000, 31, 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/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig index b9c816662c4c..761de09af56c 100644 --- a/drivers/ram/stm32mp1/Kconfig +++ b/drivers/ram/stm32mp1/Kconfig @@ -10,3 +10,32 @@ config STM32MP1_DDR family: support for LPDDR2, LPDDR3 and DDR3 the SDRAM parameters for controleur and phy need to be provided in device tree (computed by DDR tuning tools) + +config STM32MP1_DDR_INTERACTIVE + bool "STM32MP1 DDR driver : interactive support" + depends on STM32MP1_DDR + help + activate interactive support in STM32MP1 DDR controller driver + used for DDR tuning tools + to enter in intercative mode type 'd' during SPL DDR driver + initialisation + +config STM32MP1_DDR_INTERACTIVE_FORCE + bool "STM32MP1 DDR driver : force interactive mode" + depends on STM32MP1_DDR_INTERACTIVE + default n + help + force interactive mode in STM32MP1 DDR controller driver + skip the polling of character 'd' in console + useful when SPL is loaded in sysram + directly by programmer + +config STM32MP1_DDR_TUNING + bool "STM32MP1 DDR driver : support of tuning" + depends on SPL && STM32MP1_DDR_INTERACTIVE + default y + help + activate tuning command in STM32MP1 DDR interactive mode + used for DDR tuning tools + - DQ Deskew algorithm + - DQS Trimming diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile index 79eb028fab6c..bc292d16d1d4 100644 --- a/drivers/ram/stm32mp1/Makefile +++ b/drivers/ram/stm32mp1/Makefile @@ -5,3 +5,10 @@ obj-y += stm32mp1_ram.o obj-y += stm32mp1_ddr.o + +obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o stm32mp1_tests.o +obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o + +ifneq ($(DDR_INTERACTIVE),) +CFLAGS_stm32mp1_interactive.o += -DCONFIG_STM32MP1_DDR_INTERACTIVE_FORCE=y +endif diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index c7c3ba70a4ec..a83ea39162ad 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -165,6 +165,32 @@ static const struct reg_desc ddrphy_cal[] = { DDRPHY_REG_CAL(dx3dqstr), }; +#define DDR_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrctl, x),\ + INVALID_OFFSET} + +static const struct reg_desc ddr_dyn[] = { + DDR_REG_DYN(stat), + DDR_REG_DYN(init0), + DDR_REG_DYN(dfimisc), + DDR_REG_DYN(dfistat), + DDR_REG_DYN(swctl), + DDR_REG_DYN(swstat), + DDR_REG_DYN(pctrl_0), + DDR_REG_DYN(pctrl_1), +}; + +#define DDRPHY_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrphy, x),\ + INVALID_OFFSET} + +static const struct reg_desc ddrphy_dyn[] = { + DDRPHY_REG_DYN(pir), + DDRPHY_REG_DYN(pgsr), +}; + enum reg_type { REG_REG, REG_TIMING, @@ -173,6 +199,11 @@ enum reg_type { REGPHY_REG, REGPHY_TIMING, REGPHY_CAL, +/* dynamic registers => managed in driver or not changed, + * can be dumped in interactive mode + */ + REG_DYN, + REGPHY_DYN, REG_TYPE_NB }; @@ -206,6 +237,10 @@ const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE}, [REGPHY_CAL] = { "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE}, +[REG_DYN] = { + "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE}, +[REGPHY_DYN] = { + "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE}, }; const char *base_name[] = { @@ -277,10 +312,247 @@ void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) ddrphy_idone_wait(phy); } +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE +static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc) +{ + unsigned int *ptr; + + ptr = (unsigned int *)(base_addr + desc->offset); +#ifdef DEBUG + printf("[0x%08x] %s= 0x%08x\n", + (u32)ptr, desc->name, readl(ptr)); +#else + printf("%s= 0x%08x\n", desc->name, readl(ptr)); +#endif +} + +static void stm32mp1_dump_param_desc(u32 par_addr, const struct reg_desc *desc) +{ + unsigned int *ptr; + + ptr = (unsigned int *)(par_addr + desc->par_offset); + printf("%s= 0x%08x\n", desc->name, readl(ptr)); +} + +static const struct reg_desc *found_reg(const char *name, enum reg_type *type) +{ + unsigned int i, j; + const struct reg_desc *desc; + + for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { + desc = ddr_registers[i].desc; + for (j = 0; j < ddr_registers[i].size; j++) { + if (strcmp(name, desc[j].name) == 0) { + *type = i; + return &desc[j]; + } + } + } + *type = REG_TYPE_NB; + return NULL; +} + +int stm32mp1_dump_reg(const struct ddr_info *priv, + const char *name) +{ + unsigned int i, j; + const struct reg_desc *desc; + u32 base_addr; + enum base_type p_base; + enum reg_type type; + const char *p_name; + enum base_type filter = NONE_BASE; + int result = -1; + + if (name) { + if (strcmp(name, base_name[DDR_BASE]) == 0) + filter = DDR_BASE; + else if (strcmp(name, base_name[DDRPHY_BASE]) == 0) + filter = DDRPHY_BASE; + } + + for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { + p_base = ddr_registers[i].base; + p_name = ddr_registers[i].name; + if (!name || (filter == p_base || !strcmp(name, p_name))) { + result = 0; + desc = ddr_registers[i].desc; + base_addr = get_base_addr(priv, p_base); + printf("==%s.%s==\n", base_name[p_base], p_name); + for (j = 0; j < ddr_registers[i].size; j++) + stm32mp1_dump_reg_desc(base_addr, &desc[j]); + } + } + if (result) { + desc = found_reg(name, &type); + if (desc) { + p_base = ddr_registers[type].base; + base_addr = get_base_addr(priv, p_base); + stm32mp1_dump_reg_desc(base_addr, desc); + result = 0; + } + } + return result; +} + +void stm32mp1_edit_reg(const struct ddr_info *priv, + char *name, char *string) +{ + unsigned long *ptr, value; + enum reg_type type; + enum base_type base; + const struct reg_desc *desc; + u32 base_addr; + + desc = found_reg(name, &type); + + if (!desc) { + printf("%s not found\n", name); + return; + } + if (strict_strtoul(string, 16, &value) < 0) { + printf("invalid value %s\n", string); + return; + } + base = ddr_registers[type].base; + base_addr = get_base_addr(priv, base); + ptr = (unsigned long *)(base_addr + desc->offset); + writel(value, ptr); +#ifdef DEBUG + printf("[0x%08x] %s= 0x%08lx (0x%08x)\n", + (u32)ptr, desc->name, value, readl(ptr)); +#else + printf("%s= 0x%08x\n", desc->name, readl(ptr)); +#endif +} + +static u32 get_par_addr(const struct stm32mp1_ddr_config *config, + enum reg_type type) +{ + u32 par_addr = 0x0; + + switch (type) { + case REG_REG: + par_addr = (u32)&config->c_reg; + break; + case REG_TIMING: + par_addr = (u32)&config->c_timing; + break; + case REG_PERF: + par_addr = (u32)&config->c_perf; + break; + case REG_MAP: + par_addr = (u32)&config->c_map; + break; + case REGPHY_REG: + par_addr = (u32)&config->p_reg; + break; + case REGPHY_TIMING: + par_addr = (u32)&config->p_timing; + break; + case REGPHY_CAL: + par_addr = (u32)&config->p_cal; + break; + case REG_DYN: + case REGPHY_DYN: + case REG_TYPE_NB: + par_addr = (u32)NULL; + break; + } + + return par_addr; +} + +int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config, + const char *name) +{ + unsigned int i, j; + const struct reg_desc *desc; + u32 par_addr; + enum base_type p_base; + enum reg_type type; + const char *p_name; + enum base_type filter = NONE_BASE; + int result = -EINVAL; + + if (name) { + if (strcmp(name, base_name[DDR_BASE]) == 0) + filter = DDR_BASE; + else if (strcmp(name, base_name[DDRPHY_BASE]) == 0) + filter = DDRPHY_BASE; + } + + for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { + par_addr = get_par_addr(config, i); + if (!par_addr) + continue; + p_base = ddr_registers[i].base; + p_name = ddr_registers[i].name; + if (!name || (filter == p_base || !strcmp(name, p_name))) { + result = 0; + desc = ddr_registers[i].desc; + printf("==%s.%s==\n", base_name[p_base], p_name); + for (j = 0; j < ddr_registers[i].size; j++) + stm32mp1_dump_param_desc(par_addr, &desc[j]); + } + } + if (result) { + desc = found_reg(name, &type); + if (desc) { + par_addr = get_par_addr(config, type); + if (par_addr) { + stm32mp1_dump_param_desc(par_addr, desc); + result = 0; + } + } + } + return result; +} + +void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config, + char *name, char *string) +{ + unsigned long *ptr, value; + enum reg_type type; + const struct reg_desc *desc; + u32 par_addr; + + desc = found_reg(name, &type); + if (!desc) { + printf("%s not found\n", name); + return; + } + if (strict_strtoul(string, 16, &value) < 0) { + printf("invalid value %s\n", string); + return; + } + par_addr = get_par_addr(config, type); + if (!par_addr) { + printf("no parameter %s\n", name); + return; + } + ptr = (unsigned long *)(par_addr + desc->par_offset); + writel(value, ptr); + printf("%s= 0x%08x\n", desc->name, readl(ptr)); +} +#endif + +__weak bool stm32mp1_ddr_interactive(void *priv, + enum stm32mp1_ddr_interact_step step, + const struct stm32mp1_ddr_config *config) +{ + return false; +} + +#define INTERACTIVE(step)\ + stm32mp1_ddr_interactive(priv, step, config) + /* start quasi dynamic register update */ static void start_sw_done(struct stm32mp1_ddrctl *ctl) { clrbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); + debug("[0x%08x] swctl = 0x%08x\n", + (u32)&ctl->swctl, readl(&ctl->swctl)); } /* wait quasi dynamic register update */ @@ -312,7 +584,7 @@ static void wait_operating_mode(struct ddr_info *priv, int mode) /* self-refresh due to software => check also STAT.selfref_type */ if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) { mask |= DDRCTRL_STAT_SELFREF_TYPE_MASK; - stat |= DDRCTRL_STAT_SELFREF_TYPE_SR; + val |= DDRCTRL_STAT_SELFREF_TYPE_SR; } else if (mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) { /* normal mode: handle also automatic self refresh */ mask2 = DDRCTRL_STAT_OPERATING_MODE_MASK | @@ -332,6 +604,182 @@ static void wait_operating_mode(struct ddr_info *priv, int mode) debug("[0x%08x] stat = 0x%08x\n", (u32)&priv->ctl->stat, stat); } +/* Mode Register Writes (MRW or MRS) */ +void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) +{ + u32 mrctrl0; + + debug("MRS: %d = %x\n", addr, data); + + /* 1. Poll MRSTAT.mr_wr_busy until it is '0'. + * This checks that there is no outstanding MR transaction. + * No writes should be performed to MRCTRL0 and MRCTRL1 + * if MRSTAT.mr_wr_busy = 1. + */ + while (readl(&priv->ctl->mrstat) & DDRCTRL_MRSTAT_MR_WR_BUSY) + ; + + /* 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank + * and (for MRWs) MRCTRL1.mr_data to define the MR transaction. + */ + mrctrl0 = DDRCTRL_MRCTRL0_MR_TYPE_WRITE | + DDRCTRL_MRCTRL0_MR_RANK_ALL | + ((addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) + & DDRCTRL_MRCTRL0_MR_ADDR_MASK); + writel(mrctrl0, &priv->ctl->mrctrl0); + debug("[0x%08x] mrctrl0 = 0x%08x (0x%08x)\n", + (u32)&priv->ctl->mrctrl0, + readl(&priv->ctl->mrctrl0), mrctrl0); + writel(data, &priv->ctl->mrctrl1); + debug("[0x%08x] mrctrl1 = 0x%08x\n", + (u32)&priv->ctl->mrctrl1, readl(&priv->ctl->mrctrl1)); + + /* 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This + * bit is self-clearing, and triggers the MR transaction. + * The uMCTL2 then asserts the MRSTAT.mr_wr_busy while it performs + * the MR transaction to SDRAM, and no further accesses can be + * initiated until it is deasserted + */ + mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR; + writel(mrctrl0, &priv->ctl->mrctrl0); + + while (readl(&priv->ctl->mrstat) & DDRCTRL_MRSTAT_MR_WR_BUSY) + ; + debug("[0x%08x] mrctrl0 = 0x%08x\n", + (u32)&priv->ctl->mrctrl0, mrctrl0); +} + +/* switch DDR3 from DLL-on to DLL-off */ +static void ddr3_dll_off(struct ddr_info *priv) +{ + u32 mr1 = readl(&priv->phy->mr1); + u32 mr2 = readl(&priv->phy->mr2); + u32 dbgcam; + + debug("%s: entry\n", __func__); + debug("mr1: 0x%08x\n", mr1); + debug("mr2: 0x%08x\n", mr2); + /* 1. Set the DBG1.dis_hif = 1. + * This prevents further reads/writes being received on the HIF. + */ + setbits_le32(&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); + debug("[0x%08x] dbg1 = 0x%08x\n", + (u32)&priv->ctl->dbg1, readl(&priv->ctl->dbg1)); + + /* 2. Ensure all commands have been flushed from the uMCTL2 by polling + * DBGCAM.wr_data_pipeline_empty = 1, + * DBGCAM.rd_data_pipeline_empty = 1, + * DBGCAM.dbg_wr_q_depth = 0 , + * DBGCAM.dbg_lpr_q_depth = 0, and + * DBGCAM.dbg_hpr_q_depth = 0. + */ + do { + dbgcam = readl(&priv->ctl->dbgcam); + debug("[0x%08x] dbgcam = 0x%08x\n", + (u32)&priv->ctl->dbgcam, dbgcam); + } while (((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) == + DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) && + !(dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH)); + + /* 3. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) + * to disable RTT_NOM: + * a. DDR3: Write to MR1[9], MR1[6] and MR1[2] + * b. DDR4: Write to MR1[10:8] + */ + mr1 &= ~(BIT(9) | BIT(6) | BIT(2)); + mode_register_write(priv, 1, mr1); + + /* 4. For DDR4 only: Perform an MRS command + * (using MRCTRL0 and MRCTRL1 registers) to write to MR5[8:6] + * to disable RTT_PARK + */ + + /* 5. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) + * to write to MR2[10:9], to disable RTT_WR + * (and therefore disable dynamic ODT). + * This applies for both DDR3 and DDR4. + */ + mr2 &= ~GENMASK(10, 9); + mode_register_write(priv, 2, mr2); + + /* 6. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) + * to disable the DLL. The timing of this MRS is automatically + * handled by the uMCTL2. + * a. DDR3: Write to MR1[0] + * b. DDR4: Write to MR1[0] + */ + mr1 |= BIT(0); + mode_register_write(priv, 1, mr1); + + /* 7. Put the SDRAM into self-refresh mode by setting + * PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure + * the DDRC has entered self-refresh. + */ + setbits_le32(&priv->ctl->pwrctl, + DDRCTRL_PWRCTL_SELFREF_SW); + debug("[0x%08x] pwrctl = 0x%08x\n", + (u32)&priv->ctl->pwrctl, + readl(&priv->ctl->pwrctl)); + + /* 8. Wait until STAT.operating_mode[1:0]==11 indicating that the + * DWC_ddr_umctl2 core is in self-refresh mode. + * Ensure transition to self-refresh was due to software + * by checking that STAT.selfref_type[1:0]=2. + */ + wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_SR); + + /* 9. Set the MSTR.dll_off_mode = 1. + * warning: MSTR.dll_off_mode is a quasi-dynamic type 2 field + */ + start_sw_done(priv->ctl); + + setbits_le32(&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE); + debug("[0x%08x] mstr = 0x%08x\n", + (u32)&priv->ctl->mstr, + readl(&priv->ctl->mstr)); + + wait_sw_done_ack(priv->ctl); + + /* 10. Change the clock frequency to the desired value. */ + + /* 11. Update any registers which may be required to change for the new + * frequency. This includes static and dynamic registers. + * This includes both uMCTL2 registers and PHY registers. + */ + /* change Bypass Mode Frequency Range */ + if (clk_get_rate(&priv->clk) < 100000000) + clrbits_le32(&priv->phy->dllgcr, DDRPHYC_DLLGCR_BPS200); + else + setbits_le32(&priv->phy->dllgcr, DDRPHYC_DLLGCR_BPS200); + + setbits_le32(&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS); + + setbits_le32(&priv->phy->dx0dllcr, DDRPHYC_DXNDLLCR_DLLDIS); + setbits_le32(&priv->phy->dx1dllcr, DDRPHYC_DXNDLLCR_DLLDIS); + setbits_le32(&priv->phy->dx2dllcr, DDRPHYC_DXNDLLCR_DLLDIS); + setbits_le32(&priv->phy->dx3dllcr, DDRPHYC_DXNDLLCR_DLLDIS); + + /* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */ + clrbits_le32(&priv->ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); + wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + + /* 13. If ZQCTL0.dis_srx_zqcl = 0, the uMCTL2 performs a ZQCL command + * at this point. + */ + + /* 14. Perform MRS commands as required to re-program timing registers + * in the SDRAM for the new frequency + * (in particular, CL, CWL and WR may need to be changed). + */ + + /* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes.*/ + clrbits_le32(&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); + debug("[0x%08x] dbg1 = 0x%08x\n", + (u32)&priv->ctl->dbg1, readl(&priv->ctl->dbg1)); + + debug("%s: exit\n", __func__); +} + void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) { start_sw_done(ctl); @@ -355,7 +803,7 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, } /* board-specific DDR power initializations. */ -__weak int board_ddr_power_init(void) +__weak int board_ddr_power_init(enum ddr_type ddr_type) { return 0; } @@ -365,16 +813,25 @@ void stm32mp1_ddr_init(struct ddr_info *priv, const struct stm32mp1_ddr_config *config) { u32 pir; - int ret; + int ret = -EINVAL; - ret = board_ddr_power_init(); + if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) + ret = board_ddr_power_init(STM32MP_DDR3); + else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) + ret = board_ddr_power_init(STM32MP_LPDDR2); + else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) + ret = board_ddr_power_init(STM32MP_LPDDR3); if (ret) panic("ddr power init failed\n"); +start: + debug("%s entry\n", __func__); + debug("name = %s\n", config->info.name); - debug("speed = %d MHz\n", config->info.speed); + debug("speed = %d kHz\n", config->info.speed); debug("size = 0x%x\n", config->info.size); + /* * 1. Program the DWC_ddr_umctl2 registers * 1.1 RESETS: presetn, core_ddrc_rstn, aresetn @@ -389,7 +846,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv, /* 1.2. start CLOCK */ if (stm32mp1_ddr_clk_enable(priv, config->info.speed)) - panic("invalid DRAM clock : %d MHz\n", + panic("invalid DRAM clock : %d kHz\n", config->info.speed); /* 1.3. deassert reset */ @@ -401,11 +858,12 @@ void stm32mp1_ddr_init(struct ddr_info *priv, */ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); -/* 1.4. wait 4 cycles for synchronization */ - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); +/* 1.4. wait 128 cycles to permit initialization of end logic */ + udelay(2); + /* for PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */ + + if (INTERACTIVE(STEP_DDR_RESET)) + goto start; /* 1.5. initialize registers ddr_umctl2 */ /* Stop uMCTL2 before PHY is ready */ @@ -414,6 +872,17 @@ void stm32mp1_ddr_init(struct ddr_info *priv, (u32)&priv->ctl->dfimisc, readl(&priv->ctl->dfimisc)); set_reg(priv, REG_REG, &config->c_reg); + + /* DDR3 = don't set DLLOFF for init mode */ + if ((config->c_reg.mstr & + (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) + == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { + debug("deactivate DLL OFF in mstr\n"); + clrbits_le32(&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE); + debug("[0x%08x] mstr = 0x%08x\n", + (u32)&priv->ctl->mstr, readl(&priv->ctl->mstr)); + } + set_reg(priv, REG_TIMING, &config->c_timing); set_reg(priv, REG_MAP, &config->c_map); @@ -421,9 +890,14 @@ void stm32mp1_ddr_init(struct ddr_info *priv, clrsetbits_le32(&priv->ctl->init0, DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK, DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL); + debug("[0x%08x] init0 = 0x%08x\n", + (u32)&priv->ctl->init0, readl(&priv->ctl->init0)); set_reg(priv, REG_PERF, &config->c_perf); + if (INTERACTIVE(STEP_CTL_INIT)) + goto start; + /* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); @@ -436,6 +910,19 @@ void stm32mp1_ddr_init(struct ddr_info *priv, set_reg(priv, REGPHY_TIMING, &config->p_timing); set_reg(priv, REGPHY_CAL, &config->p_cal); + /* DDR3 = don't set DLLOFF for init mode */ + if ((config->c_reg.mstr & + (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) + == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { + debug("deactivate DLL OFF in mr1\n"); + clrbits_le32(&priv->phy->mr1, BIT(0)); + debug("[0x%08x] mr1 = 0x%08x\n", + (u32)&priv->phy->mr1, readl(&priv->phy->mr1)); + } + + if (INTERACTIVE(STEP_PHY_INIT)) + goto start; + /* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE * Perform DDR PHY DRAM initialization and Gate Training Evaluation */ @@ -445,6 +932,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv, * by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE * DRAM init is done by PHY, init0.skip_dram.init = 1 */ + pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL | DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC; @@ -456,7 +944,12 @@ void stm32mp1_ddr_init(struct ddr_info *priv, /* 6. SET DFIMISC.dfi_init_complete_en to 1 */ /* Enable quasi-dynamic register programming*/ start_sw_done(priv->ctl); + setbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + debug("[0x%08x] dfimisc = 0x%08x\n", + (u32)&priv->ctl->dfimisc, + readl(&priv->ctl->dfimisc)); + wait_sw_done_ack(priv->ctl); /* 7. Wait for DWC_ddr_umctl2 to move to normal operation mode @@ -466,6 +959,10 @@ void stm32mp1_ddr_init(struct ddr_info *priv, wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + /* switch to DLL OFF mode */ + if (config->c_reg.mstr & DDRCTRL_MSTR_DLL_OFF_MODE) + ddr3_dll_off(priv); + debug("DDR DQS training : "); /* 8. Disable Auto refresh and power down by setting * - RFSHCTL3.dis_au_refresh = 1 @@ -492,4 +989,7 @@ void stm32mp1_ddr_init(struct ddr_info *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); + + if (INTERACTIVE(STEP_DDR_READY)) + goto start; } diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h index 3cd0161299eb..90b4a4b95b80 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h @@ -26,6 +26,7 @@ struct stm32mp1_ddrphy; * @ctl: DDR controleur base address * @clk: DDR clock * @phy: DDR PHY base address + * @pwr: pwr base address * @rcc: rcc base address */ struct ddr_info { @@ -34,6 +35,7 @@ struct ddr_info { struct clk clk; struct stm32mp1_ddrctl *ctl; struct stm32mp1_ddrphy *phy; + void *pwr; u32 rcc; }; @@ -157,7 +159,7 @@ struct stm32mp1_ddrphy_cal { struct stm32mp1_ddr_info { const char *name; - u16 speed; /* in MHZ */ + u32 speed; /* in kHZ */ u32 size; /* memory size in byte = col * row * width */ }; @@ -172,7 +174,7 @@ struct stm32mp1_ddr_config { struct stm32mp1_ddrphy_cal p_cal; }; -int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u16 mem_speed); +int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed); void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir); void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl); void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, @@ -197,10 +199,6 @@ void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config, char *name, char *string); -void stm32mp1_dump_info( - const struct ddr_info *priv, - const struct stm32mp1_ddr_config *config); - bool stm32mp1_ddr_interactive( void *priv, enum stm32mp1_ddr_interact_step step, diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h index a606b2bcbe27..9d33186b3a25 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h @@ -234,6 +234,8 @@ struct stm32mp1_ddrphy { /* DDRCTRL REGISTERS */ #define DDRCTRL_MSTR_DDR3 BIT(0) +#define DDRCTRL_MSTR_LPDDR2 BIT(2) +#define DDRCTRL_MSTR_LPDDR3 BIT(3) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL (0 << 12) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF (1 << 12) @@ -330,6 +332,7 @@ struct stm32mp1_ddrphy { #define DDRPHYC_DXNGCR_DXEN BIT(0) +#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30) #define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) #define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14) #define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14 diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c new file mode 100644 index 000000000000..3840af54ec82 --- /dev/null +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include "stm32mp1_ddr.h" +#include "stm32mp1_tests.h" + +DECLARE_GLOBAL_DATA_PTR; + +enum ddr_command { + DDR_CMD_HELP, + DDR_CMD_INFO, + DDR_CMD_FREQ, + DDR_CMD_RESET, + DDR_CMD_PARAM, + DDR_CMD_PRINT, + DDR_CMD_EDIT, + DDR_CMD_STEP, + DDR_CMD_NEXT, + DDR_CMD_GO, + DDR_CMD_TEST, + DDR_CMD_TUNING, + DDR_CMD_UNKNOWN, +}; + +const char *step_str[] = { + [STEP_DDR_RESET] = "DDR_RESET", + [STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE", + [STEP_PHY_INIT] = "DDR PHY_INIT_DONE", + [STEP_DDR_READY] = "DDR_READY", + [STEP_RUN] = "RUN" +}; + +enum ddr_command stm32mp1_get_command(char *cmd, int argc) +{ + const char *cmd_string[DDR_CMD_UNKNOWN] = { + [DDR_CMD_HELP] = "help", + [DDR_CMD_INFO] = "info", + [DDR_CMD_FREQ] = "freq", + [DDR_CMD_RESET] = "reset", + [DDR_CMD_PARAM] = "param", + [DDR_CMD_PRINT] = "print", + [DDR_CMD_EDIT] = "edit", + [DDR_CMD_STEP] = "step", + [DDR_CMD_NEXT] = "next", + [DDR_CMD_GO] = "go", + [DDR_CMD_TEST] = "test", +#ifdef CONFIG_STM32MP1_DDR_TUNING + [DDR_CMD_TUNING] = "tuning", +#endif + }; + /* min and max number of argument */ + const char cmd_arg[DDR_CMD_UNKNOWN][2] = { + [DDR_CMD_HELP] = { 0, 0 }, + [DDR_CMD_INFO] = { 0, 255 }, + [DDR_CMD_FREQ] = { 0, 1 }, + [DDR_CMD_RESET] = { 0, 0 }, + [DDR_CMD_PARAM] = { 0, 2 }, + [DDR_CMD_PRINT] = { 0, 1 }, + [DDR_CMD_EDIT] = { 2, 2 }, + [DDR_CMD_STEP] = { 0, 1 }, + [DDR_CMD_NEXT] = { 0, 0 }, + [DDR_CMD_GO] = { 0, 0 }, + [DDR_CMD_TEST] = { 0, 255 }, +#ifdef CONFIG_STM32MP1_DDR_TUNING + [DDR_CMD_TUNING] = { 0, 255 }, +#endif + }; + int i; + + for (i = 0; i < DDR_CMD_UNKNOWN; i++) + if (!strcmp(cmd, cmd_string[i])) { + if (argc - 1 < cmd_arg[i][0]) { + printf("no enought argument (min=%d)\n", + cmd_arg[i][0]); + return DDR_CMD_UNKNOWN; + } else if (argc - 1 > cmd_arg[i][1]) { + printf("too many argument (max=%d)\n", + cmd_arg[i][1]); + return DDR_CMD_UNKNOWN; + } else { + return i; + } + } + + printf("unknown command %s\n", cmd); + return DDR_CMD_UNKNOWN; +} + +static void stm32mp1_do_usage(void) +{ + const char *usage = { + "commands:\n\n" + "help this message\n" + "info [ ] display/change DDR information\n" + "freq [freq] display/change the DDR frequency\n" + "param [type|reg] print input parameters\n" + "param edit parameters in step 0\n" + "print [type|reg] dump register\n" + "edit modify register\n" + " all registers if [type|reg] is absent\n" + " = ctl, phy\n" + " or one category (static, timing, map, perf, cal, dyn)\n" + " = name of the register\n" + "step [n] list the step / go to the step \n" + "next go to the next step\n" + "go continue SPL execution\n" + "reset reboot machine\n" + "test [help] | [...] list (with help) or execute test \n" +#ifdef CONFIG_STM32MP1_DDR_TUNING + "tuning [help] | [...] list (with help) or execute test \n" +#endif + }; + + puts(usage); +} + +static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step, + enum stm32mp1_ddr_interact_step expected) +{ + if (step != expected) { + printf("invalid step %d:%s expecting %d:%s\n", + step, step_str[step], + expected, + step_str[expected]); + return false; + } + return true; +} + +static void stm32mp1_do_info(struct ddr_info *priv, + struct stm32mp1_ddr_config *config, + enum stm32mp1_ddr_interact_step step, + int argc, char * const argv[]) +{ + unsigned long value; + static char *ddr_name; + + if (argc == 1) { + printf("step = %d : %s\n", step, step_str[step]); + printf("name = %s\n", config->info.name); + printf("size = 0x%x\n", config->info.size); + printf("speed = %d kHz\n", config->info.speed); + return; + } + + if (argc < 3) { + printf("no enought parameter\n"); + return; + } + if (!strcmp(argv[1], "name")) { + u32 i, name_len = 0; + + for (i = 2; i < argc; i++) + name_len += strlen(argv[i]) + 1; + if (ddr_name) + free(ddr_name); + ddr_name = malloc(name_len); + config->info.name = ddr_name; + if (!ddr_name) { + printf("alloc error, length %d\n", name_len); + return; + } + strcpy(ddr_name, argv[2]); + for (i = 3; i < argc; i++) { + strcat(ddr_name, " "); + strcat(ddr_name, argv[i]); + } + printf("name = %s\n", ddr_name); + return; + } + if (!strcmp(argv[1], "size")) { + if (strict_strtoul(argv[2], 16, &value) < 0) { + printf("invalid value %s\n", argv[2]); + } else { + config->info.size = value; + printf("size = 0x%x\n", config->info.size); + } + return; + } + if (!strcmp(argv[1], "speed")) { + if (strict_strtoul(argv[2], 10, &value) < 0) { + printf("invalid value %s\n", argv[2]); + } else { + config->info.speed = value; + printf("speed = %d kHz\n", config->info.speed); + value = clk_get_rate(&priv->clk); + printf("DDRPHY = %ld kHz\n", value / 1000); + } + return; + } + printf("argument %s invalid\n", argv[1]); +} + +static bool stm32mp1_do_freq(struct ddr_info *priv, + int argc, char * const argv[]) +{ + unsigned long ddrphy_clk; + + if (argc == 2) { + if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) { + printf("invalid argument %s", argv[1]); + return false; + } + if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) { + printf("ERROR: update failed!\n"); + return false; + } + } + ddrphy_clk = clk_get_rate(&priv->clk); + printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000); + if (argc == 2) + return true; + return false; +} + +static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step, + const struct stm32mp1_ddr_config *config, + int argc, char * const argv[]) +{ + switch (argc) { + case 1: + stm32mp1_dump_param(config, NULL); + break; + case 2: + if (stm32mp1_dump_param(config, argv[1])) + printf("invalid argument %s\n", + argv[1]); + break; + case 3: + if (!stm32mp1_check_step(step, STEP_DDR_RESET)) + return; + stm32mp1_edit_param(config, argv[1], argv[2]); + break; + } +} + +static void stm32mp1_do_print(struct ddr_info *priv, + int argc, char * const argv[]) +{ + switch (argc) { + case 1: + stm32mp1_dump_reg(priv, NULL); + break; + case 2: + if (stm32mp1_dump_reg(priv, argv[1])) + printf("invalid argument %s\n", + argv[1]); + break; + } +} + +static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step, + int argc, char * const argv[]) +{ + int i; + unsigned long value; + + switch (argc) { + case 1: + for (i = 0; i < ARRAY_SIZE(step_str); i++) + printf("%d:%s\n", i, step_str[i]); + break; + + case 2: + if ((strict_strtoul(argv[1], 0, + &value) < 0) || + value >= ARRAY_SIZE(step_str)) { + printf("invalid argument %s\n", + argv[1]); + goto end; + } + + if (value != STEP_DDR_RESET && + value <= step) { + printf("invalid target %d:%s, current step is %d:%s\n", + (int)value, step_str[value], + step, step_str[step]); + goto end; + } + printf("step to %d:%s\n", + (int)value, step_str[value]); + return (int)value; + }; + +end: + return step; +} + +static const char * const s_result[] = { + [TEST_PASSED] = "Pass", + [TEST_FAILED] = "Failed", + [TEST_ERROR] = "Error" +}; + +static void stm32mp1_ddr_subcmd(struct ddr_info *priv, + int argc, char *argv[], + const struct test_desc array[], + const int array_nb) +{ + int i; + unsigned long value; + int result; + char string[50] = ""; + + if (argc == 1) { + printf("%s:%d\n", argv[0], array_nb); + for (i = 0; i < array_nb; i++) + printf("%d:%s:%s\n", + i, array[i].name, array[i].usage); + return; + } + if (argc > 1 && !strcmp(argv[1], "help")) { + printf("%s:%d\n", argv[0], array_nb); + for (i = 0; i < array_nb; i++) + printf("%d:%s:%s:%s\n", i, + array[i].name, array[i].usage, array[i].help); + return; + } + + if ((strict_strtoul(argv[1], 0, &value) < 0) || + value >= array_nb) { + sprintf(string, "invalid argument %s", + argv[1]); + result = TEST_FAILED; + goto end; + } + + if (argc > (array[value].max_args + 2)) { + sprintf(string, "invalid nb of args %d, max %d", + argc - 2, array[value].max_args); + result = TEST_FAILED; + goto end; + } + + printf("execute %d:%s\n", (int)value, array[value].name); + clear_ctrlc(); + result = array[value].fct(priv->ctl, priv->phy, + string, argc - 2, &argv[2]); + +end: + printf("Result: %s [%s]\n", s_result[result], string); +} + +bool stm32mp1_ddr_interactive(void *priv, + enum stm32mp1_ddr_interact_step step, + const struct stm32mp1_ddr_config *config) +{ + const char *prompt = "DDR>"; + char buffer[CONFIG_SYS_CBSIZE]; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + int argc; + static int next_step = -1; + + if (next_step < 0 && step == STEP_DDR_RESET) { +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE + gd->flags &= ~(GD_FLG_SILENT | + GD_FLG_DISABLE_CONSOLE); + next_step = STEP_DDR_RESET; +#else + unsigned long start = get_timer(0); + + while (1) { + if (tstc() && (getc() == 'd')) { + next_step = STEP_DDR_RESET; + break; + } + if (get_timer(start) > 100) + break; + } +#endif + } + + debug("** step %d ** %s / %d\n", step, step_str[step], next_step); + + if (next_step < 0) + return false; + + if (step < 0 || step > ARRAY_SIZE(step_str)) { + printf("** step %d ** INVALID\n", step); + return false; + } + + printf("%d:%s\n", step, step_str[step]); + printf("%s\n", prompt); + + if (next_step > step) + return false; + + while (next_step == step) { + cli_readline_into_buffer(prompt, buffer, 0); + argc = cli_simple_parse_line(buffer, argv); + if (!argc) + continue; + + switch (stm32mp1_get_command(argv[0], argc)) { + case DDR_CMD_HELP: + stm32mp1_do_usage(); + break; + + case DDR_CMD_INFO: + stm32mp1_do_info(priv, + (struct stm32mp1_ddr_config *)config, + step, argc, argv); + break; + + case DDR_CMD_FREQ: + if (stm32mp1_do_freq(priv, argc, argv)) + next_step = STEP_DDR_RESET; + break; + + case DDR_CMD_RESET: + do_reset(NULL, 0, 0, NULL); + break; + + case DDR_CMD_PARAM: + stm32mp1_do_param(step, config, argc, argv); + break; + + case DDR_CMD_PRINT: + stm32mp1_do_print(priv, argc, argv); + break; + + case DDR_CMD_EDIT: + stm32mp1_edit_reg(priv, argv[1], argv[2]); + break; + + case DDR_CMD_GO: + next_step = STEP_RUN; + break; + + case DDR_CMD_NEXT: + next_step = step + 1; + break; + + case DDR_CMD_STEP: + next_step = stm32mp1_do_step(step, argc, argv); + break; + + case DDR_CMD_TEST: + if (!stm32mp1_check_step(step, STEP_DDR_READY)) + continue; + stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb); + break; + +#ifdef CONFIG_STM32MP1_DDR_TUNING + case DDR_CMD_TUNING: + if (!stm32mp1_check_step(step, STEP_DDR_READY)) + continue; + stm32mp1_ddr_subcmd(priv, argc, argv, + tuning, tuning_nb); + break; +#endif + default: + break; + } + } + return next_step == STEP_DDR_RESET; +} diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index bd497a3021d8..6245cb419eed 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -12,6 +12,8 @@ #include #include "stm32mp1_ddr.h" +DECLARE_GLOBAL_DATA_PTR; + static const char *const clkname[] = { "ddrc1", "ddrc2", @@ -20,7 +22,7 @@ static const char *const clkname[] = { "ddrphyc" /* LAST clock => used for get_rate() */ }; -int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed) +int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) { unsigned long ddrphy_clk; unsigned long ddr_clk; @@ -43,16 +45,15 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed) priv->clk = clk; ddrphy_clk = clk_get_rate(&priv->clk); - debug("DDR: mem_speed (%d MHz), RCC %d MHz\n", - mem_speed, (u32)(ddrphy_clk / 1000 / 1000)); + debug("DDR: mem_speed (%d kHz), RCC %d kHz\n", + mem_speed, (u32)(ddrphy_clk / 1000)); /* max 10% frequency delta */ - ddr_clk = abs(ddrphy_clk - mem_speed * 1000 * 1000); - if (ddr_clk > (mem_speed * 1000 * 100)) { - pr_err("DDR expected freq %d MHz, current is %d MHz\n", - mem_speed, (u32)(ddrphy_clk / 1000 / 1000)); - return -EINVAL; + ddr_clk = abs(ddrphy_clk - mem_speed * 1000); + if (ddr_clk > (mem_speed * 100)) { + pr_err("DDR expected freq %d kHz, current is %d kHz\n", + mem_speed, (u32)(ddrphy_clk / 1000)); + return -1; } - return 0; } @@ -108,6 +109,7 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) } } + ret = clk_get_by_name(dev, "axidcg", &axidcg); if (ret) { debug("%s: Cannot found axidcg\n", __func__); @@ -141,7 +143,7 @@ static int stm32mp1_ddr_probe(struct udevice *dev) { struct ddr_info *priv = dev_get_priv(dev); struct regmap *map; - int ret; + int ret = 0; debug("STM32MP1 DDR probe\n"); priv->dev = dev; @@ -153,11 +155,17 @@ static int stm32mp1_ddr_probe(struct udevice *dev) priv->ctl = regmap_get_range(map, 0); priv->phy = regmap_get_range(map, 1); + map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR); + if (IS_ERR(map)) + return PTR_ERR(map); + priv->pwr = regmap_get_range(map, 0); + priv->rcc = STM32_RCC_BASE; 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/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c new file mode 100644 index 000000000000..5f2af4ede78b --- /dev/null +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -0,0 +1,1360 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ +#include +#include +#include +#include +#include "stm32mp1_tests.h" + +#define ADDR_INVALID 0xFFFFFFFF + +DECLARE_GLOBAL_DATA_PTR; + +static int get_bufsize(char *string, int argc, char *argv[], int arg_nb, + size_t *bufsize, size_t default_size) +{ + unsigned long value; + + if (argc > arg_nb) { + if (strict_strtoul(argv[arg_nb], 0, &value) < 0) { + sprintf(string, "invalid %d parameter %s", + arg_nb, argv[arg_nb]); + return -1; + } + if (value > STM32_DDR_SIZE || value == 0) { + sprintf(string, "invalid size %s", argv[arg_nb]); + return -1; + } + if (value & 0x3) { + sprintf(string, "unaligned size %s", + argv[arg_nb]); + return -1; + } + *bufsize = value; + } else { + if (default_size != STM32_DDR_SIZE) + *bufsize = default_size; + else + *bufsize = get_ram_size((long *)STM32_DDR_BASE, + STM32_DDR_SIZE); + } + return 0; +} + +static int get_nb_loop(char *string, int argc, char *argv[], int arg_nb, + u32 *nb_loop, u32 default_nb_loop) +{ + unsigned long value; + + if (argc > arg_nb) { + if (strict_strtoul(argv[arg_nb], 0, &value) < 0) { + sprintf(string, "invalid %d parameter %s", + arg_nb, argv[arg_nb]); + return -1; + } + if (value == 0) + printf("WARNING: infinite loop requested\n"); + *nb_loop = value; + } else { + *nb_loop = default_nb_loop; + } + + return 0; +} + +static int get_addr(char *string, int argc, char *argv[], int arg_nb, + u32 *addr) +{ + unsigned long value; + + if (argc > arg_nb) { + if (strict_strtoul(argv[arg_nb], 16, &value) < 0) { + sprintf(string, "invalid %d parameter %s", + arg_nb, argv[arg_nb]); + return -1; + } + if (value < STM32_DDR_BASE) { + sprintf(string, "too low address %s", argv[arg_nb]); + return -1; + } + if (value & 0x3 && value != ADDR_INVALID) { + sprintf(string, "unaligned address %s", + argv[arg_nb]); + return -1; + } + *addr = value; + } else { + *addr = STM32_DDR_BASE; + } + + return 0; +} + +static int get_pattern(char *string, int argc, char *argv[], int arg_nb, + u32 *pattern, u32 default_pattern) +{ + unsigned long value; + + if (argc > arg_nb) { + if (strict_strtoul(argv[arg_nb], 16, &value) < 0) { + sprintf(string, "invalid %d parameter %s", + arg_nb, argv[arg_nb]); + return -1; + } + *pattern = value; + } else { + *pattern = default_pattern; + } + + return 0; +} + +static u32 check_addr(u32 addr, u32 value) +{ + u32 data = readl(addr); + + if (value != data) { + printf("0x%08x: 0x%08x <=> 0x%08x", addr, data, value); + data = readl(addr); + printf("(2nd read: 0x%08x)", data); + if (value == data) + printf("- read error"); + else + printf("- write error"); + printf("\n"); + return -1; + } + return 0; +} + +static int progress(u32 offset) +{ + if (!(offset & 0xFFFFFF)) { + putc('.'); + if (ctrlc()) { + printf("\ntest interrupted!\n"); + return 1; + } + } + return 0; +} + +static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress) +{ + (*loop)++; + if (nb_loop && *loop >= nb_loop) + return 1; + if ((*loop) % progress) + return 0; + /* allow to interrupt the test only for progress step */ + if (ctrlc()) { + printf("test interrupted!\n"); + return 1; + } + printf("loop #%d\n", *loop); + return 0; +} + +/********************************************************************** + * + * Function: memTestDataBus() + * + * Description: Test the data bus wiring in a memory region by + * performing a walking 1's test at a fixed address + * within that region. The address is selected + * by the caller. + * + * Notes: + * + * Returns: 0 if the test succeeds. + * A non-zero result is the first pattern that failed. + * + **********************************************************************/ +static u32 databus(u32 *address) +{ + u32 pattern; + u32 read_value; + + /* Perform a walking 1's test at the given address. */ + for (pattern = 1; pattern != 0; pattern <<= 1) { + /* Write the test pattern. */ + writel(pattern, address); + + /* Read it back (immediately is okay for this test). */ + read_value = readl(address); + debug("%x: %x <=> %x\n", + (u32)address, read_value, pattern); + + if (read_value != pattern) + return pattern; + } + + return 0; +} + +/********************************************************************** + * + * Function: memTestAddressBus() + * + * Description: Test the address bus wiring in a memory region by + * performing a walking 1's test on the relevant bits + * of the address and checking for aliasing. This test + * will find single-bit address failures such as stuck + * -high, stuck-low, and shorted pins. The base address + * and size of the region are selected by the caller. + * + * Notes: For best results, the selected base address should + * have enough LSB 0's to guarantee single address bit + * changes. For example, to test a 64-Kbyte region, + * select a base address on a 64-Kbyte boundary. Also, + * select the region size as a power-of-two--if at all + * possible. + * + * Returns: NULL if the test succeeds. + * A non-zero result is the first address at which an + * aliasing problem was uncovered. By examining the + * contents of memory, it may be possible to gather + * additional information about the problem. + * + **********************************************************************/ +static u32 *addressbus(u32 *address, u32 nb_bytes) +{ + u32 mask = (nb_bytes / sizeof(u32) - 1); + u32 offset; + u32 test_offset; + u32 read_value; + + u32 pattern = 0xAAAAAAAA; + u32 antipattern = 0x55555555; + + /* Write the default pattern at each of the power-of-two offsets. */ + for (offset = 1; (offset & mask) != 0; offset <<= 1) + writel(pattern, &address[offset]); + + /* Check for address bits stuck high. */ + test_offset = 0; + writel(antipattern, &address[test_offset]); + + for (offset = 1; (offset & mask) != 0; offset <<= 1) { + read_value = readl(&address[offset]); + debug("%x: %x <=> %x\n", + (u32)&address[offset], read_value, pattern); + if (read_value != pattern) + return &address[offset]; + } + + writel(pattern, &address[test_offset]); + + /* Check for address bits stuck low or shorted. */ + for (test_offset = 1; (test_offset & mask) != 0; test_offset <<= 1) { + writel(antipattern, &address[test_offset]); + if (readl(&address[0]) != pattern) + return &address[test_offset]; + + for (offset = 1; (offset & mask) != 0; offset <<= 1) { + if (readl(&address[offset]) != pattern && + offset != test_offset) + return &address[test_offset]; + } + writel(pattern, &address[test_offset]); + } + + return NULL; +} + +/********************************************************************** + * + * Function: memTestDevice() + * + * Description: Test the integrity of a physical memory device by + * performing an increment/decrement test over the + * entire region. In the process every storage bit + * in the device is tested as a zero and a one. The + * base address and the size of the region are + * selected by the caller. + * + * Notes: + * + * Returns: NULL if the test succeeds. + * + * A non-zero result is the first address at which an + * incorrect value was read back. By examining the + * contents of memory, it may be possible to gather + * additional information about the problem. + * + **********************************************************************/ +static u32 *memdevice(u32 *address, u32 nb_bytes) +{ + u32 offset; + u32 nb_words = nb_bytes / sizeof(u32); + + u32 pattern; + u32 antipattern; + + puts("Fill with pattern"); + /* Fill memory with a known pattern. */ + for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) { + writel(pattern, &address[offset]); + if (progress(offset)) + return NULL; + } + + puts("\nCheck and invert pattern"); + /* Check each location and invert it for the second pass. */ + for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) { + if (readl(&address[offset]) != pattern) + return &address[offset]; + + antipattern = ~pattern; + writel(antipattern, &address[offset]); + if (progress(offset)) + return NULL; + } + + puts("\nCheck inverted pattern"); + /* Check each location for the inverted pattern and zero it. */ + for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) { + antipattern = ~pattern; + if (readl(&address[offset]) != antipattern) + return &address[offset]; + if (progress(offset)) + return NULL; + } + printf("\n"); + + return NULL; +} + +static enum test_result databuswalk0(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + int i; + u32 loop = 0, nb_loop; + u32 addr; + u32 error = 0; + u32 data; + + if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + + printf("running %d loops at 0x%x\n", nb_loop, addr); + while (!error) { + for (i = 0; i < 32; i++) + writel(~(1 << i), addr + 4 * i); + for (i = 0; i < 32; i++) { + data = readl(addr + 4 * i); + if (~(1 << i) != data) { + error |= 1 << i; + debug("%x: error %x expected %x => error:%x\n", + addr + 4 * i, data, ~(1 << i), error); + } + } + if (test_loop_end(&loop, nb_loop, 1000)) + break; + for (i = 0; i < 32; i++) + writel(0, addr + 4 * i); + } + if (error) { + sprintf(string, "loop %d: error for bits 0x%x", + loop, error); + return TEST_FAILED; + } + sprintf(string, "no error for %d loops", loop); + return TEST_PASSED; +} + +static enum test_result databuswalk1(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + int i; + u32 loop = 0, nb_loop; + u32 addr; + u32 error = 0; + u32 data; + + if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + printf("running %d loops at 0x%x\n", nb_loop, addr); + while (!error) { + for (i = 0; i < 32; i++) + writel(1 << i, addr + 4 * i); + for (i = 0; i < 32; i++) { + data = readl(addr + 4 * i); + if ((1 << i) != data) { + error |= 1 << i; + debug("%x: error %x expected %x => error:%x\n", + addr + 4 * i, data, (1 << i), error); + } + } + if (test_loop_end(&loop, nb_loop, 1000)) + break; + for (i = 0; i < 32; i++) + writel(0, addr + 4 * i); + } + if (error) { + sprintf(string, "loop %d: error for bits 0x%x", + loop, error); + return TEST_FAILED; + } + sprintf(string, "no error for %d loops", loop); + return TEST_PASSED; +} + +static enum test_result test_databus(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr; + u32 error; + + if (get_addr(string, argc, argv, 0, &addr)) + return TEST_ERROR; + error = databus((u32 *)addr); + if (error) { + sprintf(string, "0x%x: error for bits 0x%x", + addr, error); + return TEST_FAILED; + } + sprintf(string, "address 0x%x", addr); + return TEST_PASSED; +} + +static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr; + u32 bufsize; + u32 error; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + if (!is_power_of_2(bufsize)) { + sprintf(string, "size 0x%x is not a power of 2", + (u32)bufsize); + return TEST_ERROR; + } + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + + error = (u32)addressbus((u32 *)addr, bufsize); + if (error) { + sprintf(string, "0x%x: error for address 0x%x", + addr, error); + return TEST_FAILED; + } + sprintf(string, "address 0x%x, size 0x%x", + addr, bufsize); + return TEST_PASSED; +} + +static enum test_result test_memdevice(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr; + size_t bufsize; + u32 error; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + error = (u32)memdevice((u32 *)addr, (unsigned long)bufsize); + if (error) { + sprintf(string, "0x%x: error for address 0x%x", + addr, error); + return TEST_FAILED; + } + sprintf(string, "address 0x%x, size 0x%x", + addr, bufsize); + return TEST_PASSED; +} + +/********************************************************************** + * + * Function: sso + * + * Description: Test the Simultaneous Switching Output. + * Verifies succes sive reads and writes to the same memory word, + * holding one bit constant while toggling all other data bits + * simultaneously + * => stress the data bus over an address range + * + * The CPU writes to each address in the given range. + * For each bit, first the CPU holds the bit at 1 while + * toggling the other bits, and then the CPU holds the bit at 0 + * while toggling the other bits. + * After each write, the CPU reads the address that was written + * to verify that it contains the correct data + * + **********************************************************************/ +static enum test_result test_sso(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + int i, j; + u32 addr, bufsize, remaining, offset; + u32 error = 0; + u32 data; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + + printf("running sso at 0x%x length 0x%x", addr, bufsize); + offset = addr; + remaining = bufsize; + while (remaining) { + for (i = 0; i < 32; i++) { + /* write pattern. */ + for (j = 0; j < 6; j++) { + switch (j) { + case 0: + case 2: + data = 1 << i; + break; + case 3: + case 5: + data = ~(1 << i); + break; + case 1: + data = ~0x0; + break; + case 4: + data = 0x0; + break; + } + + writel(data, offset); + error = check_addr(offset, data); + if (error) + goto end; + } + } + offset += 4; + remaining -= 4; + if (progress(offset << 7)) + goto end; + } + puts("\n"); + +end: + if (error) { + sprintf(string, "error for pattern 0x%x @0x%x", + data, offset); + return TEST_FAILED; + } + sprintf(string, "no error for sso at 0x%x length 0x%x", addr, bufsize); + return TEST_PASSED; +} + +/********************************************************************** + * + * Function: Random + * + * Description: Verifies r/w with pseudo-ramdom value on one region + * + write the region (individual access) + * + memcopy to the 2nd region (try to use burst) + * + verify the 2 regions + * + **********************************************************************/ +static enum test_result test_random(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr, offset, value = 0; + size_t bufsize; + u32 loop = 0, nb_loop; + u32 error = 0; + unsigned int seed; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; + + printf("running %d loops at 0x%x\n", nb_loop, addr); + while (!error) { + seed = rand(); + for (offset = addr; offset < addr + bufsize; offset += 4) + writel(rand(), offset); + + memcpy((void *)addr + bufsize, (void *)addr, bufsize); + + srand(seed); + for (offset = addr; offset < addr + 2 * bufsize; offset += 4) { + if (offset == (addr + bufsize)) + srand(seed); + value = rand(); + error = check_addr(offset, value); + if (error) + break; + if (progress(offset)) + return TEST_FAILED; + } + if (test_loop_end(&loop, nb_loop, 100)) + break; + } + + if (error) { + sprintf(string, + "loop %d: error for address 0x%x: 0x%x expected 0x%x", + loop, offset, readl(offset), value); + return TEST_FAILED; + } + sprintf(string, "no error for %d loops, size 0x%x", + loop, bufsize); + return TEST_PASSED; +} + +/********************************************************************** + * + * Function: noise + * + * Description: Verifies r/w while forcing switching of all data bus lines. + * optimised 4 iteration write/read/write/read cycles... + * for pattern and inversed pattern + * + **********************************************************************/ +void do_noise(u32 addr, u32 pattern, u32 *result) +{ + __asm__("push {R0-R11}"); + __asm__("mov r0, %0" : : "r" (addr)); + __asm__("mov r1, %0" : : "r" (pattern)); + __asm__("mov r11, %0" : : "r" (result)); + + __asm__("mvn r2, r1"); + + __asm__("str r1, [r0]"); + __asm__("ldr r3, [r0]"); + __asm__("str r2, [r0]"); + __asm__("ldr r4, [r0]"); + + __asm__("str r1, [r0]"); + __asm__("ldr r5, [r0]"); + __asm__("str r2, [r0]"); + __asm__("ldr r6, [r0]"); + + __asm__("str r1, [r0]"); + __asm__("ldr r7, [r0]"); + __asm__("str r2, [r0]"); + __asm__("ldr r8, [r0]"); + + __asm__("str r1, [r0]"); + __asm__("ldr r9, [r0]"); + __asm__("str r2, [r0]"); + __asm__("ldr r10, [r0]"); + + __asm__("stmia R11!, {R3-R10}"); + + __asm__("pop {R0-R11}"); +} + +static enum test_result test_noise(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr, pattern; + u32 result[8]; + int i; + enum test_result res = TEST_PASSED; + + if (get_pattern(string, argc, argv, 0, &pattern, 0xFFFFFFFF)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 1, &addr)) + return TEST_ERROR; + + printf("running noise for 0x%x at 0x%x\n", pattern, addr); + + do_noise(addr, pattern, result); + + for (i = 0; i < 0x8;) { + if (check_addr((u32)&result[i++], pattern)) + res = TEST_FAILED; + if (check_addr((u32)&result[i++], ~pattern)) + res = TEST_FAILED; + } + + return res; +} + +/********************************************************************** + * + * Function: noise_burst + * + * Description: Verifies r/w while forcing switching of all data bus lines. + * optimised write loop witrh store multiple to use burst + * for pattern and inversed pattern + * + **********************************************************************/ +void do_noise_burst(u32 addr, u32 pattern, size_t bufsize) +{ + __asm__("push {R0-R9}"); + __asm__("mov r0, %0" : : "r" (addr)); + __asm__("mov r1, %0" : : "r" (pattern)); + __asm__("mov r9, %0" : : "r" (bufsize)); + + __asm__("mvn r2, r1"); + __asm__("mov r3, r1"); + __asm__("mov r4, r2"); + __asm__("mov r5, r1"); + __asm__("mov r6, r2"); + __asm__("mov r7, r1"); + __asm__("mov r8, r2"); + + __asm__("loop1:"); + __asm__("stmia R0!, {R1-R8}"); + __asm__("stmia R0!, {R1-R8}"); + __asm__("stmia R0!, {R1-R8}"); + __asm__("stmia R0!, {R1-R8}"); + __asm__("subs r9, r9, #128"); + __asm__("bge loop1"); + __asm__("pop {R0-R9}"); +} + +/* chunk size enough to allow interruption with Ctrl-C*/ +#define CHUNK_SIZE 0x8000000 +static enum test_result test_noise_burst(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 addr, offset, pattern; + size_t bufsize, remaining, size; + int i; + enum test_result res = TEST_PASSED; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &pattern, 0xFFFFFFFF)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; + + printf("running noise burst for 0x%x at 0x%x + 0x%x", + pattern, addr, bufsize); + + offset = addr; + remaining = bufsize; + size = CHUNK_SIZE; + while (remaining) { + if (remaining < size) + size = remaining; + do_noise_burst(offset, pattern, size); + remaining -= size; + offset += size; + if (progress(offset)) { + res = TEST_FAILED; + goto end; + } + } + puts("\ncheck buffer"); + for (i = 0; i < bufsize;) { + if (check_addr(addr + i, pattern)) + res = TEST_FAILED; + i += 4; + if (check_addr(addr + i, ~pattern)) + res = TEST_FAILED; + i += 4; + if (progress(i)) { + res = TEST_FAILED; + goto end; + } + } +end: + puts("\n"); + return res; +} + +/********************************************************************** + * + * Function: pattern test + * + * Description: optimized loop for read/write pattern (array of 8 u32) + * + **********************************************************************/ +#define PATTERN_SIZE 8 +static enum test_result test_loop(const u32 *pattern, u32 *address, + const u32 bufsize) +{ + int i; + int j; + enum test_result res = TEST_PASSED; + u32 *offset, testsize, remaining; + + offset = address; + remaining = bufsize; + while (remaining) { + testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize; + + __asm__("push {R0-R10}"); + __asm__("mov r0, %0" : : "r" (pattern)); + __asm__("mov r1, %0" : : "r" (offset)); + __asm__("mov r2, %0" : : "r" (testsize)); + __asm__("ldmia r0!, {R3-R10}"); + + __asm__("loop2:"); + __asm__("stmia r1!, {R3-R10}"); + __asm__("stmia r1!, {R3-R10}"); + __asm__("stmia r1!, {R3-R10}"); + __asm__("stmia r1!, {R3-R10}"); + __asm__("subs r2, r2, #8"); + __asm__("bge loop2"); + __asm__("pop {R0-R10}"); + + offset += testsize; + remaining -= testsize; + if (progress((u32)offset)) { + res = TEST_FAILED; + goto end; + } + } + + puts("\ncheck buffer"); + for (i = 0; i < bufsize; i += PATTERN_SIZE * 4) { + for (j = 0; j < PATTERN_SIZE; j++, address++) + if (check_addr((u32)address, pattern[j])) { + res = TEST_FAILED; + goto end; + } + if (progress(i)) { + res = TEST_FAILED; + goto end; + } + } + +end: + puts("\n"); + return res; +} + +const u32 pattern_div1_x16[PATTERN_SIZE] = { + 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, + 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF +}; + +const u32 pattern_div2_x16[PATTERN_SIZE] = { + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 +}; + +const u32 pattern_div4_x16[PATTERN_SIZE] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 +}; + +const u32 pattern_div4_x32[PATTERN_SIZE] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +const u32 pattern_mostly_zero_x16[PATTERN_SIZE] = { + 0x00000000, 0x00000000, 0x00000000, 0x0000FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +const u32 pattern_mostly_zero_x32[PATTERN_SIZE] = { + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +const u32 pattern_mostly_one_x16[PATTERN_SIZE] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +const u32 pattern_mostly_one_x32[PATTERN_SIZE] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +#define NB_PATTERN 5 +static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + const u32 * const patterns_x16[NB_PATTERN] = { + pattern_div1_x16, + pattern_div2_x16, + pattern_div4_x16, + pattern_mostly_zero_x16, + pattern_mostly_one_x16, + }; + const u32 * const patterns_x32[NB_PATTERN] = { + pattern_div2_x16, + pattern_div4_x16, + pattern_div4_x32, + pattern_mostly_zero_x32, + pattern_mostly_one_x32 + }; + const char *patterns_comments[NB_PATTERN] = { + "switching at frequency F/1", + "switching at frequency F/2", + "switching at frequency F/4", + "mostly zero", + "mostly one" + }; + + enum test_result res = TEST_PASSED, pattern_res; + int i, bus_width; + const u32 **patterns; + u32 bufsize; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { + case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: + case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER: + bus_width = 16; + break; + default: + bus_width = 32; + break; + } + + printf("running test pattern at 0x%08x length 0x%x width = %d\n", + STM32_DDR_BASE, bufsize, bus_width); + + patterns = + (const u32 **)(bus_width == 16 ? patterns_x16 : patterns_x32); + + for (i = 0; i < NB_PATTERN; i++) { + printf("test data pattern %s:", patterns_comments[i]); + pattern_res = test_loop(patterns[i], (u32 *)STM32_DDR_BASE, + bufsize); + if (pattern_res != TEST_PASSED) { + printf("Failed\n"); + return pattern_res; + } + printf("Passed\n"); + } + + return res; +} + +/********************************************************************** + * + * Function: pattern test with size + * + * Description: loop for write pattern + * + **********************************************************************/ + +static enum test_result test_loop_size(const u32 *pattern, u32 size, + u32 *address, + const u32 bufsize) +{ + int i, j; + enum test_result res = TEST_PASSED; + u32 *p = address; + + for (i = 0; i < bufsize; i += size * 4) { + for (j = 0; j < size ; j++, p++) + *p = pattern[j]; + if (progress(i)) { + res = TEST_FAILED; + goto end; + } + } + + puts("\ncheck buffer"); + p = address; + for (i = 0; i < bufsize; i += size * 4) { + for (j = 0; j < size; j++, p++) + if (check_addr((u32)p, pattern[j])) { + res = TEST_FAILED; + goto end; + } + if (progress(i)) { + res = TEST_FAILED; + goto end; + } + } + +end: + puts("\n"); + return res; +} + +static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + + u32 checkboard[2] = {0x55555555, 0xAAAAAAAA}; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running test checkboard at 0x%08x length 0x%x\n", + STM32_DDR_BASE, bufsize); + + res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, + bufsize); + + checkboard[0] = ~checkboard[0]; + checkboard[1] = ~checkboard[1]; + + res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, + bufsize); + + return res; +} + +static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + int i; + + u32 value; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); + for (i = 0; i < 256; i++) { + value = i | i << 8 | i << 16 | i << 24; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, + bufsize); + if (res != TEST_PASSED) + return res; + } + + return res; +} + +static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + int i; + + u32 value; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); + for (i = 0; i < 64; i++) { + if (i < 32) + value = 1 << i; + else + value = 1 << (63 - i); + + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, + bufsize); + if (res != TEST_PASSED) + return res; + } + + return res; +} + +static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + int i; + + u32 value; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); + for (i = 0; i < 64; i++) { + if (i < 32) + value = ~(1 << i); + else + value = ~(1 << (63 - i)); + + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, + bufsize); + if (res != TEST_PASSED) + return res; + } + + return res; +} + +/* + * try to catch bad bits which are dependent on the current values of + * surrounding bits in either the same word32 + */ +static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + int i, j; + + u32 bitspread[4]; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); + for (i = 1; i < 32; i++) { + for (j = 0; j < i; j++) { + if (i < 32) + bitspread[0] = (1 << i) | (1 << j); + else + bitspread[0] = (1 << (63 - i)) | + (1 << (63 - j)); + bitspread[1] = bitspread[0]; + bitspread[2] = ~bitspread[0]; + bitspread[3] = ~bitspread[0]; + printf("pattern = %08x", bitspread[0]); + + res = test_loop_size(bitspread, 4, + (u32 *)STM32_DDR_BASE, + bufsize); + if (res != TEST_PASSED) + return res; + } + } + + return res; +} + +static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED; + u32 bufsize; + int i; + + u32 bitflip[4]; + + if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + return TEST_ERROR; + + printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); + for (i = 0; i < 32; i++) { + bitflip[0] = 1 << i; + bitflip[1] = bitflip[0]; + bitflip[2] = ~bitflip[0]; + bitflip[3] = bitflip[2]; + printf("pattern = %08x", bitflip[0]); + + res = test_loop_size(bitflip, 4, (u32 *)STM32_DDR_BASE, + bufsize); + if (res != TEST_PASSED) + return res; + } + + return res; +} + +/********************************************************************** + * + * Function: infinite read access to DDR + * + * Description: continuous read the same pattern at the same address + * + **********************************************************************/ +static enum test_result test_read(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 *addr; + u32 data; + u32 loop = 0; + bool random = false; + + if (get_addr(string, argc, argv, 0, (u32 *)&addr)) + return TEST_ERROR; + + if ((u32)addr == ADDR_INVALID) { + printf("random "); + random = true; + } + + printf("running at 0x%08x\n", (u32)addr); + + while (1) { + if (random) + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = readl(addr); + if (test_loop_end(&loop, 0, 1000)) + break; + } + sprintf(string, "0x%x: %x", (u32)addr, data); + + return TEST_PASSED; +} + +/********************************************************************** + * + * Function: infinite write access to DDR + * + * Description: continuous write the same pattern at the same address + * + **********************************************************************/ +static enum test_result test_write(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 *addr; + u32 data = 0xA5A5AA55; + u32 loop = 0; + bool random = false; + + if (get_addr(string, argc, argv, 0, (u32 *)&addr)) + return TEST_ERROR; + + if ((u32)addr == ADDR_INVALID) { + printf("random "); + random = true; + } + + printf("running at 0x%08x\n", (u32)addr); + + while (1) { + if (random) { + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = rand(); + } + writel(data, addr); + if (test_loop_end(&loop, 0, 1000)) + break; + } + sprintf(string, "0x%x: %x", (u32)addr, data); + + return TEST_PASSED; +} + +#define NB_TEST_INFINITE 2 +static enum test_result test_all(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + enum test_result res = TEST_PASSED, result; + int i, nb_error = 0; + + /* execute all the test except the lasts which are infinite */ + for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { + printf("execute %d:%s\n", (int)i, test[i].name); + result = test[i].fct(ctl, phy, string, 0, NULL); + printf("result %d:%s = ", (int)i, test[i].name); + if (result != TEST_PASSED) { + nb_error++; + res = TEST_FAILED; + puts("Failed"); + } else { + puts("Passed"); + } + puts("\n\n"); + } + sprintf(string, "%d/%d test failed", nb_error, + test_nb - NB_TEST_INFINITE); + + return res; +} + +/**************************************************************** + * TEST Description + ****************************************************************/ + +const struct test_desc test[] = { + {test_all, "All", "", "Execute all tests", 0 }, + {test_databus, "Simple DataBus", "[addr]", + "Verifies each data line by walking 1 on fixed address", + 1 + }, + {databuswalk0, "DataBusWalking0", "[loop] [addr]", + "Verifies each data bus signal can be driven low (32 word burst)", + 2 + }, + {databuswalk1, "DataBusWalking1", "[loop] [addr]", + "Verifies each data bus signal can be driven high (32 word burst)", + 2 + }, + {test_addressbus, "AddressBus", "[size] [addr]", + "Verifies each relevant bits of the address and checking for aliasing", + 2 + }, + {test_memdevice, "MemDevice", "[size] [addr]", + "Test the integrity of a physical memory (test every storage bit in the region)", + 2 + }, + {test_sso, "SimultaneousSwitchingOutput", "[size] [addr] ", + "Stress the data bus over an address range", + 2 + }, + {test_noise, "Noise", "[pattern] [addr]", + "Verifies r/w while forcing switching of all data bus lines.", + 3 + }, + {test_noise_burst, "NoiseBurst", "[size] [pattern] [addr]", + "burst transfers while forcing switching of the data bus lines", + 3 + }, + {test_random, "Random", "[size] [loop] [addr]", + "Verifies r/w and memcopy(burst for pseudo random value.", + 3 + }, + {test_freq_pattern, "FrequencySelectivePattern ", "[size]", + "write & test patterns: Mostly Zero, Mostly One and F/n", + 1 + }, + {test_blockseq, "BlockSequential", "[size]", + "test incremental pattern", + 1 + }, + {test_checkboard, "Checkerboard", "[size]", + "test checker pattern", + 1 + }, + {test_bitspread, "BitSpread", "[size]", + "test Bit Spread pattern", + 1 + }, + {test_bitflip, "BitFlip", "[size]", + "test Bit Flip pattern", + 1 + }, + {test_walkbit0, "WalkingOnes", "[size]", + "test Walking Ones pattern", + 1 + }, + {test_walkbit1, "WalkingZeroes", "[size]", + "test Walking Zeroes pattern", + 1 + }, + /* need to the the 2 last one (infinite) : skipped for test all */ + {test_read, "infinite read", "[addr]", + "basic test : infinite read access", 1}, + {test_write, "infinite write", "[addr]", + "basic test : infinite write access", 1}, +}; + +const int test_nb = ARRAY_SIZE(test); diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.h b/drivers/ram/stm32mp1/stm32mp1_tests.h new file mode 100644 index 000000000000..a69fc0a0ace6 --- /dev/null +++ b/drivers/ram/stm32mp1/stm32mp1_tests.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef _RAM_STM32MP1_TESTS_H_ +#define _RAM_STM32MP1_TESTS_H_ + +#include "stm32mp1_ddr_regs.h" + +enum test_result { + TEST_PASSED, + TEST_FAILED, + TEST_ERROR +}; + +struct test_desc { + enum test_result (*fct)(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, + int argc, char *argv[]); + const char *name; + const char *usage; + const char *help; + u8 max_args; +}; + +extern const struct test_desc test[]; +extern const int test_nb; + +extern const struct test_desc tuning[]; +extern const int tuning_nb; + +#endif diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c new file mode 100644 index 000000000000..0778921879b6 --- /dev/null +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -0,0 +1,1504 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#if defined(DEBUG) +#define DEBUG_BIST +#endif + +#include +#include +#include +#include +#include +#include + +#include "stm32mp1_ddr_regs.h" +#include "stm32mp1_ddr.h" +#include "stm32mp1_tests.h" +#include "stm32mp1_tuning.h" + +/* TODO make enum for nominal_delay_m_1.... (for all arrays) */ + +/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */ +const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12}; + +/* New DQ delay value (index). These values are set during Deskew algo */ +u8 deskew_delay[NUM_BYTES][8]; + +/*If there is still skew on a bit, mark this bit. */ +u8 deskew_non_converge[NUM_BYTES][8]; + +/*Stores the DQS trim values (PHASE index, unit index) */ +u8 eye_training_val[NUM_BYTES][2]; + +/* stores the log of pass/fail */ +u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1]; + +/* stores the dqs gate values (gsl index, gps index) */ +u8 dqs_gate_values[NUM_BYTES][2]; + +static void itm_soft_reset(struct stm32mp1_ddrphy *phy); +static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte); + +static u8 BIST_error_max = 1; +static u32 BIST_seed = 0x1234ABCD; + +static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl) +{ + u32 data_bus = readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK; + u8 nb_bytes = NUM_BYTES; + + switch (data_bus) { + case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: + nb_bytes /= 2; + break; + case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER: + nb_bytes /= 4; + break; + default: + break; + } + + return nb_bytes; +} + +/* Read DQS PHASE delay register and provides the index of the retrieved + * value in dx_dll_phase array. + */ +u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u32 addr = DXNDLLCR(phy, byte); + u32 sdphase = 0; + u8 index = 0; + + sdphase = (readl(addr) & DDRPHYC_DXNDLLCR_SDPHASE_MASK) + >> DDRPHYC_DXNDLLCR_SDPHASE_SHIFT; + + switch (sdphase) { + case 0x0: /* 90deg */ + case 0x5: + case 0xA: + case 0xF: + index = 3; /* The index of 90deg in dx_dll_phase */ + break; + + case 0x2: /* 54deg */ + case 0x7: + index = 1; + break; + + case 0x1: /* 72deg */ + case 0x6: + case 0xB: + index = 2; + break; + + case 0x3: /* 36deg */ + index = 0; + break; + + case 0x4: /* 108deg */ + case 0x9: + case 0xe: + index = 4; + break; + + case 0x8: /* 126deg */ + case 0xd: + index = 5; + break; + + case 0xc: /* 144deg */ + index = 6; + break; + + default: + index = 3; /* 90deg */ + } + + pr_debug("%s: [%x]: %x => phase = %x -> DQS phase index = %d\n", + __func__, addr, readl(addr), sdphase, index); + + return index; +} + +/* Read DQS unit delay register and provides the index of the retrieved value + * We are assuming that the delay on DQS and DQSN are equal + */ +u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u32 addr = DXNDQSTR(phy, byte); + u32 index; + + /* We are assuming that the delay on DQS and DQSN are equal */ + index = (readl(addr) & DDRPHYC_DXNDQSTR_DQSDLY_MASK) + >> DDRPHYC_DXNDQSTR_DQSDLY_SHIFT; + + pr_debug("%s: [%x]: %x => DQS unit index = %x\n", + __func__, addr, readl(addr), index); + + return index; +} + +/* Read DQ unit delay register and provides the retrieved value for DQS + * We are assuming that we have the same delay when clocking + * by DQS and when clocking by DQSN + */ +u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) +{ + u32 index; + u32 addr = DXNDQTR(phy, byte); + + /* We are assuming that we have the same delay when clocking by DQS + * and when clocking by DQSN : use only the low bits + */ + index = (readl(addr) >> DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit)) + & DDRPHYC_DXNDQTR_DQDLY_LOW_MASK; + + pr_debug("%s: [%x]: %x => DQ unit index = %x\n", + __func__, addr, readl(addr), index); + + return index; +} + +/* read r0dgsl value */ +u8 get_r0dgsl_index(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u32 addr = DXNDQSTR(phy, byte); + + return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGSL_MASK) + >> DDRPHYC_DXNDQSTR_R0DGSL_SHIFT; +} + +/*read r0dgsl value */ +u8 get_r0dgps_index(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u32 addr = DXNDQSTR(phy, byte); + + return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGPS_MASK) + >> DDRPHYC_DXNDQSTR_R0DGPS_SHIFT; +} + +/* Sets the DQS phase delay for a byte lane. + *phase delay is specified by giving the index of the desired delay + * in the dx_dll_phase array. + */ +void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) +{ + u8 sdphase_val = 0; + + /* Write DXNDLLCR.SDPHASE = dx_dll_phase(phase_index); */ + sdphase_val = dx_dll_phase[phase_idx]; + clrsetbits_le32(DXNDLLCR(phy, byte), + DDRPHYC_DXNDLLCR_SDPHASE_MASK, + sdphase_val << DDRPHYC_DXNDLLCR_SDPHASE_SHIFT); +} + +/* Sets the DQS unit delay for a byte lane. + * unit delay is specified by giving the index of the desired delay + * for dgsdly and dqsndly (same value). + */ +void DQS_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 unit_dly_idx) +{ + /* Write the same value in DXNDQSTR.DQSDLY and DXNDQSTR.DQSNDLY */ + clrsetbits_le32(DXNDQSTR(phy, byte), + DDRPHYC_DXNDQSTR_DQSDLY_MASK | + DDRPHYC_DXNDQSTR_DQSNDLY_MASK, + (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSDLY_SHIFT) | + (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT)); + + /* After changing this value, an ITM soft reset (PIR.ITMSRST=1, + * plus PIR.INIT=1) must be issued. + */ + stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); +} + +/* Sets the DQ unit delay for a bit line in particular byte lane. + * unit delay is specified by giving the desired delay + */ +void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 bit, + u8 dq_delay_index) +{ + u8 dq_bit_delay_val = dq_delay_index | (dq_delay_index << 2); + + /* same value on delay for clock DQ an DQS_b */ + clrsetbits_le32(DXNDQTR(phy, byte), + DDRPHYC_DXNDQTR_DQDLY_MASK + << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit), + dq_bit_delay_val << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit)); +} + +void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgsl_idx) +{ + clrsetbits_le32(DXNDQSTR(phy, byte), + DDRPHYC_DXNDQSTR_R0DGSL_MASK, + r0dgsl_idx << DDRPHYC_DXNDQSTR_R0DGSL_SHIFT); +} + +void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgps_idx) +{ + clrsetbits_le32(DXNDQSTR(phy, byte), + DDRPHYC_DXNDQSTR_R0DGPS_MASK, + r0dgps_idx << DDRPHYC_DXNDQSTR_R0DGPS_SHIFT); +} + +/* Basic BIST configuration for data lane tests. */ +void config_BIST(struct stm32mp1_ddrphy *phy) +{ + /* Selects the SDRAM bank address to be used during BIST. */ + u32 bbank = 0; + /* Selects the SDRAM row address to be used during BIST. */ + u32 brow = 0; + /* Selects the SDRAM column address to be used during BIST. */ + u32 bcol = 0; + /* Selects the value by which the SDRAM address is incremented + * for each write/read access. + */ + u32 bainc = 0x00000008; + /* Specifies the maximum SDRAM rank to be used during BIST. + * The default value is set to maximum ranks minus 1. + * must be 0 with single rank + */ + u32 bmrank = 0; + /* Selects the SDRAM rank to be used during BIST. + * must be 0 with single rank + */ + u32 brank = 0; + /* Specifies the maximum SDRAM bank address to be used during + * BIST before the address & increments to the next rank. + */ + u32 bmbank = 1; + /* Specifies the maximum SDRAM row address to be used during + * BIST before the address & increments to the next bank. + */ + u32 bmrow = 0x7FFF; /* To check */ + /* Specifies the maximum SDRAM column address to be used during + * BIST before the address & increments to the next row. + */ + u32 bmcol = 0x3FF; /* To check */ + u32 bmode_conf = 0x00000001; /* DRam mode */ + u32 bdxen_conf = 0x00000001; /* BIST on Data byte */ + u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */ + + /*Setup BIST for DRAM mode, and LFSR-random data pattern.*/ + /*Write BISTRR.BMODE = 1?b1;*/ + /*Write BISTRR.BDXEN = 1?b1;*/ + /*Write BISTRR.BDPAT = 2?b10;*/ + + /* reset BIST */ + writel(0x3, &phy->bistrr); + + writel((bmode_conf << 3) | (bdxen_conf << 14) | (bdpat_conf << 17), + &phy->bistrr); + + /*Setup BIST Word Count*/ + /*Write BISTWCR.BWCNT = 16?b0008;*/ + writel(0x00000200, &phy->bistwcr); /* A multiple of BL/2 */ + + writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0); + writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1); + + /* To check this line : */ + writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2); +} + +/* Select the Byte lane to be tested by BIST. */ +void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) +{ + clrsetbits_le32(&phy->bistrr, + DDRPHYC_BISTRR_BDXSEL_MASK, + datx8 << DDRPHYC_BISTRR_BDXSEL_SHIFT); + + /*(For example, selecting Byte Lane 3, BISTRR.BDXSEL = 4?b0011)*/ + /* Write BISTRR.BDXSEL = datx8; */ +} + +/* Perform BIST Write_Read test on a byte lane and return test result. */ +void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, + struct BIST_result *bist) +{ + bool result = true; /* BIST_SUCCESS */ + u32 cnt = 0; + u32 error = 0; + + bist->test_result = true; + +run: + itm_soft_reset(phy); + + /*Perform BIST Reset*/ + /* Write BISTRR.BINST = 3?b011; */ + clrsetbits_le32(&phy->bistrr, + 0x00000007, + 0x00000003); + + /*Re-seed LFSR*/ + /* Write BISTLSR.SEED = 32'h1234ABCD; */ + if (BIST_seed) + writel(BIST_seed, &phy->bistlsr); + else + writel(rand(), &phy->bistlsr); + + /* some delay to reset BIST */ + mdelay(1); + + /*Perform BIST Run*/ + clrsetbits_le32(&phy->bistrr, + 0x00000007, + 0x00000001); + /* Write BISTRR.BINST = 3?b001; */ + + /* Wait for a number of CTL clocks before reading BIST register*/ + /* Wait 300 ctl_clk cycles; ... IS it really needed?? */ + /* Perform BIST Instruction Stop*/ + /* Write BISTRR.BINST = 3?b010;*/ + + /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */ + while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE)) + ; + + /*Check if received correct number of words*/ + /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */ + if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) == + readl(&phy->bistwcr)) { + /*Determine if there is a data comparison error*/ + /* if (Read BISTGSR.BDXERR = 1?b0) */ + if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR) + result = false; /* BIST_FAIL; */ + else + result = true; /* BIST_SUCCESS; */ + } else { + result = false; /* BIST_FAIL; */ + } + + /* loop while success */ + cnt++; + if (result && cnt != 1000) + goto run; + + if (!result) { + error++; +#ifdef DEBUG_BIST + if (error < 5) + printf(" %d: %d, bistwcsr=0x%x, bistgsr=0x%x\n", + error, cnt, readl(&phy->bistwcsr), + readl(&phy->bistgsr)); +#endif + } + if (error < BIST_error_max) { + if (cnt != 1000) + goto run; + bist->test_result = true; + } else { + bist->test_result = false; + } +#ifdef DEBUG_BIST + if (cnt != 1000) + goto run; + printf(" - BIST result = %d, error=%d\n", bist->test_result, error); +#endif +} + +/* Init the Write_Read result struct. */ +void init_result_struct(struct BIST_result *result) +{ + u8 i = 0; + + /* Init with an overall "true" (success) condition. + * Any fail at any bit will set this to false + */ + result->test_result = true; + result->all_bits_fail = false; + + /* Init with an "true" (success) condition for bit_i. + * A fail at this bit will set this to false + */ + for (i = 0; i < 8; i++) + result->bit_i_test_result[i] = true; +} + +/* After running the deskew algo, this function applies the new DQ delays + * by reading them from the array "deskew_delay"and writing in PHY registers. + * The bits that are not deskewed parfectly (too much skew on them, + * or data eye very wide) are marked in the array deskew_non_converge. + */ +void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u8 bit_i; + u8 index; + + for (bit_i = 0; bit_i < 8; bit_i++) { + set_DQ_unit_delay(phy, byte, bit_i, deskew_delay[byte][bit_i]); + index = DQ_unit_index(phy, byte, bit_i); + pr_debug("Byte %d ; bit %d : The new DQ delay (%d) index=%d [delta=%d, 3 is the default]", + byte, bit_i, deskew_delay[byte][bit_i], + index, index - 3); + printf("Byte %d, bit %d, DQ delay = %d", + byte, bit_i, deskew_delay[byte][bit_i]); + if (deskew_non_converge[byte][bit_i] == 1) + pr_debug(" - not converged : still more skew"); + printf("\n"); + } +} + +/* DQ Bit de-skew algorithm. + * Deskews data lines as much as possible. + * 1. Add delay to DQS line until finding the failure + * (normally a hold time violation) + * 2. Reduce DQS line by small steps until finding the very first time + * we go back to "Pass" condition. + * 3. For each DQ line, Reduce DQ delay until finding the very first failure + * (normally a hold time fail) + * 4. When all bits are at their first failure delay, we can consider them + * aligned. + * Handle conrer situation (Can't find Pass-fail, or fail-pass transitions + * at any step) + * TODO Provide a return Status. Improve doc + */ +static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, char *string) +{ + struct BIST_result result; + s8 dqs_unit_delay_index = 0; + u8 datx8 = 0; + u8 bit_i = 0; + s8 phase_idx = 0; + s8 bit_i_delay_index = 0; + u8 success = 0; + struct tuning_position last_right_ok; + u8 force_stop = 0; + u8 fail_found; + u8 error = 0; + u8 nb_bytes = get_nb_bytes(ctl); + /* u8 last_pass_dqs_unit = 0; */ + + memset(deskew_delay, 0, sizeof(deskew_delay)); + memset(deskew_non_converge, 0, sizeof(deskew_non_converge)); + + /*Disable DQS Drift Compensation*/ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); + /*Disable all bytes*/ + /* Disable automatic power down of DLL and IOs when disabling + * a byte (To avoid having to add programming and delay + * for a DLL re-lock when later re-enabling a disabled Byte Lane) + */ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); + + /* Disable all data bytes */ + clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + /* Config the BIST block */ + config_BIST(phy); + pr_debug("BIST Config done.\n"); + + /* Train each byte */ + for (datx8 = 0; datx8 < nb_bytes; datx8++) { + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + datx8 + 1, nb_bytes, error); + return TEST_FAILED; + } + pr_debug("\n======================\n"); + pr_debug("Start deskew byte %d .\n", datx8); + pr_debug("======================\n"); + /* Enable Byte (DXNGCR, bit DXEN) */ + setbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN); + + /* Select the byte lane for comparison of read data */ + BIST_datx8_sel(phy, datx8); + + /* Set all DQDLYn to maximum value. All bits within the byte + * will be delayed with DQSTR = 2 instead of max = 3 + * to avoid inter bits fail influence + */ + writel(0xAAAAAAAA, DXNDQTR(phy, datx8)); + + /* Set the DQS phase delay to 90 DEG (default). + * What is defined here is the index of the desired config + * in the PHASE array. + */ + phase_idx = _90deg; + + /* Set DQS unit delay to the max value. */ + dqs_unit_delay_index = MAX_DQS_UNIT_IDX; + DQS_unit_delay(phy, datx8, dqs_unit_delay_index); + DQS_phase_delay(phy, datx8, phase_idx); + + /* Issue a DLL soft reset */ + clrbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST); + setbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST); + + /* Test this typical init condition */ + BIST_test(phy, datx8, &result); + success = result.test_result; + + /* If the test pass in this typical condition, + * start the algo with it. + * Else, look for Pass init condition + */ + if (!success) { + pr_debug("Fail at init condtion. Let's look for a good init condition.\n"); + success = 0; /* init */ + /* Make sure we start with a PASS condition before + * looking for a fail condition. + * Find the first PASS PHASE condition + */ + + /* escape if we find a PASS */ + pr_debug("increase Phase idx\n"); + while (!success && (phase_idx <= MAX_DQS_PHASE_IDX)) { + DQS_phase_delay(phy, datx8, phase_idx); + BIST_test(phy, datx8, &result); + success = result.test_result; + phase_idx++; + } + /* if ended with success + * ==>> Restore the fist success condition + */ + if (success) + phase_idx--; /* because it ended with ++ */ + } + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + datx8 + 1, nb_bytes, error); + return TEST_FAILED; + } + /* We couldn't find a successful condition, its seems + * we have hold violation, lets try reduce DQS_unit Delay + */ + if (!success) { + /* We couldn't find a successful condition, its seems + * we have hold violation, lets try reduce DQS_unit + * Delay + */ + pr_debug("Still fail. Try decrease DQS Unit delay\n"); + + phase_idx = 0; + dqs_unit_delay_index = 0; + DQS_phase_delay(phy, datx8, phase_idx); + + /* escape if we find a PASS */ + while (!success && + (dqs_unit_delay_index <= + MAX_DQS_UNIT_IDX)) { + DQS_unit_delay(phy, datx8, + dqs_unit_delay_index); + BIST_test(phy, datx8, &result); + success = result.test_result; + dqs_unit_delay_index++; + } + if (success) { + /* Restore the first success condition*/ + dqs_unit_delay_index--; + /* last_pass_dqs_unit = dqs_unit_delay_index;*/ + DQS_unit_delay(phy, datx8, + dqs_unit_delay_index); + } else { + /* No need to continue, + * there is no pass region. + */ + force_stop = 1; + } + } + + /* There is an initial PASS condition + * Look for the first failing condition by PHASE stepping. + * This part of the algo can finish without converging. + */ + if (force_stop) { + printf("Result: Failed "); + printf("[Cannot Deskew lines, "); + printf("there is no PASS region]\n"); + error++; + continue; + } + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + datx8 + 1, nb_bytes, error); + return TEST_FAILED; + } + + pr_debug("there is a pass region for phase idx %d\n", + phase_idx); + pr_debug("Step1: Find the first failing condition\n"); + /* Look for the first failing condition by PHASE stepping. + * This part of the algo can finish without converging. + */ + + /* escape if we find a fail (hold time violation) + * condition at any bit or if out of delay range. + */ + while (success && (phase_idx <= MAX_DQS_PHASE_IDX)) { + DQS_phase_delay(phy, datx8, phase_idx); + BIST_test(phy, datx8, &result); + success = result.test_result; + phase_idx++; + } + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + datx8 + 1, nb_bytes, error); + return TEST_FAILED; + } + + /* if the loop ended with a failing condition at any bit, + * lets look for the first previous success condition by unit + * stepping (minimal delay) + */ + if (!success) { + pr_debug("Fail region (PHASE) found phase idx %d\n", + phase_idx); + pr_debug("Let's look for first success by DQS Unit steps\n"); + /* This part, the algo always converge */ + phase_idx--; + + /* escape if we find a success condition + * or if out of delay range. + */ + while (!success && dqs_unit_delay_index >= 0) { + DQS_unit_delay(phy, datx8, + dqs_unit_delay_index); + BIST_test(phy, datx8, &result); + success = result.test_result; + dqs_unit_delay_index--; + } + /* if the loop ended with a success condition, + * the last delay Right OK (before hold violation) + * condition is then defined as following: + */ + if (success) { + /* Hold the dely parameters of the the last + * delay Right OK condition. + * -1 to get back to current condition + */ + last_right_ok.phase = phase_idx; + /*+1 to get back to current condition */ + last_right_ok.unit = dqs_unit_delay_index + 1; + last_right_ok.bits_delay = 0xFFFFFFFF; + pr_debug("Found %d\n", dqs_unit_delay_index); + } else { + /* the last OK condition is then with the + * previous phase_idx. + * -2 instead of -1 because at the last + * iteration of the while(), + * we incremented phase_idx + */ + last_right_ok.phase = phase_idx - 1; + /* Nominal+1. Because we want the previous + * delay after reducing the phase delay. + */ + last_right_ok.unit = 1; + last_right_ok.bits_delay = 0xFFFFFFFF; + pr_debug("Not Found : try previous phase %d\n", + phase_idx - 1); + + DQS_phase_delay(phy, datx8, phase_idx - 1); + dqs_unit_delay_index = 0; + success = true; + while (success && + (dqs_unit_delay_index < + MAX_DQS_UNIT_IDX)) { + DQS_unit_delay(phy, datx8, + dqs_unit_delay_index); + BIST_test(phy, datx8, &result); + success = result.test_result; + dqs_unit_delay_index++; + pr_debug("dqs_unit_delay_index = %d, result = %d\n", + dqs_unit_delay_index, success); + } + + if (!success) { + last_right_ok.unit = + dqs_unit_delay_index - 1; + } else { + last_right_ok.unit = 0; + pr_debug("ERROR: failed region not FOUND"); + } + } + } else { + /* we can't find a failing condition at all bits + * ==> Just hold the last test condition + * (the max DQS delay) + * which is the most likely, + * the closest to a hold violation + * If we can't find a Fail condition after + * the Pass region, stick at this position + * In order to have max chances to find a fail + * when reducing DQ delays. + */ + last_right_ok.phase = MAX_DQS_PHASE_IDX; + last_right_ok.unit = MAX_DQS_UNIT_IDX; + last_right_ok.bits_delay = 0xFFFFFFFF; + pr_debug("Can't find the a fail condition\n"); + } + + /* step 2: + * if we arrive at this stage, it means that we found the last + * Right OK condition (by tweeking the DQS delay). Or we simply + * pushed DQS delay to the max + * This means that by reducing the delay on some DQ bits, + * we should find a failing condition. + */ + printf("Byte %d, DQS unit = %d, phase = %d\n", + datx8, last_right_ok.unit, last_right_ok.phase); + pr_debug("Step2, unit = %d, phase = %d, bits delay=%x\n", + last_right_ok.unit, last_right_ok.phase, + last_right_ok.bits_delay); + + /* Restore the last_right_ok condtion. */ + DQS_unit_delay(phy, datx8, last_right_ok.unit); + DQS_phase_delay(phy, datx8, last_right_ok.phase); + writel(last_right_ok.bits_delay, DXNDQTR(phy, datx8)); + + /* train each bit + * reduce delay on each bit, and perform a write/read test + * and stop at the very first time it fails. + * the goal is the find the first failing condition + * for each bit. + * When we achieve this condition< for all the bits, + * we are sure they are aligned (+/- step resolution) + */ + fail_found = 0; + for (bit_i = 0; bit_i < 8; bit_i++) { + if (ctrlc()) { + sprintf(string, + "interrupted at byte %d/%d, error=%d", + datx8 + 1, nb_bytes, error); + return error; + } +#ifdef DEBUG_BIST + printf("deskewing bit %d:\n", bit_i); +#else + pr_debug("deskewing bit %d:\n", bit_i); +#endif + success = 1; /* init */ + /* Set all DQDLYn to maximum value. + * Only bit_i will be down-delayed + * ==> if we have a fail, it will be definitely + * from bit_i + */ + writel(0xFFFFFFFF, DXNDQTR(phy, datx8)); + /* Arriving at this stage, + * we have a success condition with delay = 3; + */ + bit_i_delay_index = 3; + + /* escape if bit delay is out of range or + * if a fatil occurs + */ + while ((bit_i_delay_index >= 0) && success) { + set_DQ_unit_delay(phy, datx8, + bit_i, + bit_i_delay_index); +#ifdef DEBUG_BIST + printf(" delay_index %d:\n", bit_i_delay_index); +#endif + BIST_test(phy, datx8, &result); + success = result.test_result; + bit_i_delay_index--; + } +#ifdef DEBUG_BIST + { /* check next error */ + int delay_index = bit_i_delay_index; + + while (delay_index >= 0) { + set_DQ_unit_delay(phy, datx8, bit_i, + delay_index); + printf(" delay_index %d:\n", + delay_index); + BIST_test(phy, datx8, &result); + delay_index--; + } + } +#endif + + /* if escape with a fail condition + * ==> save this position for bit_i + */ + if (!success) { + /* save the delay position. + * Add 1 because the while loop ended with a --, + * and that we need to hold the last success + * delay + */ + deskew_delay[datx8][bit_i] = + bit_i_delay_index + 2; + if (deskew_delay[datx8][bit_i] > 3) + deskew_delay[datx8][bit_i] = 3; + + /* A flag that states we found at least a fail + * at one bit. + */ + fail_found = 1; + pr_debug("Fail found on bit %d, for delay = %d => deskew[%d][%d] = %d\n", + bit_i, bit_i_delay_index + 1, + datx8, bit_i, + deskew_delay[datx8][bit_i]); + } else { + /* if we can find a success condition by + * back-delaying this bit, just set the delay + * to 0 (the best deskew + * possible) and mark the bit. + */ + deskew_delay[datx8][bit_i] = 0; + /* set a flag that will be used later + * in the report. + */ + deskew_non_converge[datx8][bit_i] = 1; + pr_debug("Fail not found on bit %d => deskew[%d][%d] = %d\n", + bit_i, datx8, bit_i, + deskew_delay[datx8][bit_i]); + } + } + pr_debug("**********byte %d tuning complete************\n", + datx8); + /* If we can't find any failure by back delaying DQ lines, + * hold the default values + */ + if (!fail_found) { + for (bit_i = 0; bit_i < 8; bit_i++) + deskew_delay[datx8][bit_i] = 0; + pr_debug("The Deskew algorithm can't converge, there is too much margin in your design. Good job!\n"); + } + + apply_deskew_results(phy, datx8); + /* Restore nominal value for DQS delay */ + DQS_phase_delay(phy, datx8, 3); + DQS_unit_delay(phy, datx8, 3); + /* disable byte after byte bits deskew */ + clrbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN); + } /* end of byte deskew */ + + /* re-enable all data bytes */ + setbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + setbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + setbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + setbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + if (error) { + sprintf(string, "error = %d", error); + return TEST_FAILED; + } + + return TEST_PASSED; +} /* end function */ + +/* TODO: Check if how delay blocks work. Maybe I have a wrong assumption!! + * Can check with Tuning App note. + */ + +/* Trim DQS timings and set it in the centre of data eye. + * Look for a PPPPF region, then look for a FPPP region and finally select + * the mid of the FPPPPPF region + */ + +static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, char *string) +{ + u8 byte = 0; + struct BIST_result result; + s8 dqs_unit_delay_index = 0; + s8 phase_idx = 0; + s8 dqs_unit_delay_index_pass = 0; + s8 phase_idx_pass = 0; + u8 success = 0; + u8 left_phase_bound_found, right_phase_bound_found; + u8 left_unit_bound_found, right_unit_bound_found; + u8 left_bound_found, right_bound_found; + struct tuning_position left_bound, right_bound; + u8 error = 0; + u8 nb_bytes = get_nb_bytes(ctl); + + /*Disable DQS Drift Compensation*/ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); + /*Disable all bytes*/ + /* Disable automatic power down of DLL and IOs when disabling a byte + * (To avoid having to add programming and delay + * for a DLL re-lock when later re-enabling a disabled Byte Lane) + */ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); + + /*Disable all data bytes */ + clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + /* Config the BIST block */ + config_BIST(phy); + + for (byte = 0; byte < nb_bytes; byte++) { + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + byte + 1, nb_bytes, error); + return TEST_FAILED; + } + right_bound.phase = 0; + right_bound.unit = 0; + + left_bound.phase = 0; + left_bound.unit = 0; + + left_phase_bound_found = 0; + right_phase_bound_found = 0; + + left_unit_bound_found = 0; + right_unit_bound_found = 0; + + left_bound_found = 0; + right_bound_found = 0; + + /* Enable Byte (DXNGCR, bit DXEN) */ + setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); + + /* Select the byte lane for comparison of read data */ + BIST_datx8_sel(phy, byte); + + /* Set DQS phase delay to the nominal value. */ + phase_idx = _90deg; + phase_idx_pass = phase_idx; + + /* Set DQS unit delay to the nominal value. */ + dqs_unit_delay_index = 3; + dqs_unit_delay_index_pass = dqs_unit_delay_index; + success = 0; + + pr_debug("STEP0: Find Init delay\n"); + /* STEP0: Find Init delay: a delay that put the system + * in a "Pass" condition then (TODO) update + * dqs_unit_delay_index_pass & phase_idx_pass + */ + DQS_unit_delay(phy, byte, dqs_unit_delay_index); + DQS_phase_delay(phy, byte, phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + /* If we have a fail in the nominal condition */ + if (!success) { + /* Look at the left */ + while (phase_idx >= 0 && !success) { + phase_idx--; + DQS_phase_delay(phy, byte, phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + } + } + if (!success) { + /* if we can't find pass condition, + * then look at the right + */ + phase_idx = _90deg; + while (phase_idx <= MAX_DQS_PHASE_IDX && + !success) { + phase_idx++; + DQS_phase_delay(phy, byte, + phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + } + } + /* save the pass condition */ + if (success) { + phase_idx_pass = phase_idx; + } else { + printf("Result: Failed "); + printf("[Cannot DQS timings, "); + printf("there is no PASS region]\n"); + error++; + continue; + } + + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + byte + 1, nb_bytes, error); + return TEST_FAILED; + } + pr_debug("STEP1: Find LEFT PHASE DQS Bound\n"); + /* STEP1: Find LEFT PHASE DQS Bound */ + while ((phase_idx >= 0) && + (phase_idx <= MAX_DQS_PHASE_IDX) && + !left_phase_bound_found) { + DQS_unit_delay(phy, byte, + dqs_unit_delay_index); + DQS_phase_delay(phy, byte, + phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + + /*TODO: Manage the case were at the beginning + * there is already a fail + */ + if (!success) { + /* the last pass condition */ + left_bound.phase = ++phase_idx; + left_phase_bound_found = 1; + } else if (success) { + phase_idx--; + } + } + if (!left_phase_bound_found) { + left_bound.phase = 0; + phase_idx = 0; + } + /* If not found, lets take 0 */ + + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + byte + 1, nb_bytes, error); + return TEST_FAILED; + } + pr_debug("STEP2: Find UNIT left bound\n"); + /* STEP2: Find UNIT left bound */ + while ((dqs_unit_delay_index >= 0) && + !left_unit_bound_found) { + DQS_unit_delay(phy, byte, + dqs_unit_delay_index); + DQS_phase_delay(phy, byte, phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + if (!success) { + left_bound.unit = + ++dqs_unit_delay_index; + left_unit_bound_found = 1; + left_bound_found = 1; + } else if (success) { + dqs_unit_delay_index--; + } + } + + /* If not found, lets take 0 */ + if (!left_unit_bound_found) + left_bound.unit = 0; + + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + byte + 1, nb_bytes, error); + return TEST_FAILED; + } + pr_debug("STEP3: Find PHase right bound\n"); + /* STEP3: Find PHase right bound, start with "pass" + * condition + */ + + /* Set DQS phase delay to the pass value. */ + phase_idx = phase_idx_pass; + + /* Set DQS unit delay to the pass value. */ + dqs_unit_delay_index = dqs_unit_delay_index_pass; + + while ((phase_idx <= MAX_DQS_PHASE_IDX) && + !right_phase_bound_found) { + DQS_unit_delay(phy, byte, + dqs_unit_delay_index); + DQS_phase_delay(phy, byte, phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + if (!success) { + /* the last pass condition */ + right_bound.phase = --phase_idx; + right_phase_bound_found = 1; + } else if (success) { + phase_idx++; + } + } + + /* If not found, lets take the max value */ + if (!right_phase_bound_found) { + right_bound.phase = MAX_DQS_PHASE_IDX; + phase_idx = MAX_DQS_PHASE_IDX; + } + + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d, error=%d", + byte + 1, nb_bytes, error); + return TEST_FAILED; + } + pr_debug("STEP4: Find UNIT right bound\n"); + /* STEP4: Find UNIT right bound */ + while ((dqs_unit_delay_index <= MAX_DQS_UNIT_IDX) && + !right_unit_bound_found) { + DQS_unit_delay(phy, byte, + dqs_unit_delay_index); + DQS_phase_delay(phy, byte, phase_idx); + BIST_test(phy, byte, &result); + success = result.test_result; + if (!success) { + right_bound.unit = + --dqs_unit_delay_index; + right_unit_bound_found = 1; + right_bound_found = 1; + } else if (success) { + dqs_unit_delay_index++; + } + } + /* If not found, lets take the max value */ + if (!right_unit_bound_found) + right_bound.unit = MAX_DQS_UNIT_IDX; + + /* If we found a regular FAil Pass FAil pattern + * FFPPPPPPFF + * OR PPPPPFF Or FFPPPPP + */ + + if (left_bound_found || right_bound_found) { + eye_training_val[byte][0] = (right_bound.phase + + left_bound.phase) / 2; + eye_training_val[byte][1] = (right_bound.unit + + left_bound.unit) / 2; + + /* If we already lost 1/2PHASE Tuning, + * let's try to recover by ++ on unit + */ + if (((right_bound.phase + left_bound.phase) % 2 == 1) && + eye_training_val[byte][1] != MAX_DQS_UNIT_IDX) + eye_training_val[byte][1]++; + pr_debug("** found phase : %d - %d & unit %d - %d\n", + right_bound.phase, left_bound.phase, + right_bound.unit, left_bound.unit); + pr_debug("** calculating mid region: phase: %d unit: %d (nominal is 3)\n", + eye_training_val[byte][0], + eye_training_val[byte][1]); + } else { + /* PPPPPPPPPP, we're already good. + * Set nominal values. + */ + eye_training_val[byte][0] = 3; + eye_training_val[byte][1] = 3; + } + DQS_phase_delay(phy, byte, eye_training_val[byte][0]); + DQS_unit_delay(phy, byte, eye_training_val[byte][1]); + + printf("Byte %d, DQS unit = %d, phase = %d\n", + byte, + eye_training_val[byte][1], + eye_training_val[byte][0]); + } + + if (error) { + sprintf(string, "error = %d", error); + return TEST_FAILED; + } + + return TEST_PASSED; +} + +void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u8 i = 0; + + printf("Byte %d Dekew result, bit0 delay, bit1 delay...bit8 delay\n ", + byte); + + for (i = 0; i < 8; i++) + printf("%d ", DQ_unit_index(phy, byte, i)); + printf("\n"); + + printf("dxndllcr: [%08x] val:%08x\n", + DXNDLLCR(phy, byte), + readl(DXNDLLCR(phy, byte))); + printf("dxnqdstr: [%08x] val:%08x\n", + DXNDQSTR(phy, byte), + readl(DXNDQSTR(phy, byte))); + printf("dxndqtr: [%08x] val:%08x\n", + DXNDQTR(phy, byte), + readl(DXNDQTR(phy, byte))); +} + +static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string) +{ + u8 byte, gsl_idx, gps_idx = 0; + struct BIST_result result; + u8 success = 0; + u8 nb_bytes = get_nb_bytes(ctl); + + memset(dqs_gating, 0x0, sizeof(dqs_gating)); + + /*disable dqs drift compensation*/ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); + /*disable all bytes*/ + /* disable automatic power down of dll and ios when disabling a byte + * (to avoid having to add programming and delay + * for a dll re-lock when later re-enabling a disabled byte lane) + */ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); + + /* disable all data bytes */ + clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + /* config the bist block */ + config_BIST(phy); + + for (byte = 0; byte < nb_bytes; byte++) { + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* enable byte x (dxngcr, bit dxen) */ + setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); + + /* select the byte lane for comparison of read data */ + BIST_datx8_sel(phy, byte); + for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { + for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { + if (ctrlc()) { + sprintf(string, + "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* write cfg to dxndqstr */ + set_r0dgsl_delay(phy, byte, gsl_idx); + set_r0dgps_delay(phy, byte, gps_idx); + + BIST_test(phy, byte, &result); + success = result.test_result; + if (success) + dqs_gating[byte][gsl_idx][gps_idx] = 1; + itm_soft_reset(phy); + } + } + set_midpoint_read_dqs_gating(phy, byte); + /* dummy reads */ + readl(0xc0000000); + readl(0xc0000000); + } + + /* re-enable drift compensation */ + /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */ + return TEST_PASSED; +} + +/* analyse the dgs gating log table, and determine the midpoint.*/ +static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte) +{ + u8 gsl_idx, gps_idx = 0; + u8 left_bound_idx[2] = {0, 0}; + u8 right_bound_idx[2] = {0, 0}; + u8 left_bound_found = 0; + u8 right_bound_found = 0; + u8 intermittent = 0; + u8 value; + + for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { + for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { + value = dqs_gating[byte][gsl_idx][gps_idx]; + if (value == 1 && left_bound_found == 0) { + left_bound_idx[0] = gsl_idx; + left_bound_idx[1] = gps_idx; + left_bound_found = 1; + } else if (value == 0 && + left_bound_found == 1 && + !right_bound_found) { + if (gps_idx == 0) { + right_bound_idx[0] = gsl_idx - 1; + right_bound_idx[1] = MAX_GPS_IDX; + } else { + right_bound_idx[0] = gsl_idx; + right_bound_idx[1] = gps_idx - 1; + } + right_bound_found = 1; + } else if (value == 1 && + right_bound_found == 1) { + intermittent = 1; + } + } + } + + /* if only ppppppp is found, there is no mid region. */ + if (left_bound_idx[0] == 0 && left_bound_idx[1] == 0 && + right_bound_idx[0] == 0 && right_bound_idx[1] == 0) + intermittent = 1; + + /*if we found a regular fail pass fail pattern ffppppppff + * or pppppff or ffppppp + */ + if (!intermittent) { + /*if we found a regular fail pass fail pattern ffppppppff + * or pppppff or ffppppp + */ + if (left_bound_found || right_bound_found) { + pr_debug("idx0(%d): %d %d idx1(%d) : %d %d\n", + left_bound_found, + right_bound_idx[0], left_bound_idx[0], + right_bound_found, + right_bound_idx[1], left_bound_idx[1]); + dqs_gate_values[byte][0] = + (right_bound_idx[0] + left_bound_idx[0]) / 2; + dqs_gate_values[byte][1] = + (right_bound_idx[1] + left_bound_idx[1]) / 2; + /* if we already lost 1/2gsl tuning, + * let's try to recover by ++ on gps + */ + if (((right_bound_idx[0] + + left_bound_idx[0]) % 2 == 1) && + dqs_gate_values[byte][1] != MAX_GPS_IDX) + dqs_gate_values[byte][1]++; + /* if we already lost 1/2gsl tuning and gps is on max*/ + else if (((right_bound_idx[0] + + left_bound_idx[0]) % 2 == 1) && + dqs_gate_values[byte][1] == MAX_GPS_IDX) { + dqs_gate_values[byte][1] = 0; + dqs_gate_values[byte][0]++; + } + /* if we have gsl left and write limit too close + * (difference=1) + */ + if (((right_bound_idx[0] - left_bound_idx[0]) == 1)) { + dqs_gate_values[byte][1] = (left_bound_idx[1] + + right_bound_idx[1] + + 4) / 2; + if (dqs_gate_values[byte][1] >= 4) { + dqs_gate_values[byte][0] = + right_bound_idx[0]; + dqs_gate_values[byte][1] -= 4; + } else { + dqs_gate_values[byte][0] = + left_bound_idx[0]; + } + } + pr_debug("*******calculating mid region: system latency: %d phase: %d********\n", + dqs_gate_values[byte][0], + dqs_gate_values[byte][1]); + pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n"); + set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]); + set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]); + } + } else { + /* if intermitant, restore defaut values */ + pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n"); + set_r0dgsl_delay(phy, byte, 0); + set_r0dgps_delay(phy, byte, 2); + } + + /* return 0 if intermittent or if both left_bound + * and right_bound are not found + */ + return !(intermittent || (left_bound_found && right_bound_found)); +} + +static void itm_soft_reset(struct stm32mp1_ddrphy *phy) +{ + stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); +} + +/**************************************************************** + * TEST + **************************************************************** + */ +static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, + char *argv[]) +{ + u32 rfshctl3 = readl(&ctl->rfshctl3); + u32 pwrctl = readl(&ctl->pwrctl); + enum test_result res; + + stm32mp1_refresh_disable(ctl); + res = read_dqs_gating(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + + return res; +} + +static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 rfshctl3 = readl(&ctl->rfshctl3); + u32 pwrctl = readl(&ctl->pwrctl); + enum test_result res; + + stm32mp1_refresh_disable(ctl); + res = bit_deskew(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + + return res; +} + +static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + u32 rfshctl3 = readl(&ctl->rfshctl3); + u32 pwrctl = readl(&ctl->pwrctl); + enum test_result res; + + stm32mp1_refresh_disable(ctl); + res = eye_training(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + + return res; +} + +static enum test_result do_display(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + int byte; + u8 nb_bytes = get_nb_bytes(ctl); + + for (byte = 0; byte < nb_bytes; byte++) + display_reg_results(phy, byte); + + return TEST_PASSED; +} + +static enum test_result do_bist_config(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string, int argc, char *argv[]) +{ + unsigned long value; + + if (argc > 0) { + if (strict_strtoul(argv[0], 0, &value) < 0) { + sprintf(string, "invalid nbErr %s", argv[0]); + return TEST_FAILED; + } + BIST_error_max = value; + } + if (argc > 1) { + if (strict_strtoul(argv[1], 0, &value) < 0) { + sprintf(string, "invalid Seed %s", argv[1]); + return TEST_FAILED; + } + BIST_seed = value; + } + printf("Bist.nbErr = %d\n", BIST_error_max); + if (BIST_seed) + printf("Bist.Seed = 0x%x\n", BIST_seed); + else + printf("Bist.Seed = random\n"); + + return TEST_PASSED; +} + +/**************************************************************** + * TEST Description + **************************************************************** + */ + +const struct test_desc tuning[] = { + {do_read_dqs_gating, "Read DQS gating", + "software read DQS Gating", "", 0 }, + {do_bit_deskew, "Bit de-skew", "", "", 0 }, + {do_eye_training, "Eye Training", "or DQS training", "", 0 }, + {do_display, "Display registers", "", "", 0 }, + {do_bist_config, "Bist config", "[nbErr] [seed]", + "configure Bist test", 2}, +}; + +const int tuning_nb = ARRAY_SIZE(tuning); diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.h b/drivers/ram/stm32mp1/stm32mp1_tuning.h new file mode 100644 index 000000000000..964a05011c91 --- /dev/null +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef _RAM_STM32MP1_TUNING_H_ +#define _RAM_STM32MP1_TUNING_H_ + +#define MAX_DQS_PHASE_IDX _144deg +#define MAX_DQS_UNIT_IDX 7 +#define MAX_GSL_IDX 5 +#define MAX_GPS_IDX 3 + +/* Number of bytes used in this SW. ( min 1--> max 4). */ +#define NUM_BYTES 4 + +enum dqs_phase_enum { + _36deg = 0, + _54deg = 1, + _72deg = 2, + _90deg = 3, + _108deg = 4, + _126deg = 5, + _144deg = 6 +}; + +/* BIST Result struct */ +struct BIST_result { + /* Overall test result: + * 0 Fail (any bit failed) , + * 1 Success (All bits success) + */ + bool test_result; + /* 1: true, all fail / 0: False, not all bits fail */ + bool all_bits_fail; + bool bit_i_test_result[8]; /* 0 fail / 1 success */ +}; + +u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte); +u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte); +u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit); + +void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte); +void init_result_struct(struct BIST_result *result); +void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, + struct BIST_result *result); + +/* a struct that defines tuning parameters of a byte. */ +struct tuning_position { + u8 phase; /* DQS phase */ + u8 unit; /* DQS unit delay */ + u32 bits_delay; /* Bits deskew in this byte */ +}; +#endif diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 9eb532bc7a78..b1cae5898e36 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -49,4 +49,13 @@ config REMOTEPROC_TI_POWER help Say 'y' here to add support for TI power processors such as those found on certain TI keystone and OMAP generation SoCs. + +config REMOTEPROC_STM32_COPRO + bool "Support for STM32 Co-processor" + select REMOTEPROC + depends on DM + depends on ARCH_STM32MP + depends on OF_CONTROL + help + Say 'y' here to add support for STM32 Cortex-M4 co-processors. endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 77eb70852359..5b120c12d6c5 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o +obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index c8a41a63327b..8ea92f753bbd 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -5,6 +5,7 @@ */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include +#include #include #include #include @@ -17,6 +18,40 @@ DECLARE_GLOBAL_DATA_PTR; +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves, + * each of which begins with a resource entry header (as described below). + */ +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[0]; +} __packed; + /** * for_each_remoteproc_device() - iterate through the list of rproc devices * @fn: check function to call per match, if this function returns fail, @@ -291,11 +326,252 @@ int rproc_dev_init(int id) return ret; } +/* + * Determine if a valid ELF image exists at the given memory location. + * First look at the ELF header magic field, then make sure that it is + * executable. + */ +static bool is_valid_elf_image(unsigned long addr, int size) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + + ehdr = (Elf32_Ehdr *)addr; + + if (!IS_ELF(*ehdr) || size <= sizeof(Elf32_Ehdr)) { + pr_err("No elf image at address 0x%08lx\n", addr); + return false; + } + + if (ehdr->e_type != ET_EXEC) { + pr_err("Not a 32-bit elf image at address 0x%08lx\n", addr); + return false; + } + + return true; +} + + +/* Basic function to verify ELF image format */ +static int +rproc_elf_sanity_check(struct udevice *dev, ulong addr, ulong size) +{ + Elf32_Ehdr *ehdr; + char class; + + if (!addr) { + dev_err(dev, "Invalid fw address?\n"); + return -EINVAL; + } + + if (size < sizeof(Elf32_Ehdr)) { + dev_err(dev, "Image is too small\n"); + return -EINVAL; + } + + ehdr = (Elf32_Ehdr *)addr; + + /* We only support ELF32 at this point */ + class = ehdr->e_ident[EI_CLASS]; + if (class != ELFCLASS32) { + dev_err(dev, "Unsupported class: %d\n", class); + return -EINVAL; + } + + /* We assume the firmware has the same endianness as the host */ +# ifdef __LITTLE_ENDIAN + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { +# else /* BIG ENDIAN */ + if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { +# endif + dev_err(dev, "Unsupported firmware endianness\n"); + return -EINVAL; + } + + if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) { + dev_err(dev, "Image is too small\n"); + return -EINVAL; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + dev_err(dev, "Image is corrupted (bad magic)\n"); + return -EINVAL; + } + + if (ehdr->e_phnum == 0) { + dev_err(dev, "No loadable segments\n"); + return -EINVAL; + } + + if (ehdr->e_phoff > size) { + dev_err(dev, "Firmware size is too small\n"); + return -EINVAL; + } + + return 0; +} + +/* + * A very simple elf loader, assumes the image is valid, returns the + * entry point address. + */ +static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, + unsigned long *entry) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + Elf32_Phdr *phdr; /* Program header structure pointer */ + const struct dm_rproc_ops *ops; + unsigned int i; + + ehdr = (Elf32_Ehdr *)addr; + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); + + ops = rproc_get_ops(dev); + if (!ops) { + dev_dbg(dev, "Driver has no ops?\n"); + return -EINVAL; + } + + /* Load each program header */ + for (i = 0; i < ehdr->e_phnum; ++i) { + void *dst = (void *)(uintptr_t)phdr->p_paddr; + void *src = (void *)addr + phdr->p_offset; + + if (phdr->p_type != PT_LOAD) + continue; + + if (ops->da_to_pa) + dst = (void *)ops->da_to_pa(dev, (ulong)dst); + + dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n", + i, dst, phdr->p_filesz); + if (phdr->p_filesz) + memcpy(dst, src, phdr->p_filesz); + if (phdr->p_filesz != phdr->p_memsz) + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + flush_cache((unsigned long)dst, phdr->p_filesz); + ++phdr; + } + + *entry = ehdr->e_entry; + + return 0; +} + +/* Helper to find resource table in an ELF image */ +static Elf32_Shdr *find_rsc_table(struct udevice *dev, Elf32_Ehdr *ehdr, + size_t fw_size) +{ + Elf32_Shdr *shdr; + int i; + const char *name_table; + struct resource_table *table = NULL; + const u8 *elf_data = (void *)ehdr; + + /* look for the resource table and handle it */ + shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff); + name_table = (const char *)(elf_data + + shdr[ehdr->e_shstrndx].sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + u32 size = shdr->sh_size; + u32 offset = shdr->sh_offset; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + table = (struct resource_table *)(elf_data + offset); + + /* make sure we have the entire table */ + if (offset + size > fw_size || offset + size < size) { + dev_err(dev, "resource table truncated\n"); + return NULL; + } + + /* make sure table has at least the header */ + if (sizeof(struct resource_table) > size) { + dev_err(dev, "header-less resource table\n"); + return NULL; + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + dev_err(dev, "unsupported fw ver: %d\n", table->ver); + return NULL; + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + dev_err(dev, "non zero reserved bytes\n"); + return NULL; + } + + /* make sure the offsets array isn't truncated */ + if (table->num * sizeof(table->offset[0]) + + sizeof(struct resource_table) > size) { + dev_err(dev, "resource table incomplete\n"); + return NULL; + } + + return shdr; + } + + return NULL; +} + +/** + * rproc_elf_find_load_rsc_table() - find the loaded resource table + * @dev: the rproc device + * @fw_addr: the ELF firmware image address + * @fw_size: the ELF firmware image size + * @rsc_addr: resource table address + * @rsc_size: resource table size + * + * This function finds the resource table, load it and return its address. + * + * Return: 0 if all ok, else appropriate error value. + */ +static int rproc_elf_find_load_rsc_table(struct udevice *dev, + ulong fw_addr, ulong fw_size, + ulong *rsc_addr, + unsigned int *rsc_size) +{ + const struct dm_rproc_ops *ops; + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr; + Elf32_Shdr *shdr; + void *src; + void *dst; + + shdr = find_rsc_table(dev, ehdr, fw_size); + if (!shdr) + return -ENODATA; + + *rsc_addr = (ulong)shdr->sh_addr; + *rsc_size = (unsigned int)shdr->sh_size; + + ops = rproc_get_ops(dev); + if (ops->da_to_pa) + dst = (void *)ops->da_to_pa(dev, (ulong)shdr->sh_addr); + else + dst = (void *)shdr->sh_addr; + + dev_dbg(dev, "Loading resource table to 0x%8lx (%i bytes)\n", + (ulong)dst, shdr->sh_size); + + src = (void *)fw_addr + shdr->sh_offset; + + memcpy(dst, src, shdr->sh_size); + flush_cache((unsigned long)dst, shdr->sh_size); + + return 0; +} + int rproc_load(int id, ulong addr, ulong size) { struct udevice *dev = NULL; struct dm_rproc_uclass_pdata *uc_pdata; const struct dm_rproc_ops *ops; + unsigned long entry; int ret; ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); @@ -315,8 +591,22 @@ int rproc_load(int id, ulong addr, ulong size) debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n", uc_pdata->name, addr, size); - if (ops->load) - return ops->load(dev, addr, size); + + if (is_valid_elf_image(addr, size)) { + if (rproc_elf_sanity_check(dev, addr, size)) + return -EINVAL; + + /* Elf file load */ + if (ops->reset) + ops->reset(dev); + + return rproc_load_elf_image(dev, addr, &entry); + + } else { + /* Binary file load */ + if (ops->load) + return ops->load(dev, addr, size); + } debug("%s: data corruption?? mandatory function is missing!\n", dev->name); @@ -324,6 +614,45 @@ int rproc_load(int id, ulong addr, ulong size) return -EINVAL; }; +int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr, + unsigned int *rsc_size) +{ + struct udevice *dev = NULL; + const struct dm_rproc_ops *ops; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); + if (ret) { + debug("Unknown remote processor id '%d' requested(%d)\n", + id, ret); + return -EINVAL; + } + + ops = rproc_get_ops(dev); + if (!ops) { + dev_dbg(dev, "Driver has no ops?\n"); + return -EINVAL; + } + + dev_dbg(dev, "Loocking for resource table from address 0x%08lX size of %lu bytes\n", + addr, size); + + if (!rproc_elf_sanity_check(dev, addr, size)) { + /* load elf image */ + ret = rproc_elf_find_load_rsc_table(dev, addr, size, rsc_addr, + rsc_size); + if (ret) { + dev_dbg(dev, "No resource table found\n"); + return -ENODATA; + } + dev_dbg(dev, "Resource table at 0x%08lx, size 0x%x!\n", + *rsc_addr, *rsc_size); + return 0; + } + + return -ENODATA; +}; + /* * Completely internal helper enums.. * Keeping this isolated helps this code evolve independent of other diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c new file mode 100644 index 000000000000..310d077ed818 --- /dev/null +++ b/drivers/remoteproc/stm32_copro.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RCC_GCR_HOLD_BOOT 0 +#define RCC_GCR_RELEASE_BOOT 1 + +/** + * struct stm32_copro_privdata - power processor private data + * @loadaddr: base address for loading the power processor + * @reset_ctl: reset controller handle + * @hold_boot_regmap + * @hold_boot_offset + * @hold_boot_mask + * @secured_soc: TZEN flag (register protection) + */ +struct stm32_copro_privdata { + phys_addr_t loadaddr; + struct reset_ctl reset_ctl; + struct regmap *hold_boot_regmap; + uint hold_boot_offset; + uint hold_boot_mask; + bool secured_soc; + }; + +/** + * st_of_to_priv() - generate private data from device tree + * @dev: corresponding ti remote processor device + * @priv: pointer to driver specific private data + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int st_of_to_priv(struct udevice *dev, + struct stm32_copro_privdata *priv) +{ + struct regmap *regmap; + const fdt32_t *cell; + const void *blob = gd->fdt_blob; + uint tz_offset, tz_mask, tzen; + int len, ret; + + if (!blob) { + dev_dbg(dev, "no dt?\n"); + return -EINVAL; + } + + priv->loadaddr = dev_read_addr(dev); + if (priv->loadaddr == FDT_ADDR_T_NONE) { + dev_dbg(dev, "no 'reg' property\n"); + return -EINVAL; + } + + regmap = syscon_phandle_to_regmap(dev, "st,syscfg-holdboot"); + if (IS_ERR(regmap)) { + dev_dbg(dev, "unable to find holdboot regmap (%ld)\n", + PTR_ERR(regmap)); + return -EINVAL; + } + + priv->hold_boot_regmap = regmap; + + cell = dev_read_prop(dev, "st,syscfg-holdboot", &len); + if (len < 3 * sizeof(fdt32_t)) { + dev_dbg(dev, "holdboot offset and mask not available\n"); + return -EINVAL; + } + + priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1); + + priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1); + + regmap = syscon_phandle_to_regmap(dev, "st,syscfg-tz"); + if (IS_ERR(regmap)) { + dev_dbg(dev, "unable to find tz regmap (%ld)\n", + PTR_ERR(regmap)); + return -EINVAL; + } + + cell = dev_read_prop(dev, "st,syscfg-tz", &len); + if (len < 3 * sizeof(fdt32_t)) { + dev_dbg(dev, "tz offset and mask not available\n"); + return -EINVAL; + } + + tz_offset = fdtdec_get_number(cell + 1, 1); + + tz_mask = fdtdec_get_number(cell + 2, 1); + + ret = regmap_read(regmap, tz_offset, &tzen); + if (ret) { + dev_dbg(dev, "failed to read soc secure state\n"); + return ret; + } + + priv->secured_soc = !!(tzen & tz_mask); + + return reset_get_by_index(dev, 0, &priv->reset_ctl); +} + +/** + * stm32_copro_probe() - Basic probe + * @dev: corresponding STM32 remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_probe(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + ret = st_of_to_priv(dev, priv); + + dev_dbg(dev, "probed with slave_addr=0x%08lX (%d)\n", + priv->loadaddr, ret); + + return ret; +} + +/* Hold boot bit management */ +static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold) +{ + struct stm32_copro_privdata *priv; + uint status, val; + int ret; + + priv = dev_get_priv(dev); + + val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT; + + if (priv->secured_soc) { + return stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE, + priv->hold_boot_offset, val); + } + + ret = regmap_read(priv->hold_boot_regmap, priv->hold_boot_offset, + &status); + if (ret) { + dev_err(dev, "failed to read status of mcu\n"); + return ret; + } + + status &= ~priv->hold_boot_mask; + status |= val; + + ret = regmap_write(priv->hold_boot_regmap, priv->hold_boot_offset, + status); + if (ret) + dev_err(dev, "failed to set hold boot\n"); + + return ret; +} + +/** + * stm32_copro_load() - Loadup the STM32 Cortex-M4 remote processor + * @dev: corresponding STM32 remote processor device + * @addr: Address in memory where image binary is stored + * @size: Size in bytes of the image binary + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + stm32_copro_set_hold_boot(dev, true); + + ret = reset_assert(&priv->reset_ctl); + if (ret) { + dev_dbg(dev, "Unable assert reset line (ret=%d)\n", ret); + return ret; + } + + dev_dbg(dev, "Loading binary from 0x%08lX, size 0x%08lX to 0x%08lX\n", + addr, size, priv->loadaddr); + + memcpy((void *)priv->loadaddr, (void *)addr, size); + + dev_dbg(dev, "Complete!\n"); + return 0; +} + +/** + * stm32_copro_start() - Start Cortex-M4 coprocessor + * @dev: corresponding st remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_start(struct udevice *dev) +{ + int ret; + + /* move hold boot from true to false start the copro */ + ret = stm32_copro_set_hold_boot(dev, false); + if (ret) + return ret; + + /* + * Once copro running, reset hold boot flag to avoid copro + * rebooting autonomously + */ + return stm32_copro_set_hold_boot(dev, true); +} + +/** + * stm32_copro_reset() - Reset Cortex-M4 coprocessor + * @dev: corresponding st remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int stm32_copro_reset(struct udevice *dev) +{ + struct stm32_copro_privdata *priv; + int ret; + + priv = dev_get_priv(dev); + + stm32_copro_set_hold_boot(dev, true); + + ret = reset_assert(&priv->reset_ctl); + if (ret) { + dev_dbg(dev, "Unable assert reset line (ret=%d)\n", ret); + return ret; + } + + return 0; +} + +ulong stm32_copro_da_to_pa(struct udevice *dev, ulong da) +{ + /* to update according to lastest DT */ + if (da >= 0 && da < 0x10000) + return (da + 0x38000000); + + return da; +} + +static const struct dm_rproc_ops stm32_copro_ops = { + .load = stm32_copro_load, + .start = stm32_copro_start, + .reset = stm32_copro_reset, + .da_to_pa = stm32_copro_da_to_pa, +}; + +static const struct udevice_id stm32_copro_ids[] = { + {.compatible = "st,stm32mp1-rproc"}, + {} +}; + +U_BOOT_DRIVER(stm32_copro) = { + .name = "stm32_m4_proc", + .of_match = stm32_copro_ids, + .id = UCLASS_REMOTEPROC, + .ops = &stm32_copro_ops, + .probe = stm32_copro_probe, + .priv_auto_alloc_size = sizeof(struct stm32_copro_privdata), +}; diff --git a/drivers/reset/stm32-reset.c b/drivers/reset/stm32-reset.c index 16d3dba74942..1d00e177444a 100644 --- a/drivers/reset/stm32-reset.c +++ b/drivers/reset/stm32-reset.c @@ -11,6 +11,13 @@ #include #include +#ifdef CONFIG_STM32MP1_TRUSTED +#include + +#define RCC_APB5RST_BANK 0x62 +#define RCC_AHB5RST_BANK 0x64 +#endif /* CONFIG_STM32MP1_TRUSTED */ + /* reset clear offset for STM32MP RCC */ #define RCC_CL 0x4 @@ -33,12 +40,23 @@ static int stm32_reset_assert(struct reset_ctl *reset_ctl) struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); int bank = (reset_ctl->id / BITS_PER_LONG) * 4; int offset = reset_ctl->id % BITS_PER_LONG; +#ifdef CONFIG_STM32MP1_TRUSTED + int rcc_bank = reset_ctl->id / BITS_PER_LONG; +#endif /* CONFIG_STM32MP1_TRUSTED */ + debug("%s: reset id = %ld bank = %d offset = %d)\n", __func__, reset_ctl->id, bank, offset); if (dev_get_driver_data(reset_ctl->dev) == STM32MP1) /* reset assert is done in rcc set register */ - writel(BIT(offset), priv->base + bank); +#ifdef CONFIG_STM32MP1_TRUSTED + if (rcc_bank == RCC_APB5RST_BANK || + rcc_bank == RCC_AHB5RST_BANK) + stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE, + bank, BIT(offset)); + else +#endif /* CONFIG_STM32MP1_TRUSTED */ + writel(BIT(offset), priv->base + bank); else setbits_le32(priv->base + bank, BIT(offset)); @@ -50,12 +68,23 @@ static int stm32_reset_deassert(struct reset_ctl *reset_ctl) struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); int bank = (reset_ctl->id / BITS_PER_LONG) * 4; int offset = reset_ctl->id % BITS_PER_LONG; +#ifdef CONFIG_STM32MP1_TRUSTED + int rcc_bank = reset_ctl->id / BITS_PER_LONG; +#endif /* CONFIG_STM32MP1_TRUSTED */ + debug("%s: reset id = %ld bank = %d offset = %d)\n", __func__, reset_ctl->id, bank, offset); if (dev_get_driver_data(reset_ctl->dev) == STM32MP1) /* reset deassert is done in rcc clr register */ - writel(BIT(offset), priv->base + bank + RCC_CL); +#ifdef CONFIG_STM32MP1_TRUSTED + if (rcc_bank == RCC_APB5RST_BANK || + rcc_bank == RCC_AHB5RST_BANK) + stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE, + bank + RCC_CL, BIT(offset)); + else +#endif /* CONFIG_STM32MP1_TRUSTED */ + writel(BIT(offset), priv->base + bank + RCC_CL); else clrbits_le32(priv->base + bank, BIT(offset)); diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 66e02d5689d0..d806057c607d 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,14 @@ static int stm32_serial_setconfig(struct udevice *dev, uint serial_config) uint bits = SERIAL_GET_BITS(serial_config); uint stop = SERIAL_GET_STOP(serial_config); + /* + * only parity config is implemented, check if other serial settings + * are the default one. + * (STM32F4 serial IP didn't support parity setting) + */ + if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP || stm32f4) + return -ENOTSUPP; /* not supported in driver*/ + /* * only parity config is implemented, check if other serial settings * are the default one. @@ -171,6 +180,7 @@ static int stm32_serial_probe(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); struct clk clk; + struct reset_ctl reset; int ret; plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); @@ -185,6 +195,13 @@ static int stm32_serial_probe(struct udevice *dev) return ret; } + ret = reset_get_by_index(dev, 0, &reset); + if (!ret) { + reset_assert(&reset); + udelay(2); + reset_deassert(&reset); + } + plat->clock_rate = clk_get_rate(&clk); if (plat->clock_rate < 0) { clk_disable(&clk); @@ -258,7 +275,6 @@ static inline void _debug_uart_init(void) _stm32_serial_setbrg(base, uart_info, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); - printf("DEBUG done\n"); } static inline void _debug_uart_putc(int c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 516188ea88e1..da967542647c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -191,7 +191,7 @@ config SANDBOX_SPI config STM32_QSPI bool "STM32F7 QSPI driver" - depends on STM32F7 + 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/soft_spi.c b/drivers/spi/soft_spi.c index b06883f9d044..b80f810bd157 100644 --- a/drivers/spi/soft_spi.c +++ b/drivers/spi/soft_spi.c @@ -215,8 +215,8 @@ static int soft_spi_probe(struct udevice *dev) int cs_flags, clk_flags; int ret; - cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; - clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; + cs_flags = (slave && slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; + clk_flags = (slave && slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs, GPIOD_IS_OUT | cs_flags) || diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 34506402ac3a..9d02aafec512 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -24,6 +24,9 @@ static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) { struct syscon_reboot_priv *priv = dev_get_priv(dev); + if (type == SYSRESET_POWER) + return -EPROTONOSUPPORT; + regmap_write(priv->regmap, priv->offset, priv->mask); return -EINPROGRESS; @@ -36,20 +39,9 @@ static struct sysreset_ops syscon_reboot_ops = { int syscon_reboot_probe(struct udevice *dev) { struct syscon_reboot_priv *priv = dev_get_priv(dev); - int err; - u32 phandle; - ofnode node; - - err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle); - if (err) - return err; - - node = ofnode_get_by_phandle(phandle); - if (!ofnode_valid(node)) - return -EINVAL; - priv->regmap = syscon_node_to_regmap(node); - if (!priv->regmap) { + priv->regmap = syscon_phandle_to_regmap(dev, "regmap"); + if (IS_ERR(priv->regmap)) { pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 26b4d12a09fa..fa1cdc4bb73d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -72,6 +72,15 @@ config USB_GADGET_BCM_UDC_OTG_PHY help Enable the Broadcom UDC OTG physical device interface. +config USB_GADGET_GEN_UDC_OTG_PHY + bool "Generic UDC OTG PHY" + depends on PHY && USB_GADGET_DWC2_OTG + default y if ARCH_STM32MP + help + Enable the generic UDC OTG physical device interface. + it is based on the generic phy driver API on the phy + u-class and on the device tree information + config USB_GADGET_DWC2_OTG bool "DesignWare USB2.0 HS OTG controller (gadget mode)" select USB_GADGET_DUALSPEED diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b74c1fdce974..abb3c2067abe 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o +obj-$(CONFIG_USB_GADGET_GEN_UDC_OTG_PHY) += gen_udc_otg_phy.o obj-$(CONFIG_CI_UDC) += ci_udc.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index e3edd10e29c0..6552a5b2385e 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -425,6 +425,9 @@ static void reconfig_usbd(struct dwc2_udc *dev) writel(dflt_gusbcfg, ®->gusbcfg); + if (dev->pdata->usb_gotgctl) + setbits_le32(®->gotgctl, dev->pdata->usb_gotgctl); + /* 3. Put the OTG device core in the disconnected state.*/ uTemp = readl(®->dctl); uTemp |= SOFT_DISCONNECT; diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index e9e1600a1a50..43d0516a0d69 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -89,6 +89,11 @@ static struct usb_gadget_strings *g_dnl_composite_strings[] = { NULL, }; +void g_dnl_set_product(const char *s) +{ + g_dnl_string_defs[1].s = s; +} + static int g_dnl_unbind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; diff --git a/drivers/usb/gadget/gen_udc_otg_phy.c b/drivers/usb/gadget/gen_udc_otg_phy.c new file mode 100644 index 000000000000..36c31cd078ff --- /dev/null +++ b/drivers/usb/gadget/gen_udc_otg_phy.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include + +#include "dwc2_udc_otg_priv.h" + +void otg_phy_init(struct dwc2_udc *dev) +{ + struct dwc2_plat_otg_data *pdata = dev->pdata; + struct udevice *phy_dev; + struct phy phy; + + if (uclass_get_device_by_of_offset(UCLASS_PHY, + pdata->phy_of_node, &phy_dev)) { + pr_err("failed to found usb phy\n"); + hang(); + return; + } + + phy.dev = phy_dev; + phy.id = pdata->regs_phy; + + if (generic_phy_init(&phy)) { + pr_err("failed to init usb phy\n"); + generic_phy_power_off(&phy); + return; + } + + if (generic_phy_power_on(&phy)) { + pr_err("unable to power on the phy\n"); + return; + } + + pr_debug("USB Generic PHY Enable\n"); +} + +void otg_phy_off(struct dwc2_udc *dev) +{ + struct dwc2_plat_otg_data *pdata = dev->pdata; + struct udevice *phy_dev; + struct phy phy; + int ret; + + uclass_get_device_by_of_offset(UCLASS_PHY, + pdata->phy_of_node, &phy_dev); + phy.dev = phy_dev; + phy.id = pdata->regs_phy; + + ret = generic_phy_power_off(&phy); + if (ret) { + pr_err("failed to power off usb phy\n"); + return; + } + ret = generic_phy_exit(&phy); + if (ret) { + pr_err("failed to power off usb phy\n"); + return; + } + + pr_debug("USB Generic PHY Disable\n"); +} diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index b6f008a4004d..f96da8e76fc4 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -5,12 +5,15 @@ */ #include +#include #include #include -#include +#include #include #include #include +#include +#include #include #include #include @@ -35,6 +38,7 @@ struct dwc2_priv { #ifdef CONFIG_DM_REGULATOR struct udevice *vbus_supply; #endif + struct phy phy; #else uint8_t *aligned_buffer; uint8_t *status_buffer; @@ -811,7 +815,7 @@ int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle) uint32_t hcint, hctsiz; ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true, - 2000, false); + 2000, false); if (ret) return ret; @@ -1210,6 +1214,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) mdelay(1000); + printf("USB DWC2\n"); + return 0; } @@ -1317,13 +1323,119 @@ static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) return 0; } +static int dwc2_setup_phy(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + int ret; + + ret = generic_phy_get_by_index(dev, 0, &priv->phy); + if (ret) { + if (ret != -ENOENT) { + dev_err(dev, "failed to get usb phy\n"); + return ret; + } + return 0; + } + + ret = generic_phy_init(&priv->phy); + if (ret) { + dev_err(dev, "failed to init usb phy\n"); + return ret; + } + + ret = generic_phy_power_on(&priv->phy); + if (ret) { + dev_err(dev, "failed to power on usb phy\n"); + return generic_phy_exit(&priv->phy); + } + + return 0; +} + +static int dwc2_shutdown_phy(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + int ret; + + if (!generic_phy_valid(&priv->phy)) + return 0; + + ret = generic_phy_power_off(&priv->phy); + if (ret) { + dev_err(dev, "failed to power off usb phy\n"); + return ret; + } + + ret = generic_phy_exit(&priv->phy); + if (ret) { + dev_err(dev, "failed to power off usb phy\n"); + return ret; + } + return 0; +} + +static int dwc2_reset_init(struct udevice *dev) +{ + struct reset_ctl_bulk resets; + int ret; + + ret = reset_get_bulk(dev, &resets); + if (ret == -ENOTSUPP || ret == -ENOENT) + return 0; + else if (ret) + return ret; + + reset_assert_bulk(&resets); + udelay(2); + ret = reset_deassert_bulk(&resets); + if (ret) { + reset_release_bulk(&resets); + return ret; + } + + return 0; +} + +static int dwc2_clk_init(struct udevice *dev) +{ + struct clk_bulk clks; + int ret; + + ret = clk_get_bulk(dev, &clks); + if (ret == -ENOSYS || ret == -ENOENT) + return 0; + if (ret) + return ret; + + ret = clk_enable_bulk(&clks); + if (ret) { + clk_release_bulk(&clks); + return ret; + } + + return 0; +} + static int dwc2_usb_probe(struct udevice *dev) { struct dwc2_priv *priv = dev_get_priv(dev); struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev); + int ret; bus_priv->desc_before_addr = true; + ret = dwc2_reset_init(dev); + if (ret) + return ret; + + ret = dwc2_clk_init(dev); + if (ret) + return ret; + + ret = dwc2_setup_phy(dev); + if (ret) + return ret; + return dwc2_init_common(dev, priv); } @@ -1336,6 +1448,8 @@ static int dwc2_usb_remove(struct udevice *dev) if (ret) return ret; + dwc2_shutdown_phy(dev); + dwc2_uninit_common(priv->regs); reset_release_bulk(&priv->resets); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 25c94f4a9e36..8809552370ee 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -73,6 +73,13 @@ config VIDEO_ANSI Enable ANSI escape sequence decoding for a more fully functional console. +config VIDEO_MIPI_DSI + bool + help + Support MIPI DSI interface for driving a MIPI compatible device. + The MIPI Display Serial Interface (MIPI DSI) defines a high-speed + serial interface between a host processor and a display module. + config CONSOLE_NORMAL bool "Support a simple text console" depends on DM_VIDEO @@ -320,6 +327,22 @@ config VIDEO_LCD_ANX9804 from a parallel LCD interface and translate it on the fy into a DP interface for driving eDP TFT displays. It uses I2C for configuration. +config VIDEO_LCD_ORISETECH_OTM8009A + bool "OTM8009A DSI LCD panel support" + depends on DM_VIDEO + select VIDEO_MIPI_DSI + default n + ---help--- + Support for Orise Tech otm8009a 480p dsi 2dl video mode panel. + +config VIDEO_LCD_RAYDIUM_RM68200 + bool "RM68200 DSI LCD panel support" + depends on DM_VIDEO + select VIDEO_MIPI_DSI + default n + ---help--- + Support for Raydium rm68200 720x1280 dsi 2dl video mode panel. + config VIDEO_LCD_SSD2828 bool "SSD2828 bridge chip" default n @@ -681,6 +704,16 @@ config VIDEO_DW_HDMI rather requires a SoC-specific glue driver to call it), it can not be enabled from the configuration menu. +config VIDEO_DW_MIPI_DSI + bool + select VIDEO_MIPI_DSI + help + Enables the common driver code for the Synopsis Designware + block found in SoCs from various vendors. + As this does not provide any functionality by itself (but + rather requires a SoC-specific glue driver to call it), it + can not be enabled from the configuration menu. + config VIDEO_SIMPLE bool "Simple display driver for preconfigured display" help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 80e1e829033a..c3d39ede41c6 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o +obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o +obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o @@ -61,6 +63,8 @@ obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa.o +obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o +obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_display.o obj-y += bridge/ obj-y += sunxi/ diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c new file mode 100644 index 000000000000..fe1e25a3a97d --- /dev/null +++ b/drivers/video/dw_mipi_dsi.c @@ -0,0 +1,826 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author(s): Philippe Cornu for STMicroelectronics. + * Yannick Fertre for STMicroelectronics. + * + * This generic Synopsys DesignWare MIPI DSI host driver is based on the + * Linux Kernel driver from drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWVER_131 0x31333100 /* IP version 1.31 */ + +#define DSI_VERSION 0x00 +#define VERSION GENMASK(31, 8) + +#define DSI_PWR_UP 0x04 +#define RESET 0 +#define POWERUP BIT(0) + +#define DSI_CLKMGR_CFG 0x08 +#define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) +#define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) + +#define DSI_DPI_VCID 0x0c +#define DPI_VCID(vcid) ((vcid) & 0x3) + +#define DSI_DPI_COLOR_CODING 0x10 +#define LOOSELY18_EN BIT(8) +#define DPI_COLOR_CODING_16BIT_1 0x0 +#define DPI_COLOR_CODING_16BIT_2 0x1 +#define DPI_COLOR_CODING_16BIT_3 0x2 +#define DPI_COLOR_CODING_18BIT_1 0x3 +#define DPI_COLOR_CODING_18BIT_2 0x4 +#define DPI_COLOR_CODING_24BIT 0x5 + +#define DSI_DPI_CFG_POL 0x14 +#define COLORM_ACTIVE_LOW BIT(4) +#define SHUTD_ACTIVE_LOW BIT(3) +#define HSYNC_ACTIVE_LOW BIT(2) +#define VSYNC_ACTIVE_LOW BIT(1) +#define DATAEN_ACTIVE_LOW BIT(0) + +#define DSI_DPI_LP_CMD_TIM 0x18 +#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) +#define INVACT_LPCMD_TIME(p) ((p) & 0xff) + +#define DSI_DBI_VCID 0x1c +#define DSI_DBI_CFG 0x20 +#define DSI_DBI_PARTITIONING_EN 0x24 +#define DSI_DBI_CMDSIZE 0x28 + +#define DSI_PCKHDL_CFG 0x2c +#define CRC_RX_EN BIT(4) +#define ECC_RX_EN BIT(3) +#define BTA_EN BIT(2) +#define EOTP_RX_EN BIT(1) +#define EOTP_TX_EN BIT(0) + +#define DSI_GEN_VCID 0x30 + +#define DSI_MODE_CFG 0x34 +#define ENABLE_VIDEO_MODE 0 +#define ENABLE_CMD_MODE BIT(0) + +#define DSI_VID_MODE_CFG 0x38 +#define ENABLE_LOW_POWER (0x3f << 8) +#define ENABLE_LOW_POWER_MASK (0x3f << 8) +#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 +#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 +#define VID_MODE_TYPE_BURST 0x2 +#define VID_MODE_TYPE_MASK 0x3 + +#define DSI_VID_PKT_SIZE 0x3c +#define VID_PKT_SIZE(p) ((p) & 0x3fff) + +#define DSI_VID_NUM_CHUNKS 0x40 +#define VID_NUM_CHUNKS(c) ((c) & 0x1fff) + +#define DSI_VID_NULL_SIZE 0x44 +#define VID_NULL_SIZE(b) ((b) & 0x1fff) + +#define DSI_VID_HSA_TIME 0x48 +#define DSI_VID_HBP_TIME 0x4c +#define DSI_VID_HLINE_TIME 0x50 +#define DSI_VID_VSA_LINES 0x54 +#define DSI_VID_VBP_LINES 0x58 +#define DSI_VID_VFP_LINES 0x5c +#define DSI_VID_VACTIVE_LINES 0x60 +#define DSI_EDPI_CMD_SIZE 0x64 + +#define DSI_CMD_MODE_CFG 0x68 +#define MAX_RD_PKT_SIZE_LP BIT(24) +#define DCS_LW_TX_LP BIT(19) +#define DCS_SR_0P_TX_LP BIT(18) +#define DCS_SW_1P_TX_LP BIT(17) +#define DCS_SW_0P_TX_LP BIT(16) +#define GEN_LW_TX_LP BIT(14) +#define GEN_SR_2P_TX_LP BIT(13) +#define GEN_SR_1P_TX_LP BIT(12) +#define GEN_SR_0P_TX_LP BIT(11) +#define GEN_SW_2P_TX_LP BIT(10) +#define GEN_SW_1P_TX_LP BIT(9) +#define GEN_SW_0P_TX_LP BIT(8) +#define ACK_RQST_EN BIT(1) +#define TEAR_FX_EN BIT(0) + +#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ + DCS_LW_TX_LP | \ + DCS_SR_0P_TX_LP | \ + DCS_SW_1P_TX_LP | \ + DCS_SW_0P_TX_LP | \ + GEN_LW_TX_LP | \ + GEN_SR_2P_TX_LP | \ + GEN_SR_1P_TX_LP | \ + GEN_SR_0P_TX_LP | \ + GEN_SW_2P_TX_LP | \ + GEN_SW_1P_TX_LP | \ + GEN_SW_0P_TX_LP) + +#define DSI_GEN_HDR 0x6c +#define DSI_GEN_PLD_DATA 0x70 + +#define DSI_CMD_PKT_STATUS 0x74 +#define GEN_RD_CMD_BUSY BIT(6) +#define GEN_PLD_R_FULL BIT(5) +#define GEN_PLD_R_EMPTY BIT(4) +#define GEN_PLD_W_FULL BIT(3) +#define GEN_PLD_W_EMPTY BIT(2) +#define GEN_CMD_FULL BIT(1) +#define GEN_CMD_EMPTY BIT(0) + +#define DSI_TO_CNT_CFG 0x78 +#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) +#define LPRX_TO_CNT(p) ((p) & 0xffff) + +#define DSI_HS_RD_TO_CNT 0x7c +#define DSI_LP_RD_TO_CNT 0x80 +#define DSI_HS_WR_TO_CNT 0x84 +#define DSI_LP_WR_TO_CNT 0x88 +#define DSI_BTA_TO_CNT 0x8c + +#define DSI_LPCLK_CTRL 0x94 +#define AUTO_CLKLANE_CTRL BIT(1) +#define PHY_TXREQUESTCLKHS BIT(0) + +#define DSI_PHY_TMR_LPCLK_CFG 0x98 +#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_TMR_CFG 0x9c +#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) +#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) +#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) +#define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_RSTZ 0xa0 +#define PHY_DISFORCEPLL 0 +#define PHY_ENFORCEPLL BIT(3) +#define PHY_DISABLECLK 0 +#define PHY_ENABLECLK BIT(2) +#define PHY_RSTZ 0 +#define PHY_UNRSTZ BIT(1) +#define PHY_SHUTDOWNZ 0 +#define PHY_UNSHUTDOWNZ BIT(0) + +#define DSI_PHY_IF_CFG 0xa4 +#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) +#define N_LANES(n) (((n) - 1) & 0x3) + +#define DSI_PHY_ULPS_CTRL 0xa8 +#define DSI_PHY_TX_TRIGGERS 0xac + +#define DSI_PHY_STATUS 0xb0 +#define PHY_STOP_STATE_CLK_LANE BIT(2) +#define PHY_LOCK BIT(0) + +#define DSI_PHY_TST_CTRL0 0xb4 +#define PHY_TESTCLK BIT(1) +#define PHY_UNTESTCLK 0 +#define PHY_TESTCLR BIT(0) +#define PHY_UNTESTCLR 0 + +#define DSI_PHY_TST_CTRL1 0xb8 +#define PHY_TESTEN BIT(16) +#define PHY_UNTESTEN 0 +#define PHY_TESTDOUT(n) (((n) & 0xff) << 8) +#define PHY_TESTDIN(n) ((n) & 0xff) + +#define DSI_INT_ST0 0xbc +#define DSI_INT_ST1 0xc0 +#define DSI_INT_MSK0 0xc4 +#define DSI_INT_MSK1 0xc8 + +#define DSI_PHY_TMR_RD_CFG 0xf4 +#define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) + +#define PHY_STATUS_TIMEOUT_US 10000 +#define CMD_PKT_STATUS_TIMEOUT_US 20000 + +#define MSEC_PER_SEC 1000 + +struct dw_mipi_dsi { + struct mipi_dsi_host dsi_host; + struct mipi_dsi_device *device; + void __iomem *base; + unsigned int lane_mbps; /* per lane */ + u32 channel; + u32 lanes; + u32 format; + unsigned long mode_flags; + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; +}; + +static int dsi_mode_vrefresh(struct display_timing *timings) +{ + int refresh = 0; + unsigned int calc_val; + u32 htotal = timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + u32 vtotal = timings->vactive.typ + timings->vfront_porch.typ + + timings->vback_porch.typ + timings->vsync_len.typ; + + if (htotal > 0 && vtotal > 0) { + calc_val = timings->pixelclock.typ; + calc_val /= htotal; + refresh = (calc_val + vtotal / 2) / vtotal; + } + + return refresh; +} + +/* + * The controller should generate 2 frames before + * preparing the peripheral. + */ +static void dw_mipi_dsi_wait_for_two_frames(struct display_timing *timings) +{ + int refresh, two_frames; + + refresh = dsi_mode_vrefresh(timings); + two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; + mdelay(two_frames); +} + +static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host) +{ + return container_of(host, struct dw_mipi_dsi, dsi_host); +} + +static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) +{ + writel(val, dsi->base + reg); +} + +static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) +{ + return readl(dsi->base + reg); +} + +static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi *dsi = host_to_dsi(host); + + if (device->lanes > dsi->max_data_lanes) { + dev_err(device->dev, + "the number of data lanes(%u) is too many\n", + device->lanes); + return -EINVAL; + } + + dsi->lanes = device->lanes; + dsi->channel = device->channel; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; + + return 0; +} + +static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; + u32 val = 0; + + if (msg->flags & MIPI_DSI_MSG_REQ_ACK) + val |= ACK_RQST_EN; + if (lpm) + val |= CMD_MODE_ALL_LP; + + dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS); + dsi_write(dsi, DSI_CMD_MODE_CFG, val); +} + +static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) +{ + int ret; + u32 val, mask; + + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_CMD_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "failed to get available command FIFO\n"); + return ret; + } + + dsi_write(dsi, DSI_GEN_HDR, hdr_val); + + mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, (val & mask) == mask, + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "failed to write command FIFO\n"); + return ret; + } + + return 0; +} + +static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_packet *packet) +{ + const u8 *tx_buf = packet->payload; + int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; + __le32 word; + u32 val; + + while (len) { + if (len < pld_data_bytes) { + word = 0; + memcpy(&word, tx_buf, len); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + len = 0; + } else { + memcpy(&word, tx_buf, pld_data_bytes); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + tx_buf += pld_data_bytes; + len -= pld_data_bytes; + } + + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_W_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, + "failed to get available write payload FIFO\n"); + return ret; + } + } + + word = 0; + memcpy(&word, packet->header, sizeof(packet->header)); + return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); +} + +static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + int i, j, ret, len = msg->rx_len; + u8 *buf = msg->rx_buf; + u32 val; + + /* Wait end of the read operation */ + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_RD_CMD_BUSY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Timeout during read operation\n"); + return ret; + } + + for (i = 0; i < len; i += 4) { + /* Read fifo must not be empty before all bytes are read */ + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_R_EMPTY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Read payload FIFO is empty\n"); + return ret; + } + + val = dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j = 0; j < 4 && j + i < len; j++) + buf[i + j] = val >> (8 * j); + } + + return ret; +} + +static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct dw_mipi_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + int ret, nb_bytes; + + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { + dev_err(dsi->dev, "failed to create packet: %d\n", ret); + return ret; + } + + dw_mipi_message_config(dsi, msg); + + ret = dw_mipi_dsi_write(dsi, &packet); + if (ret) + return ret; + + if (msg->rx_buf && msg->rx_len) { + ret = dw_mipi_dsi_read(dsi, msg); + if (ret) + return ret; + nb_bytes = msg->rx_len; + } else { + nb_bytes = packet.size; + } + + return nb_bytes; +} + +static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { + .attach = dw_mipi_dsi_host_attach, + .transfer = dw_mipi_dsi_host_transfer, +}; + +static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) +{ + u32 val; + + /* + * TODO dw drv improvements + * enabling low power is panel-dependent, we should use the + * panel configuration here... + */ + val = ENABLE_LOW_POWER; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |= VID_MODE_TYPE_BURST; + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; + else + val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; + + dsi_write(dsi, DSI_VID_MODE_CFG, val); +} + +static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, + unsigned long mode_flags) +{ + dsi_write(dsi, DSI_PWR_UP, RESET); + + if (mode_flags & MIPI_DSI_MODE_VIDEO) { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); + dw_mipi_dsi_video_mode_config(dsi); + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); + } else { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); + } + + dsi_write(dsi, DSI_PWR_UP, POWERUP); +} + +static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) +{ + /* + * The maximum permitted escape clock is 20MHz and it is derived from + * lanebyteclk, which is running at "lane_mbps / 8". Thus we want: + * + * (lane_mbps >> 3) / esc_clk_division < 20 + * which is: + * (lane_mbps >> 3) / 20 > esc_clk_division + */ + u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1; + + dsi_write(dsi, DSI_PWR_UP, RESET); + + /* + * TODO dw drv improvements + * timeout clock division should be computed with the + * high speed transmission counter timeout and byte lane... + */ + dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(10) | + TX_ESC_CLK_DIVISION(esc_clk_division)); +} + +static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 val = 0, color = 0; + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB888: + color = DPI_COLOR_CODING_24BIT; + break; + case MIPI_DSI_FMT_RGB666: + color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + color = DPI_COLOR_CODING_18BIT_1; + break; + case MIPI_DSI_FMT_RGB565: + color = DPI_COLOR_CODING_16BIT_1; + break; + } + + if (dsi->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH) + val |= VSYNC_ACTIVE_LOW; + if (dsi->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH) + val |= HSYNC_ACTIVE_LOW; + + dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); + dsi_write(dsi, DSI_DPI_COLOR_CODING, color); + dsi_write(dsi, DSI_DPI_CFG_POL, val); + /* + * TODO dw drv improvements + * largest packet sizes during hfp or during vsa/vpb/vfp + * should be computed according to byte lane, lane number and only + * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS) + */ + dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4) + | INVACT_LPCMD_TIME(4)); +} + +static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) +{ + dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); +} + +static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + /* + * TODO dw drv improvements + * only burst mode is supported here. For non-burst video modes, + * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC & + * DSI_VNPCR.NPSIZE... especially because this driver supports + * non-burst video modes, see dw_mipi_dsi_video_mode_config()... + */ + dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(timings->hactive.typ)); +} + +static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * compute high speed transmission counter timeout according + * to the timeout clock division (TO_CLK_DIVISION) and byte lane... + */ + dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); + /* + * TODO dw drv improvements + * the Bus-Turn-Around Timeout Counter should be computed + * according to byte lane... + */ + dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); +} + +/* Get lane byte clock cycles. */ +static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, + struct display_timing *timings, + u32 hcomponent) +{ + u32 frac, lbcc; + + lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; + + frac = lbcc % (timings->pixelclock.typ / 1000); + lbcc = lbcc / (timings->pixelclock.typ / 1000); + if (frac) + lbcc++; + + return lbcc; +} + +static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 htotal, hsa, hbp, lbcc; + + htotal = timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + + hsa = timings->hback_porch.typ; + hbp = timings->hsync_len.typ; + + /* + * TODO dw drv improvements + * computations below may be improved... + */ + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, htotal); + dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc); + + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hsa); + dsi_write(dsi, DSI_VID_HSA_TIME, lbcc); + + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hbp); + dsi_write(dsi, DSI_VID_HBP_TIME, lbcc); +} + +static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 vactive, vsa, vfp, vbp; + + vactive = timings->vactive.typ; + vsa = timings->vback_porch.typ; + vfp = timings->vfront_porch.typ; + vbp = timings->vsync_len.typ; + + dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive); + dsi_write(dsi, DSI_VID_VSA_LINES, vsa); + dsi_write(dsi, DSI_VID_VFP_LINES, vfp); + dsi_write(dsi, DSI_VID_VBP_LINES, vbp); +} + +static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) +{ + u32 hw_version; + + /* + * TODO dw drv improvements + * data & clock lane timers should be computed according to panel + * blankings and to the automatic clock lane control mode... + * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with + * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) + */ + + hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; + + if (hw_version >= HWVER_131) { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | + PHY_LP2HS_TIME_V131(0x40)); + dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); + } else { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | + PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + } + + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) + | PHY_CLKLP2HS_TIME(0x40)); +} + +static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * stop wait time should be the maximum between host dsi + * and panel stop wait times + */ + dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | + N_LANES(dsi->lanes)); +} + +static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) +{ + /* Clear PHY state */ + dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK + | PHY_RSTZ | PHY_SHUTDOWNZ); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); +} + +static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) +{ + u32 val; + int ret; + + dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | + PHY_UNRSTZ | PHY_UNSHUTDOWNZ); + + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, + val & PHY_LOCK, PHY_STATUS_TIMEOUT_US); + if (ret) + dev_warn(dsi->dev, "failed to wait phy lock state\n"); + + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, + val, val & PHY_STOP_STATE_CLK_LANE, + PHY_STATUS_TIMEOUT_US); + if (ret) + dev_warn(dsi->dev, "failed to wait phy clk lane stop state\n"); +} + +static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) +{ + dsi_read(dsi, DSI_INT_ST0); + dsi_read(dsi, DSI_INT_ST1); + dsi_write(dsi, DSI_INT_MSK0, 0); + dsi_write(dsi, DSI_INT_MSK1, 0); +} + +static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + int ret; + + ret = phy_ops->get_lane_mbps(dsi->device, timings, dsi->lanes, + dsi->format, &dsi->lane_mbps); + if (ret) + dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n"); + + dw_mipi_dsi_init(dsi); + dw_mipi_dsi_dpi_config(dsi, timings); + dw_mipi_dsi_packet_handler_config(dsi); + dw_mipi_dsi_video_mode_config(dsi); + dw_mipi_dsi_video_packet_config(dsi, timings); + dw_mipi_dsi_command_mode_config(dsi); + dw_mipi_dsi_line_timer_config(dsi, timings); + dw_mipi_dsi_vertical_timing_config(dsi, timings); + + dw_mipi_dsi_dphy_init(dsi); + dw_mipi_dsi_dphy_timing_config(dsi); + dw_mipi_dsi_dphy_interface_config(dsi); + + dw_mipi_dsi_clear_err(dsi); + + ret = phy_ops->init(dsi->device); + if (ret) + dev_warn(dsi->dev, "Phy init() failed\n"); + + dw_mipi_dsi_dphy_enable(dsi); + + dw_mipi_dsi_wait_for_two_frames(timings); + + /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ + dw_mipi_dsi_set_mode(dsi, 0); +} + +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device) +{ + struct mipi_dsi_host *host = device->host; + struct dw_mipi_dsi *dsi = host_to_dsi(host); + + /* Switch to video mode for panel-bridge enable & panel enable */ + dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_bridge_enable); + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(device->dev); + struct udevice *panel = platdata->panel; + struct display_timing timings; + struct dw_mipi_dsi *dsi; + struct clk clk; + int ret; + + dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); + + dsi->phy_ops = platdata->phy_ops; + dsi->max_data_lanes = platdata->max_data_lanes; + dsi->device = device; + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; + device->host = &dsi->dsi_host; + + /* TODO Get these settings from panel */ + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + dsi->base = (void *)dev_read_addr(device->dev); + if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) { + dev_err(device->dev, "dsi dt register address error\n"); + return -EINVAL; + } + + ret = panel_get_display_timing(panel, &timings); + if (ret) { + ret = fdtdec_decode_display_timing(gd->fdt_blob, + dev_of_offset(panel), + 0, &timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + if (!dsi->phy_ops->init || !dsi->phy_ops->get_lane_mbps) { + dev_err(device->dev, "Phy not properly configured\n"); + return -ENODEV; + } + + ret = clk_get_by_name(device->dev, "px_clk", &clk); + if (ret) { + dev_err(device->dev, "peripheral clock get error %d\n", ret); + return ret; + } + + /* get the pixel clock set by the clock framework */ + timings.pixelclock.typ = clk_get_rate(&clk); + + dw_mipi_dsi_bridge_set(dsi, &timings); + + return 0; +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_init_bridge); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Philippe Cornu "); +MODULE_AUTHOR("Yannick Fertré "); +MODULE_DESCRIPTION("DW MIPI DSI host controller driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dw-mipi-dsi"); diff --git a/drivers/video/mipi_display.c b/drivers/video/mipi_display.c new file mode 100644 index 000000000000..611ee53bbc25 --- /dev/null +++ b/drivers/video/mipi_display.c @@ -0,0 +1,817 @@ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Andrzej Hajda + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Mipi_display.c contains a set of dsi helpers. + * This file is based on the drm helper file drivers/gpu/drm/drm_mipi_dsi.c + * (kernel linux). + * + */ + +#include +#include +#include +#include +#include + +/** + * DOC: dsi helpers + * + * These functions contain some common logic and helpers to deal with MIPI DSI + * peripherals. + * + * Helpers are provided for a number of standard MIPI DSI command as well as a + * subset of the MIPI DCS command set. + */ + +/** + * mipi_dsi_attach - attach a DSI device to its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_attach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->attach) + return -ENOSYS; + + return ops->attach(dsi->host, dsi); +} +EXPORT_SYMBOL(mipi_dsi_attach); + +/** + * mipi_dsi_detach - detach a DSI device from its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_detach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->detach) + return -ENOSYS; + + return ops->detach(dsi->host, dsi); +} +EXPORT_SYMBOL(mipi_dsi_detach); + +/** + * mipi_dsi_device_transfer - transfer message to a DSI device + * @dsi: DSI peripheral + * @msg: message + */ +static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, + struct mipi_dsi_msg *msg) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->transfer) + return -ENOSYS; + + if (dsi->mode_flags & MIPI_DSI_MODE_LPM) + msg->flags |= MIPI_DSI_MSG_USE_LPM; + + return ops->transfer(dsi->host, msg); +} + +/** + * mipi_dsi_packet_format_is_short - check if a packet is of the short format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a short packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_short(u8 type) +{ + switch (type) { + case MIPI_DSI_V_SYNC_START: + case MIPI_DSI_V_SYNC_END: + case MIPI_DSI_H_SYNC_START: + case MIPI_DSI_H_SYNC_END: + case MIPI_DSI_END_OF_TRANSMISSION: + case MIPI_DSI_COLOR_MODE_OFF: + case MIPI_DSI_COLOR_MODE_ON: + case MIPI_DSI_SHUTDOWN_PERIPHERAL: + case MIPI_DSI_TURN_ON_PERIPHERAL: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_short); + +/** + * mipi_dsi_packet_format_is_long - check if a packet is of the long format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a long packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_long(u8 type) +{ + switch (type) { + case MIPI_DSI_NULL_PACKET: + case MIPI_DSI_BLANKING_PACKET: + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: + case MIPI_DSI_PACKED_PIXEL_STREAM_30: + case MIPI_DSI_PACKED_PIXEL_STREAM_36: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: + case MIPI_DSI_PACKED_PIXEL_STREAM_16: + case MIPI_DSI_PACKED_PIXEL_STREAM_18: + case MIPI_DSI_PIXEL_STREAM_3BYTE_18: + case MIPI_DSI_PACKED_PIXEL_STREAM_24: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_long); + +/** + * mipi_dsi_create_packet - create a packet from a message according to the + * DSI protocol + * @packet: pointer to a DSI packet structure + * @msg: message to translate into a packet + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg) +{ + if (!packet || !msg) + return -EINVAL; + + /* do some minimum sanity checking */ + if (!mipi_dsi_packet_format_is_short(msg->type) && + !mipi_dsi_packet_format_is_long(msg->type)) + return -EINVAL; + + if (msg->channel > 3) + return -EINVAL; + + memset(packet, 0, sizeof(*packet)); + packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); + + /* TODO: compute ECC if hardware support is not available */ + + /* + * Long write packets contain the word count in header bytes 1 and 2. + * The payload follows the header and is word count bytes long. + * + * Short write packets encode up to two parameters in header bytes 1 + * and 2. + */ + if (mipi_dsi_packet_format_is_long(msg->type)) { + packet->header[1] = (msg->tx_len >> 0) & 0xff; + packet->header[2] = (msg->tx_len >> 8) & 0xff; + + packet->payload_length = msg->tx_len; + packet->payload = msg->tx_buf; + } else { + const u8 *tx = msg->tx_buf; + + packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; + packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; + } + + packet->size = sizeof(packet->header) + packet->payload_length; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_create_packet); + +/* + * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the + * the payload in a long packet transmitted from the peripheral back to the + * host processor + * @dsi: DSI peripheral device + * @value: the maximum size of the payload + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value) +{ + u8 tx[2] = { value & 0xff, value >> 8 }; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_len = sizeof(tx), + .tx_buf = tx, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} +EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); + +/** + * mipi_dsi_generic_write() - transmit data using a generic write packet + * @dsi: DSI peripheral device + * @payload: buffer containing the payload + * @size: size of payload buffer + * + * This function will automatically choose the right data type depending on + * the payload length. + * + * Return: The number of bytes transmitted on success or a negative error code + * on failure. + */ +ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = payload, + .tx_len = size + }; + + switch (size) { + case 0: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; + break; + + case 1: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; + break; + + case 2: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; + break; + + default: + msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + break; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_generic_write); + +/** + * mipi_dsi_generic_read() - receive data using a generic read packet + * @dsi: DSI peripheral device + * @params: buffer containing the request parameters + * @num_params: number of request parameters + * @data: buffer in which to return the received data + * @size: size of receive buffer + * + * This function will automatically choose the right data type depending on + * the number of parameters passed in. + * + * Return: The number of bytes successfully read or a negative error code on + * failure. + */ +ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, + size_t num_params, void *data, size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_len = num_params, + .tx_buf = params, + .rx_len = size, + .rx_buf = data + }; + + switch (num_params) { + case 0: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; + break; + + case 1: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; + break; + + case 2: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; + break; + + default: + return -EINVAL; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_generic_read); + +/** + * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload + * @dsi: DSI peripheral device + * @data: buffer containing data to be transmitted + * @len: size of transmission buffer + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = data, + .tx_len = len + }; + + switch (len) { + case 0: + return -EINVAL; + + case 1: + msg.type = MIPI_DSI_DCS_SHORT_WRITE; + break; + + case 2: + msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + + default: + msg.type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer); + +/** + * mipi_dsi_dcs_write() - send DCS write command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer containing the command payload + * @len: command payload length + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len) +{ + ssize_t err; + size_t size; + u8 *tx; + + if (len > 0) { + size = 1 + len; + + tx = kmalloc(size, GFP_KERNEL); + if (!tx) + return -ENOMEM; + + /* concatenate the DCS command byte and the payload */ + tx[0] = cmd; + memcpy(&tx[1], data, len); + } else { + tx = &cmd; + size = 1; + } + + err = mipi_dsi_dcs_write_buffer(dsi, tx, size); + + if (len > 0) + kfree(tx); + + return err; +} +EXPORT_SYMBOL(mipi_dsi_dcs_write); + +/** + * mipi_dsi_dcs_read() - send DCS read request command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer in which to receive data + * @len: size of receive buffer + * + * Return: The number of bytes read or a negative error code on failure. + */ +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_DCS_READ, + .tx_buf = &cmd, + .tx_len = 1, + .rx_buf = data, + .rx_len = len + }; + + return mipi_dsi_device_transfer(dsi, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_read); + +/** + * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any + * given pixel format defined by the MIPI DSI + * specification + * @fmt: MIPI DSI pixel format + * + * Returns: The number of bits per pixel of the given pixel format. + */ +int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB888: + case MIPI_DSI_FMT_RGB666: + return 24; + + case MIPI_DSI_FMT_RGB666_PACKED: + return 18; + + case MIPI_DSI_FMT_RGB565: + return 16; + } + + return -EINVAL; +} +EXPORT_SYMBOL(mipi_dsi_pixel_format_to_bpp); + +/** + * mipi_dsi_dcs_nop() - send DCS nop packet + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_nop); + +/** + * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset); + +/** + * mipi_dsi_dcs_get_power_mode() - query the display module's current power + * mode + * @dsi: DSI peripheral device + * @mode: return location for the current power mode + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode, + sizeof(*mode)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode); + +/** + * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: return location for the pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format, + sizeof(*format)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format); + +/** + * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the + * display module except interface communication + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode); + +/** + * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display + * module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode); + +/** + * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off); + +/** + * mipi_dsi_dcs_set_display_on() - start displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on); + +/** + * mipi_dsi_dcs_set_column_address() - define the column extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first column of frame memory + * @end: last column of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address); + +/** + * mipi_dsi_dcs_set_page_address() - define the page extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first page of frame memory + * @end: last page of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address); + +/** + * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect + * output signal on the TE signal line + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off); + +/** + * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect + * output signal on the TE signal line. + * @dsi: DSI peripheral device + * @mode: the Tearing Effect Output Line mode + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode) +{ + u8 value = mode; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value, + sizeof(value)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on); + +/** + * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, + sizeof(format)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format); + +/** + * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for + * the Tearing Effect output signal of the display module + * @dsi: DSI peripheral device + * @scanline: scanline to use as trigger + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) +{ + u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8, + scanline & 0xff }; + ssize_t err; + + err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline); + +/** + * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the + * display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, + u16 brightness) +{ + u8 payload[2] = { brightness & 0xff, brightness >> 8 }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness); + +/** + * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value + * of the display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, + u16 *brightness) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, + brightness, sizeof(*brightness)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); + +MODULE_AUTHOR("Andrzej Hajda "); +MODULE_AUTHOR("Yannick Fertre "); +MODULE_DESCRIPTION("MIPI DSI Bus"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c new file mode 100644 index 000000000000..ad1d6f0fd4ac --- /dev/null +++ b/drivers/video/orisetech_otm8009a.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Author(s): Yannick Fertre for STMicroelectronics. + * Philippe Cornu for STMicroelectronics. + * + * This otm8009a panel driver is based on the Linux Kernel driver from + * drivers/gpu/drm/panel/panel-orisetech-otm8009a.c. + */ +#include +#include +#include +#include +#include +#include +#include + +#define OTM8009A_BACKLIGHT_DEFAULT 240 +#define OTM8009A_BACKLIGHT_MAX 255 + +/* Manufacturer Command Set */ +#define MCS_ADRSFT 0x0000 /* Address Shift Function */ +#define MCS_PANSET 0xB3A6 /* Panel Type Setting */ +#define MCS_SD_CTRL 0xC0A2 /* Source Driver Timing Setting */ +#define MCS_P_DRV_M 0xC0B4 /* Panel Driving Mode */ +#define MCS_OSC_ADJ 0xC181 /* Oscillator Adjustment for Idle/Normal mode */ +#define MCS_RGB_VID_SET 0xC1A1 /* RGB Video Mode Setting */ +#define MCS_SD_PCH_CTRL 0xC480 /* Source Driver Precharge Control */ +#define MCS_NO_DOC1 0xC48A /* Command not documented */ +#define MCS_PWR_CTRL1 0xC580 /* Power Control Setting 1 */ +#define MCS_PWR_CTRL2 0xC590 /* Power Control Setting 2 for Normal Mode */ +#define MCS_PWR_CTRL4 0xC5B0 /* Power Control Setting 4 for DC Voltage */ +#define MCS_PANCTRLSET1 0xCB80 /* Panel Control Setting 1 */ +#define MCS_PANCTRLSET2 0xCB90 /* Panel Control Setting 2 */ +#define MCS_PANCTRLSET3 0xCBA0 /* Panel Control Setting 3 */ +#define MCS_PANCTRLSET4 0xCBB0 /* Panel Control Setting 4 */ +#define MCS_PANCTRLSET5 0xCBC0 /* Panel Control Setting 5 */ +#define MCS_PANCTRLSET6 0xCBD0 /* Panel Control Setting 6 */ +#define MCS_PANCTRLSET7 0xCBE0 /* Panel Control Setting 7 */ +#define MCS_PANCTRLSET8 0xCBF0 /* Panel Control Setting 8 */ +#define MCS_PANU2D1 0xCC80 /* Panel U2D Setting 1 */ +#define MCS_PANU2D2 0xCC90 /* Panel U2D Setting 2 */ +#define MCS_PANU2D3 0xCCA0 /* Panel U2D Setting 3 */ +#define MCS_PAND2U1 0xCCB0 /* Panel D2U Setting 1 */ +#define MCS_PAND2U2 0xCCC0 /* Panel D2U Setting 2 */ +#define MCS_PAND2U3 0xCCD0 /* Panel D2U Setting 3 */ +#define MCS_GOAVST 0xCE80 /* GOA VST Setting */ +#define MCS_GOACLKA1 0xCEA0 /* GOA CLKA1 Setting */ +#define MCS_GOACLKA3 0xCEB0 /* GOA CLKA3 Setting */ +#define MCS_GOAECLK 0xCFC0 /* GOA ECLK Setting */ +#define MCS_NO_DOC2 0xCFD0 /* Command not documented */ +#define MCS_GVDDSET 0xD800 /* GVDD/NGVDD */ +#define MCS_VCOMDC 0xD900 /* VCOM Voltage Setting */ +#define MCS_GMCT2_2P 0xE100 /* Gamma Correction 2.2+ Setting */ +#define MCS_GMCT2_2N 0xE200 /* Gamma Correction 2.2- Setting */ +#define MCS_NO_DOC3 0xF5B6 /* Command not documented */ +#define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ +#define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ + +struct otm8009a_panel_priv { + struct udevice *reg; + struct gpio_desc reset; +}; + +static const struct display_timing default_timing = { + .pixelclock = {.min = 32729000, .typ = 32729000, .max = 32729000,}, + .hactive = {.min = 480, .typ = 480, .max = 480,}, + .hfront_porch = {.min = 120, .typ = 120, .max = 120,}, + .hback_porch = {.min = 120, .typ = 120, .max = 120,}, + .hsync_len = {.min = 63, .typ = 63, .max = 63,}, + .vactive = {.min = 800, .typ = 800, .max = 800,}, + .vfront_porch = {.min = 12, .typ = 12, .max = 12,}, + .vback_porch = {.min = 12, .typ = 12, .max = 12,}, + .vsync_len = {.min = 12, .typ = 12, .max = 12,}, +}; + +static void otm8009a_dcs_write_buf(struct udevice *dev, const void *data, + size_t len) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + + if (mipi_dsi_dcs_write_buffer(device, data, len) < 0) + dev_err(dev, "mipi dsi dcs write buffer failed\n"); +} + +#define dcs_write_seq(dev, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + otm8009a_dcs_write_buf(dev, d, ARRAY_SIZE(d)); \ +}) + +#define dcs_write_cmd_at(dev, cmd, seq...) \ +({ \ + static const u16 c = cmd; \ + struct udevice *device = dev; \ + dcs_write_seq(device, MCS_ADRSFT, (c) & 0xFF); \ + dcs_write_seq(device, (c) >> 8, seq); \ +}) + +static int otm8009a_init_sequence(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + int ret; + + /* Enter CMD2 */ + dcs_write_cmd_at(dev, MCS_CMD2_ENA1, 0x80, 0x09, 0x01); + + /* Enter Orise Command2 */ + dcs_write_cmd_at(dev, MCS_CMD2_ENA2, 0x80, 0x09); + + dcs_write_cmd_at(dev, MCS_SD_PCH_CTRL, 0x30); + mdelay(10); + + dcs_write_cmd_at(dev, MCS_NO_DOC1, 0x40); + mdelay(10); + + dcs_write_cmd_at(dev, MCS_PWR_CTRL4 + 1, 0xA9); + dcs_write_cmd_at(dev, MCS_PWR_CTRL2 + 1, 0x34); + dcs_write_cmd_at(dev, MCS_P_DRV_M, 0x50); + dcs_write_cmd_at(dev, MCS_VCOMDC, 0x4E); + dcs_write_cmd_at(dev, MCS_OSC_ADJ, 0x66); /* 65Hz */ + dcs_write_cmd_at(dev, MCS_PWR_CTRL2 + 2, 0x01); + dcs_write_cmd_at(dev, MCS_PWR_CTRL2 + 5, 0x34); + dcs_write_cmd_at(dev, MCS_PWR_CTRL2 + 4, 0x33); + dcs_write_cmd_at(dev, MCS_GVDDSET, 0x79, 0x79); + dcs_write_cmd_at(dev, MCS_SD_CTRL + 1, 0x1B); + dcs_write_cmd_at(dev, MCS_PWR_CTRL1 + 2, 0x83); + dcs_write_cmd_at(dev, MCS_SD_PCH_CTRL + 1, 0x83); + dcs_write_cmd_at(dev, MCS_RGB_VID_SET, 0x0E); + dcs_write_cmd_at(dev, MCS_PANSET, 0x00, 0x01); + + dcs_write_cmd_at(dev, MCS_GOAVST, 0x85, 0x01, 0x00, 0x84, 0x01, 0x00); + dcs_write_cmd_at(dev, MCS_GOACLKA1, 0x18, 0x04, 0x03, 0x39, 0x00, 0x00, + 0x00, 0x18, 0x03, 0x03, 0x3A, 0x00, 0x00, 0x00); + dcs_write_cmd_at(dev, MCS_GOACLKA3, 0x18, 0x02, 0x03, 0x3B, 0x00, 0x00, + 0x00, 0x18, 0x01, 0x03, 0x3C, 0x00, 0x00, 0x00); + dcs_write_cmd_at(dev, MCS_GOAECLK, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00); + + dcs_write_cmd_at(dev, MCS_NO_DOC2, 0x00); + + dcs_write_cmd_at(dev, MCS_PANCTRLSET1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET5, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET6, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, + 4, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + dcs_write_cmd_at(dev, MCS_PANCTRLSET8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + + dcs_write_cmd_at(dev, MCS_PANU2D1, 0x00, 0x26, 0x09, 0x0B, 0x01, 0x25, + 0x00, 0x00, 0x00, 0x00); + dcs_write_cmd_at(dev, MCS_PANU2D2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0A, 0x0C, 0x02); + dcs_write_cmd_at(dev, MCS_PANU2D3, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_cmd_at(dev, MCS_PAND2U1, 0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26, + 0x00, 0x00, 0x00, 0x00); + dcs_write_cmd_at(dev, MCS_PAND2U2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0B, 0x09, 0x01); + dcs_write_cmd_at(dev, MCS_PAND2U3, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + + dcs_write_cmd_at(dev, MCS_PWR_CTRL1 + 1, 0x66); + + dcs_write_cmd_at(dev, MCS_NO_DOC3, 0x06); + + dcs_write_cmd_at(dev, MCS_GMCT2_2P, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, + 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A, + 0x01); + dcs_write_cmd_at(dev, MCS_GMCT2_2N, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, + 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A, + 0x01); + + /* Exit CMD2 */ + dcs_write_cmd_at(dev, MCS_CMD2_ENA1, 0xFF, 0xFF, 0xFF); + + ret = mipi_dsi_dcs_nop(device); + if (ret) + return ret; + + ret = mipi_dsi_dcs_exit_sleep_mode(device); + if (ret) + return ret; + + /* Wait for sleep out exit */ + mdelay(120); + + /* Default portrait 480x800 rgb24 */ + dcs_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + + ret = mipi_dsi_dcs_set_column_address(device, 0, 479); + if (ret) + return ret; + + ret = mipi_dsi_dcs_set_page_address(device, 0, 799); + if (ret) + return ret; + + /* See otm8009a driver documentation for pixel format descriptions */ + ret = mipi_dsi_dcs_set_pixel_format(device, MIPI_DCS_PIXEL_FMT_24BIT | + MIPI_DCS_PIXEL_FMT_24BIT << 4); + if (ret) + return ret; + + /* Disable CABC feature */ + dcs_write_seq(dev, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + + return 0; +} + +static int otm8009a_panel_enable_backlight(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + int ret; + + device->lanes = 2; + device->format = MIPI_DSI_FMT_RGB888; + device->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_attach(device); + if (ret < 0) + return ret; + + ret = otm8009a_init_sequence(dev); + if (ret) + return ret; + + /* + * Power on the backlight with the requested brightness + * Note We can not use mipi_dsi_dcs_set_display_brightness() + * as otm8009a driver support only 8-bit brightness (1 param). + */ + dcs_write_seq(dev, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + OTM8009A_BACKLIGHT_DEFAULT); + + /* Update Brightness Control & Backlight */ + dcs_write_seq(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); + + ret = mipi_dsi_dcs_set_display_on(device); + if (ret) + return ret; + + ret = mipi_dsi_dcs_nop(device); + if (ret) + return ret; + + /* Send Command GRAM memory write (no parameters) */ + dcs_write_seq(dev, MIPI_DCS_WRITE_MEMORY_START); + + /* need to wait a few time before set the DSI bridge in video mode */ + mdelay(10); + + return 0; +} + +static int otm8009a_panel_get_display_timing(struct udevice *dev, + struct display_timing *timings) +{ + memcpy(timings, &default_timing, sizeof(*timings)); + return 0; +} + +static int otm8009a_panel_ofdata_to_platdata(struct udevice *dev) +{ + struct otm8009a_panel_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "power-supply", + &priv->reg); + if (ret && ret != -ENOENT) { + dev_err(dev, "Warning: cannot get power supply\n"); + return ret; + } + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset, + GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "warning: cannot get reset GPIO\n"); + if (ret != -ENOENT) + return ret; + } + + return 0; +} + +static int otm8009a_panel_probe(struct udevice *dev) +{ + struct otm8009a_panel_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { + dev_err(dev, "enable regulator '%s'\n", priv->reg->name); + ret = regulator_set_enable(priv->reg, true); + if (ret) + return ret; + } + + /* reset panel */ + dm_gpio_set_value(&priv->reset, true); + mdelay(1); + dm_gpio_set_value(&priv->reset, false); + mdelay(10); + + return 0; +} + +static const struct panel_ops otm8009a_panel_ops = { + .enable_backlight = otm8009a_panel_enable_backlight, + .get_display_timing = otm8009a_panel_get_display_timing, +}; + +static const struct udevice_id otm8009a_panel_ids[] = { + { .compatible = "orisetech,otm8009a" }, + { } +}; + +U_BOOT_DRIVER(otm8009a_panel) = { + .name = "otm8009a_panel", + .id = UCLASS_PANEL, + .of_match = otm8009a_panel_ids, + .ops = &otm8009a_panel_ops, + .ofdata_to_platdata = otm8009a_panel_ofdata_to_platdata, + .probe = otm8009a_panel_probe, + .platdata_auto_alloc_size = sizeof(struct mipi_dsi_panel_plat), + .priv_auto_alloc_size = sizeof(struct otm8009a_panel_priv), +}; diff --git a/drivers/video/raydium-rm68200.c b/drivers/video/raydium-rm68200.c new file mode 100644 index 000000000000..3347f12eeafa --- /dev/null +++ b/drivers/video/raydium-rm68200.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Author(s): Yannick Fertre for STMicroelectronics. + * Philippe Cornu for STMicroelectronics. + * + * This rm68200 panel driver is based on the Linux Kernel driver from + * drivers/gpu/drm/panel/panel-raydium-rm68200.c. + */ +#include +#include +#include +#include +#include +#include +#include + +/*** Manufacturer Command Set ***/ +#define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ +#define MCS_CMD1_UCS 0x00 /* User Command Set (UCS = CMD1) */ +#define MCS_CMD2_P0 0x01 /* Manufacture Command Set Page0 (CMD2 P0) */ +#define MCS_CMD2_P1 0x02 /* Manufacture Command Set Page1 (CMD2 P1) */ +#define MCS_CMD2_P2 0x03 /* Manufacture Command Set Page2 (CMD2 P2) */ +#define MCS_CMD2_P3 0x04 /* Manufacture Command Set Page3 (CMD2 P3) */ + +/* CMD2 P0 commands (Display Options and Power) */ +#define MCS_STBCTR 0x12 /* TE1 Output Setting Zig-Zag Connection */ +#define MCS_SGOPCTR 0x16 /* Source Bias Current */ +#define MCS_SDCTR 0x1A /* Source Output Delay Time */ +#define MCS_INVCTR 0x1B /* Inversion Type */ +#define MCS_EXT_PWR_IC 0x24 /* External PWR IC Control */ +#define MCS_SETAVDD 0x27 /* PFM Control for AVDD Output */ +#define MCS_SETAVEE 0x29 /* PFM Control for AVEE Output */ +#define MCS_BT2CTR 0x2B /* DDVDL Charge Pump Control */ +#define MCS_BT3CTR 0x2F /* VGH Charge Pump Control */ +#define MCS_BT4CTR 0x34 /* VGL Charge Pump Control */ +#define MCS_VCMCTR 0x46 /* VCOM Output Level Control */ +#define MCS_SETVGN 0x52 /* VG M/S N Control */ +#define MCS_SETVGP 0x54 /* VG M/S P Control */ +#define MCS_SW_CTRL 0x5F /* Interface Control for PFM and MIPI */ + +/* CMD2 P2 commands (GOA Timing Control) - no description in datasheet */ +#define GOA_VSTV1 0x00 +#define GOA_VSTV2 0x07 +#define GOA_VCLK1 0x0E +#define GOA_VCLK2 0x17 +#define GOA_VCLK_OPT1 0x20 +#define GOA_BICLK1 0x2A +#define GOA_BICLK2 0x37 +#define GOA_BICLK3 0x44 +#define GOA_BICLK4 0x4F +#define GOA_BICLK_OPT1 0x5B +#define GOA_BICLK_OPT2 0x60 +#define MCS_GOA_GPO1 0x6D +#define MCS_GOA_GPO2 0x71 +#define MCS_GOA_EQ 0x74 +#define MCS_GOA_CLK_GALLON 0x7C +#define MCS_GOA_FS_SEL0 0x7E +#define MCS_GOA_FS_SEL1 0x87 +#define MCS_GOA_FS_SEL2 0x91 +#define MCS_GOA_FS_SEL3 0x9B +#define MCS_GOA_BS_SEL0 0xAC +#define MCS_GOA_BS_SEL1 0xB5 +#define MCS_GOA_BS_SEL2 0xBF +#define MCS_GOA_BS_SEL3 0xC9 +#define MCS_GOA_BS_SEL4 0xD3 + +/* CMD2 P3 commands (Gamma) */ +#define MCS_GAMMA_VP 0x60 /* Gamma VP1~VP16 */ +#define MCS_GAMMA_VN 0x70 /* Gamma VN1~VN16 */ + +struct rm68200_panel_priv { + struct udevice *reg; + struct udevice *backlight; + struct gpio_desc reset; +}; + +static const struct display_timing default_timing = { + .pixelclock = {.min = 52582000, .typ = 52582000, .max = 52582000,}, + .hactive = {.min = 720, .typ = 720, .max = 720,}, + .hfront_porch = {.min = 38, .typ = 38, .max = 38,}, + .hback_porch = {.min = 8, .typ = 8, .max = 8,}, + .hsync_len = {.min = 38, .typ = 38, .max = 38,}, + .vactive = {.min = 1280, .typ = 1280, .max = 1280,}, + .vfront_porch = {.min = 12, .typ = 12, .max = 12,}, + .vback_porch = {.min = 4, .typ = 4, .max = 4,}, + .vsync_len = {.min = 12, .typ = 12, .max = 12,}, +}; + +static void rm68200_dcs_write_buf(struct udevice *dev, const void *data, + size_t len) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + int err; + + err = mipi_dsi_dcs_write_buffer(device, data, len); + if (err < 0) + dev_err(dev, "MIPI DSI DCS write buffer failed: %d\n", err); +} + +static void rm68200_dcs_write_cmd(struct udevice *dev, u8 cmd, u8 value) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + int err; + + err = mipi_dsi_dcs_write(device, cmd, &value, 1); + if (err < 0) + dev_err(dev, "MIPI DSI DCS write failed: %d\n", err); +} + +#define dcs_write_seq(ctx, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + \ + rm68200_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \ +}) + +/* + * This panel is not able to auto-increment all cmd addresses so for some of + * them, we need to send them one by one... + */ +#define dcs_write_cmd_seq(ctx, cmd, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + unsigned int i; \ + \ + for (i = 0; i < ARRAY_SIZE(d) ; i++) \ + rm68200_dcs_write_cmd(ctx, cmd + i, d[i]); \ +}) + +static void rm68200_init_sequence(struct udevice *dev) +{ + /* Enter CMD2 with page 0 */ + dcs_write_seq(dev, MCS_CMD_MODE_SW, MCS_CMD2_P0); + dcs_write_cmd_seq(dev, MCS_EXT_PWR_IC, 0xC0, 0x53, 0x00); + dcs_write_seq(dev, MCS_BT2CTR, 0xE5); + dcs_write_seq(dev, MCS_SETAVDD, 0x0A); + dcs_write_seq(dev, MCS_SETAVEE, 0x0A); + dcs_write_seq(dev, MCS_SGOPCTR, 0x52); + dcs_write_seq(dev, MCS_BT3CTR, 0x53); + dcs_write_seq(dev, MCS_BT4CTR, 0x5A); + dcs_write_seq(dev, MCS_INVCTR, 0x00); + dcs_write_seq(dev, MCS_STBCTR, 0x0A); + dcs_write_seq(dev, MCS_SDCTR, 0x06); + dcs_write_seq(dev, MCS_VCMCTR, 0x56); + dcs_write_seq(dev, MCS_SETVGN, 0xA0, 0x00); + dcs_write_seq(dev, MCS_SETVGP, 0xA0, 0x00); + dcs_write_seq(dev, MCS_SW_CTRL, 0x11); /* 2 data lanes, see doc */ + + dcs_write_seq(dev, MCS_CMD_MODE_SW, MCS_CMD2_P2); + dcs_write_seq(dev, GOA_VSTV1, 0x05); + dcs_write_seq(dev, 0x02, 0x0B); + dcs_write_seq(dev, 0x03, 0x0F); + dcs_write_seq(dev, 0x04, 0x7D, 0x00, 0x50); + dcs_write_cmd_seq(dev, GOA_VSTV2, 0x05, 0x16, 0x0D, 0x11, 0x7D, 0x00, + 0x50); + dcs_write_cmd_seq(dev, GOA_VCLK1, 0x07, 0x08, 0x01, 0x02, 0x00, 0x7D, + 0x00, 0x85, 0x08); + dcs_write_cmd_seq(dev, GOA_VCLK2, 0x03, 0x04, 0x05, 0x06, 0x00, 0x7D, + 0x00, 0x85, 0x08); + dcs_write_seq(dev, GOA_VCLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + dcs_write_cmd_seq(dev, GOA_BICLK1, 0x07, 0x08); + dcs_write_seq(dev, 0x2D, 0x01); + dcs_write_seq(dev, 0x2F, 0x02, 0x00, 0x40, 0x05, 0x08, 0x54, 0x7D, + 0x00); + dcs_write_cmd_seq(dev, GOA_BICLK2, 0x03, 0x04, 0x05, 0x06, 0x00); + dcs_write_seq(dev, 0x3D, 0x40); + dcs_write_seq(dev, 0x3F, 0x05, 0x08, 0x54, 0x7D, 0x00); + dcs_write_seq(dev, GOA_BICLK3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(dev, GOA_BICLK4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00); + dcs_write_seq(dev, 0x58, 0x00, 0x00, 0x00); + dcs_write_seq(dev, GOA_BICLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(dev, GOA_BICLK_OPT2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(dev, MCS_GOA_GPO1, 0x00, 0x00, 0x00, 0x00); + dcs_write_seq(dev, MCS_GOA_GPO2, 0x00, 0x20, 0x00); + dcs_write_seq(dev, MCS_GOA_EQ, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00); + dcs_write_seq(dev, MCS_GOA_CLK_GALLON, 0x00, 0x00); + dcs_write_cmd_seq(dev, MCS_GOA_FS_SEL0, 0xBF, 0x02, 0x06, 0x14, 0x10, + 0x16, 0x12, 0x08, 0x3F); + dcs_write_cmd_seq(dev, MCS_GOA_FS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0C, + 0x0A, 0x0E, 0x3F, 0x3F, 0x00); + dcs_write_cmd_seq(dev, MCS_GOA_FS_SEL2, 0x04, 0x3F, 0x3F, 0x3F, 0x3F, + 0x05, 0x01, 0x3F, 0x3F, 0x0F); + dcs_write_cmd_seq(dev, MCS_GOA_FS_SEL3, 0x0B, 0x0D, 0x3F, 0x3F, 0x3F, + 0x3F); + dcs_write_cmd_seq(dev, 0xA2, 0x3F, 0x09, 0x13, 0x17, 0x11, 0x15); + dcs_write_cmd_seq(dev, 0xA9, 0x07, 0x03, 0x3F); + dcs_write_cmd_seq(dev, MCS_GOA_BS_SEL0, 0x3F, 0x05, 0x01, 0x17, 0x13, + 0x15, 0x11, 0x0F, 0x3F); + dcs_write_cmd_seq(dev, MCS_GOA_BS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0B, + 0x0D, 0x09, 0x3F, 0x3F, 0x07); + dcs_write_cmd_seq(dev, MCS_GOA_BS_SEL2, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, + 0x02, 0x06, 0x3F, 0x3F, 0x08); + dcs_write_cmd_seq(dev, MCS_GOA_BS_SEL3, 0x0C, 0x0A, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x0E, 0x10, 0x14); + dcs_write_cmd_seq(dev, MCS_GOA_BS_SEL4, 0x12, 0x16, 0x00, 0x04, 0x3F); + dcs_write_seq(dev, 0xDC, 0x02); + dcs_write_seq(dev, 0xDE, 0x12); + + dcs_write_seq(dev, MCS_CMD_MODE_SW, 0x0E); /* No documentation */ + dcs_write_seq(dev, 0x01, 0x75); + + dcs_write_seq(dev, MCS_CMD_MODE_SW, MCS_CMD2_P3); + dcs_write_cmd_seq(dev, MCS_GAMMA_VP, 0x00, 0x0C, 0x12, 0x0E, 0x06, + 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, + 0x12, 0x0C, 0x00); + dcs_write_cmd_seq(dev, MCS_GAMMA_VN, 0x00, 0x0C, 0x12, 0x0E, 0x06, + 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, + 0x12, 0x0C, 0x00); + + /* Exit CMD2 */ + dcs_write_seq(dev, MCS_CMD_MODE_SW, MCS_CMD1_UCS); +} + +static int rm68200_panel_enable_backlight(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + struct rm68200_panel_priv *priv = dev_get_priv(dev); + int ret; + + device->lanes = 2; + device->format = MIPI_DSI_FMT_RGB888; + device->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_attach(device); + if (ret < 0) + return ret; + + rm68200_init_sequence(dev); + + ret = mipi_dsi_dcs_exit_sleep_mode(device); + if (ret) + return ret; + + mdelay(125); + + ret = mipi_dsi_dcs_set_display_on(device); + if (ret) + return ret; + + mdelay(20); + + ret = backlight_enable(priv->backlight); + if (ret) + return ret; + + return 0; +} + +static int rm68200_panel_get_display_timing(struct udevice *dev, + struct display_timing *timings) +{ + memcpy(timings, &default_timing, sizeof(*timings)); + return 0; +} + +static int rm68200_panel_ofdata_to_platdata(struct udevice *dev) +{ + struct rm68200_panel_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "power-supply", + &priv->reg); + if (ret && ret != -ENOENT) { + dev_err(dev, "Warning: cannot get power supply\n"); + return ret; + } + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset, + GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "Warning: cannot get reset GPIO\n"); + if (ret != -ENOENT) + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + dev_err(dev, "Cannot get backlight: ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int rm68200_panel_probe(struct udevice *dev) +{ + struct rm68200_panel_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { + ret = regulator_set_enable(priv->reg, true); + if (ret) + return ret; + } + + /* reset panel */ + dm_gpio_set_value(&priv->reset, true); + mdelay(1); + dm_gpio_set_value(&priv->reset, false); + mdelay(10); + + return 0; +} + +static const struct panel_ops rm68200_panel_ops = { + .enable_backlight = rm68200_panel_enable_backlight, + .get_display_timing = rm68200_panel_get_display_timing, +}; + +static const struct udevice_id rm68200_panel_ids[] = { + { .compatible = "raydium,rm68200" }, + { } +}; + +U_BOOT_DRIVER(rm68200_panel) = { + .name = "rm68200_panel", + .id = UCLASS_PANEL, + .of_match = rm68200_panel_ids, + .ops = &rm68200_panel_ops, + .ofdata_to_platdata = rm68200_panel_ofdata_to_platdata, + .probe = rm68200_panel_probe, + .platdata_auto_alloc_size = sizeof(struct mipi_dsi_panel_plat), + .priv_auto_alloc_size = sizeof(struct rm68200_panel_priv), +}; diff --git a/drivers/video/stm32/Kconfig b/drivers/video/stm32/Kconfig index 78b1facad4b2..95d51bb4e969 100644 --- a/drivers/video/stm32/Kconfig +++ b/drivers/video/stm32/Kconfig @@ -13,6 +13,15 @@ menuconfig VIDEO_STM32 DSI. This option enables these supports which can be used on devices which have RGB TFT or DSI display connected. +config VIDEO_STM32_DSI + bool "Enable STM32 DSI video support" + depends on VIDEO_STM32 + select VIDEO_BRIDGE + select VIDEO_DW_MIPI_DSI + help + This option enables support DSI internal bridge which can be used on + devices which have DSI devices connected. + config VIDEO_STM32_MAX_XRES int "Maximum horizontal resolution (for memory allocation purposes)" depends on VIDEO_STM32 diff --git a/drivers/video/stm32/Makefile b/drivers/video/stm32/Makefile index 7297e5f57a6a..f8b42d1a4d12 100644 --- a/drivers/video/stm32/Makefile +++ b/drivers/video/stm32/Makefile @@ -6,3 +6,4 @@ # Yannick Fertre obj-${CONFIG_VIDEO_STM32} = stm32_ltdc.o +obj-${CONFIG_VIDEO_STM32_DSI} += stm32_dsi.o diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c new file mode 100644 index 000000000000..09266fe9a949 --- /dev/null +++ b/drivers/video/stm32/stm32_dsi.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Author(s): Philippe Cornu for STMicroelectronics. + * Yannick Fertre for STMicroelectronics. + * + * This MIPI DSI controller driver is based on the Linux Kernel driver from + * drivers/gpu/drm/stm/dw_mipi_dsi-stm.c. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWVER_130 0x31333000 /* IP version 1.30 */ +#define HWVER_131 0x31333100 /* IP version 1.31 */ + +/* DSI digital registers & bit definitions */ +#define DSI_VERSION 0x00 +#define VERSION GENMASK(31, 8) + +/* + * DSI wrapper registers & bit definitions + * Note: registers are named as in the Reference Manual + */ +#define DSI_WCFGR 0x0400 /* Wrapper ConFiGuration Reg */ +#define WCFGR_DSIM BIT(0) /* DSI Mode */ +#define WCFGR_COLMUX GENMASK(3, 1) /* COLor MUltipleXing */ + +#define DSI_WCR 0x0404 /* Wrapper Control Reg */ +#define WCR_DSIEN BIT(3) /* DSI ENable */ + +#define DSI_WISR 0x040C /* Wrapper Interrupt and Status Reg */ +#define WISR_PLLLS BIT(8) /* PLL Lock Status */ +#define WISR_RRS BIT(12) /* Regulator Ready Status */ + +#define DSI_WPCR0 0x0418 /* Wrapper Phy Conf Reg 0 */ +#define WPCR0_UIX4 GENMASK(5, 0) /* Unit Interval X 4 */ +#define WPCR0_TDDL BIT(16) /* Turn Disable Data Lanes */ + +#define DSI_WRPCR 0x0430 /* Wrapper Regulator & Pll Ctrl Reg */ +#define WRPCR_PLLEN BIT(0) /* PLL ENable */ +#define WRPCR_NDIV GENMASK(8, 2) /* pll loop DIVision Factor */ +#define WRPCR_IDF GENMASK(14, 11) /* pll Input Division Factor */ +#define WRPCR_ODF GENMASK(17, 16) /* pll Output Division Factor */ +#define WRPCR_REGEN BIT(24) /* REGulator ENable */ +#define WRPCR_BGREN BIT(28) /* BandGap Reference ENable */ +#define IDF_MIN 1 +#define IDF_MAX 7 +#define NDIV_MIN 10 +#define NDIV_MAX 125 +#define ODF_MIN 1 +#define ODF_MAX 8 + +/* dsi color format coding according to the datasheet */ +enum dsi_color { + DSI_RGB565_CONF1, + DSI_RGB565_CONF2, + DSI_RGB565_CONF3, + DSI_RGB666_CONF1, + DSI_RGB666_CONF2, + DSI_RGB888, +}; + +#define LANE_MIN_KBPS 31250 +#define LANE_MAX_KBPS 500000 + +/* Timeout for regulator on/off, pll lock/unlock & fifo empty */ +#define TIMEOUT_US 200000 + +struct stm32_dsi_priv { + struct mipi_dsi_device device; + void __iomem *base; + struct udevice *panel; + u32 pllref_clk; + u32 hw_version; + int lane_min_kbps; + int lane_max_kbps; + struct udevice *vdd_reg; +}; + +static inline void dsi_write(struct stm32_dsi_priv *dsi, u32 reg, u32 val) +{ + writel(val, dsi->base + reg); +} + +static inline u32 dsi_read(struct stm32_dsi_priv *dsi, u32 reg) +{ + return readl(dsi->base + reg); +} + +static inline void dsi_set(struct stm32_dsi_priv *dsi, u32 reg, u32 mask) +{ + dsi_write(dsi, reg, dsi_read(dsi, reg) | mask); +} + +static inline void dsi_clear(struct stm32_dsi_priv *dsi, u32 reg, u32 mask) +{ + dsi_write(dsi, reg, dsi_read(dsi, reg) & ~mask); +} + +static inline void dsi_update_bits(struct stm32_dsi_priv *dsi, u32 reg, + u32 mask, u32 val) +{ + dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val); +} + +static enum dsi_color dsi_color_from_mipi(u32 fmt) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB888: + return DSI_RGB888; + case MIPI_DSI_FMT_RGB666: + return DSI_RGB666_CONF2; + case MIPI_DSI_FMT_RGB666_PACKED: + return DSI_RGB666_CONF1; + case MIPI_DSI_FMT_RGB565: + return DSI_RGB565_CONF1; + default: + pr_err("MIPI color invalid, so we use rgb888\n"); + } + return DSI_RGB888; +} + +static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf) +{ + int divisor = idf * odf; + + /* prevent from division by 0 */ + if (!divisor) + return 0; + + return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor); +} + +static int dsi_pll_get_params(struct stm32_dsi_priv *dsi, + int clkin_khz, int clkout_khz, + int *idf, int *ndiv, int *odf) +{ + int i, o, n, n_min, n_max; + int fvco_min, fvco_max, delta, best_delta; /* all in khz */ + + /* Early checks preventing division by 0 & odd results */ + if (clkin_khz <= 0 || clkout_khz <= 0) + return -EINVAL; + + fvco_min = dsi->lane_min_kbps * 2 * ODF_MAX; + fvco_max = dsi->lane_max_kbps * 2 * ODF_MIN; + + best_delta = 1000000; /* big started value (1000000khz) */ + + for (i = IDF_MIN; i <= IDF_MAX; i++) { + /* Compute ndiv range according to Fvco */ + n_min = ((fvco_min * i) / (2 * clkin_khz)) + 1; + n_max = (fvco_max * i) / (2 * clkin_khz); + + /* No need to continue idf loop if we reach ndiv max */ + if (n_min >= NDIV_MAX) + break; + + /* Clamp ndiv to valid values */ + if (n_min < NDIV_MIN) + n_min = NDIV_MIN; + if (n_max > NDIV_MAX) + n_max = NDIV_MAX; + + for (o = ODF_MIN; o <= ODF_MAX; o *= 2) { + n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz); + /* Check ndiv according to vco range */ + if (n < n_min || n > n_max) + continue; + /* Check if new delta is better & saves parameters */ + delta = dsi_pll_get_clkout_khz(clkin_khz, i, n, o) - + clkout_khz; + if (delta < 0) + delta = -delta; + if (delta < best_delta) { + *idf = i; + *ndiv = n; + *odf = o; + best_delta = delta; + } + /* fast return in case of "perfect result" */ + if (!delta) + return 0; + } + } + + return 0; +} + +static int dsi_phy_init(void *priv_data) +{ + struct mipi_dsi_device *device = priv_data; + struct udevice *dev = device->dev; + struct stm32_dsi_priv *dsi = dev_get_priv(dev); + u32 val; + int ret; + + /* Enable the regulator */ + dsi_set(dsi, DSI_WRPCR, WRPCR_REGEN | WRPCR_BGREN); + ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_RRS, + TIMEOUT_US); + if (ret) { + dev_err(dev, "!TIMEOUT! waiting REGU\n"); + return ret; + } + + /* Enable the DSI PLL & wait for its lock */ + dsi_set(dsi, DSI_WRPCR, WRPCR_PLLEN); + ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_PLLLS, + TIMEOUT_US); + if (ret) { + dev_err(dev, "!TIMEOUT! waiting PLL\n"); + return ret; + } + + /* Enable the DSI wrapper */ + dsi_set(dsi, DSI_WCR, WCR_DSIEN); + + return 0; +} + +static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, + u32 lanes, u32 format, unsigned int *lane_mbps) +{ + struct mipi_dsi_device *device = priv_data; + struct udevice *dev = device->dev; + struct stm32_dsi_priv *dsi = dev_get_priv(dev); + int idf, ndiv, odf, pll_in_khz, pll_out_khz; + int ret, bpp; + u32 val; + + /* Update lane capabilities according to hw version */ + dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; + dsi->lane_min_kbps = LANE_MIN_KBPS; + dsi->lane_max_kbps = LANE_MAX_KBPS; + if (dsi->hw_version == HWVER_131) { + dsi->lane_min_kbps *= 2; + dsi->lane_max_kbps *= 2; + } + + pll_in_khz = dsi->pllref_clk / 1000; + + /* Compute requested pll out */ + bpp = mipi_dsi_pixel_format_to_bpp(format); + pll_out_khz = (timings->pixelclock.typ / 1000) * bpp / lanes; + /* Add 20% to pll out to be higher than pixel bw (burst mode only) */ + pll_out_khz = (pll_out_khz * 12) / 10; + if (pll_out_khz > dsi->lane_max_kbps) { + pll_out_khz = dsi->lane_max_kbps; + dev_warn(dev, "Warning max phy mbps is used\n"); + } + if (pll_out_khz < dsi->lane_min_kbps) { + pll_out_khz = dsi->lane_min_kbps; + dev_warn(dev, "Warning min phy mbps is used\n"); + } + + /* Compute best pll parameters */ + idf = 0; + ndiv = 0; + odf = 0; + ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, + &idf, &ndiv, &odf); + if (ret) { + dev_err(dev, "Warning dsi_pll_get_params(): bad params\n"); + return ret; + } + + /* Get the adjusted pll out value */ + pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); + + /* Set the PLL division factors */ + dsi_update_bits(dsi, DSI_WRPCR, WRPCR_NDIV | WRPCR_IDF | WRPCR_ODF, + (ndiv << 2) | (idf << 11) | ((ffs(odf) - 1) << 16)); + + /* Compute uix4 & set the bit period in high-speed mode */ + val = 4000000 / pll_out_khz; + dsi_update_bits(dsi, DSI_WPCR0, WPCR0_UIX4, val); + + /* Select video mode by resetting DSIM bit */ + dsi_clear(dsi, DSI_WCFGR, WCFGR_DSIM); + + /* Select the color coding */ + dsi_update_bits(dsi, DSI_WCFGR, WCFGR_COLMUX, + dsi_color_from_mipi(format) << 1); + + *lane_mbps = pll_out_khz / 1000; + + debug("pll_in %ukHz pll_out %ukHz lane_mbps %uMHz\n", + pll_in_khz, pll_out_khz, *lane_mbps); + + return 0; +} + +static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { + .init = dsi_phy_init, + .get_lane_mbps = dsi_get_lane_mbps, +}; + +static int stm32_dsi_attach(struct udevice *dev) +{ + struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(dev); + struct mipi_dsi_device *device = &priv->device; + int ret; + + platdata->max_data_lanes = 2; + platdata->phy_ops = &dw_mipi_dsi_stm_phy_ops; + + ret = uclass_first_device(UCLASS_PANEL, &platdata->panel); + if (ret) { + dev_err(dev, "panel device error %d\n", ret); + return ret; + } + + ret = dw_mipi_dsi_init_bridge(device); + if (ret) { + dev_err(dev, "failed to initialize mipi dsi host\n"); + return ret; + } + + return 0; +} + +static int stm32_dsi_set_backlight(struct udevice *dev, int percent) +{ + struct dw_mipi_dsi_plat_data *dplat = dev_get_platdata(dev); + struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct mipi_dsi_device *device = &priv->device; + struct udevice *panel = dplat->panel; + struct mipi_dsi_panel_plat *mplat; + int ret; + + mplat = dev_get_platdata(panel); + mplat->device = device; + + ret = panel_enable_backlight(panel); + if (ret) { + dev_err(dev, "panel %s enable backlight error %d\n", + panel->name, ret); + return ret; + } + + dw_mipi_dsi_bridge_enable(device); + + return 0; +} + +static int stm32_dsi_probe(struct udevice *dev) +{ + struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct mipi_dsi_device *device = &priv->device; + struct reset_ctl rst; + struct clk clk; + int ret; + + device->dev = dev; + + priv->base = (void *)dev_read_addr(dev); + if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) { + dev_err(dev, "dsi dt register address error\n"); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "phy-dsi-supply", + &priv->vdd_reg); + if (ret && ret != -ENOENT) { + dev_err(dev, "Warning: cannot get phy dsi supply\n"); + return -ENODEV; + } + + ret = regulator_set_enable(priv->vdd_reg, true); + if (ret) + return -ENODEV; + } + + ret = clk_get_by_name(device->dev, "pclk", &clk); + if (ret) { + dev_err(dev, "peripheral clock get error %d\n", ret); + regulator_set_enable(priv->vdd_reg, false); + return -ENODEV; + } + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "peripheral clock enable error %d\n", ret); + regulator_set_enable(priv->vdd_reg, false); + return -ENODEV; + } + + ret = clk_get_by_name(dev, "ref", &clk); + if (ret) { + dev_err(dev, "pll reference clock get error %d\n", ret); + clk_disable(&clk); + regulator_set_enable(priv->vdd_reg, false); + return ret; + } + + priv->pllref_clk = (unsigned int)clk_get_rate(&clk); + + ret = reset_get_by_index(device->dev, 0, &rst); + if (ret) { + dev_err(dev, "missing dsi hardware reset\n"); + clk_disable(&clk); + regulator_set_enable(priv->vdd_reg, false); + return -ENODEV; + } + + /* Reset */ + reset_deassert(&rst); + + return 0; +} + +struct video_bridge_ops stm32_dsi_ops = { + .attach = stm32_dsi_attach, + .set_backlight = stm32_dsi_set_backlight, +}; + +static const struct udevice_id stm32_dsi_ids[] = { + { .compatible = "st,stm32-dsi"}, + { } +}; + +U_BOOT_DRIVER(stm32_dsi) = { + .name = "stm32-display-dsi", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = stm32_dsi_ids, + .bind = dm_scan_fdt_dev, + .probe = stm32_dsi_probe, + .ops = &stm32_dsi_ops, + .priv_auto_alloc_size = sizeof(struct stm32_dsi_priv), + .platdata_auto_alloc_size = sizeof(struct dw_mipi_dsi_plat_data), +}; diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index dc6c88902f66..8c996b8100d7 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -4,22 +4,20 @@ * Author(s): Philippe Cornu for STMicroelectronics. * Yannick Fertre for STMicroelectronics. */ - #include #include +#include #include #include #include #include +#include #include #include #include -DECLARE_GLOBAL_DATA_PTR; - struct stm32_ltdc_priv { void __iomem *regs; - struct display_timing timing; enum video_log2_bpp l2bpp; u32 bg_col_argb; u32 crop_x, crop_y, crop_w, crop_h; @@ -174,8 +172,8 @@ static u32 stm32_ltdc_get_pixel_format(enum video_log2_bpp l2bpp) case VIDEO_BPP2: case VIDEO_BPP4: default: - debug("%s: warning %dbpp not supported yet, %dbpp instead\n", - __func__, VNBITS(l2bpp), VNBITS(VIDEO_BPP16)); + pr_warn("%s: warning %dbpp not supported yet, %dbpp instead\n", + __func__, VNBITS(l2bpp), VNBITS(VIDEO_BPP16)); pf = PF_RGB565; break; } @@ -209,23 +207,23 @@ static void stm32_ltdc_enable(struct stm32_ltdc_priv *priv) setbits_le32(priv->regs + LTDC_GCR, GCR_LTDCEN); } -static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv) +static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv, + struct display_timing *timings) { void __iomem *regs = priv->regs; - struct display_timing *timing = &priv->timing; u32 hsync, vsync, acc_hbp, acc_vbp, acc_act_w, acc_act_h; u32 total_w, total_h; u32 val; /* Convert video timings to ltdc timings */ - hsync = timing->hsync_len.typ - 1; - vsync = timing->vsync_len.typ - 1; - acc_hbp = hsync + timing->hback_porch.typ; - acc_vbp = vsync + timing->vback_porch.typ; - acc_act_w = acc_hbp + timing->hactive.typ; - acc_act_h = acc_vbp + timing->vactive.typ; - total_w = acc_act_w + timing->hfront_porch.typ; - total_h = acc_act_h + timing->vfront_porch.typ; + hsync = timings->hsync_len.typ - 1; + vsync = timings->vsync_len.typ - 1; + acc_hbp = hsync + timings->hback_porch.typ; + acc_vbp = vsync + timings->vback_porch.typ; + acc_act_w = acc_hbp + timings->hactive.typ; + acc_act_h = acc_vbp + timings->vactive.typ; + total_w = acc_act_w + timings->hfront_porch.typ; + total_h = acc_act_h + timings->vfront_porch.typ; /* Synchronization sizes */ val = (hsync << 16) | vsync; @@ -247,14 +245,14 @@ static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv) /* Signal polarities */ val = 0; - debug("%s: timing->flags 0x%08x\n", __func__, timing->flags); - if (timing->flags & DISPLAY_FLAGS_HSYNC_HIGH) + debug("%s: timing->flags 0x%08x\n", __func__, timings->flags); + if (timings->flags & DISPLAY_FLAGS_HSYNC_HIGH) val |= GCR_HSPOL; - if (timing->flags & DISPLAY_FLAGS_VSYNC_HIGH) + if (timings->flags & DISPLAY_FLAGS_VSYNC_HIGH) val |= GCR_VSPOL; - if (timing->flags & DISPLAY_FLAGS_DE_HIGH) + if (timings->flags & DISPLAY_FLAGS_DE_HIGH) val |= GCR_DEPOL; - if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) + if (timings->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) val |= GCR_PCPOL; clrsetbits_le32(regs + LTDC_GCR, GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); @@ -330,96 +328,129 @@ static int stm32_ltdc_probe(struct udevice *dev) struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_ltdc_priv *priv = dev_get_priv(dev); - struct udevice *panel; +#ifdef CONFIG_VIDEO_BRIDGE + struct udevice *bridge = NULL; +#endif + struct udevice *panel = NULL; + struct display_timing timings; struct clk pclk; struct reset_ctl rst; - int rate, ret; + int ret; priv->regs = (void *)dev_read_addr(dev); if ((fdt_addr_t)priv->regs == FDT_ADDR_T_NONE) { - debug("%s: ltdc dt register address error\n", __func__); + dev_err(dev, "ltdc dt register address error\n"); return -EINVAL; } ret = clk_get_by_index(dev, 0, &pclk); if (ret) { - debug("%s: peripheral clock get error %d\n", __func__, ret); + dev_err(dev, "peripheral clock get error %d\n", ret); return ret; } ret = clk_enable(&pclk); if (ret) { - debug("%s: peripheral clock enable error %d\n", - __func__, ret); + dev_err(dev, "peripheral clock enable error %d\n", ret); return ret; } - ret = reset_get_by_index(dev, 0, &rst); + ret = uclass_first_device_err(UCLASS_PANEL, &panel); if (ret) { - debug("%s: missing ltdc hardware reset\n", __func__); - return -ENODEV; + if (ret != -ENODEV) + dev_err(dev, "panel device error %d\n", ret); + return ret; } - /* Reset */ - reset_deassert(&rst); - - ret = uclass_first_device(UCLASS_PANEL, &panel); + ret = panel_get_display_timing(panel, &timings); if (ret) { - debug("%s: panel device error %d\n", __func__, ret); - return ret; + ret = fdtdec_decode_display_timing(gd->fdt_blob, + dev_of_offset(panel), + 0, &timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } } - ret = panel_enable_backlight(panel); + ret = clk_set_rate(&pclk, timings.pixelclock.typ); + if (ret) + dev_warn(dev, "fail to set pixel clock %d hz\n", + timings.pixelclock.typ); + + debug("%s: Set pixel clock req %d hz get %ld hz\n", __func__, + timings.pixelclock.typ, clk_get_rate(&pclk)); + + ret = reset_get_by_index(dev, 0, &rst); if (ret) { - debug("%s: panel %s enable backlight error %d\n", - __func__, panel->name, ret); + dev_err(dev, "missing ltdc hardware reset\n"); return ret; } - ret = fdtdec_decode_display_timing(gd->fdt_blob, - dev_of_offset(dev), 0, - &priv->timing); - if (ret) { - debug("%s: decode display timing error %d\n", - __func__, ret); - return -EINVAL; - } + /* Reset */ + reset_deassert(&rst); - rate = clk_set_rate(&pclk, priv->timing.pixelclock.typ); - if (rate < 0) { - debug("%s: fail to set pixel clock %d hz %d hz\n", - __func__, priv->timing.pixelclock.typ, rate); - return rate; +#ifdef CONFIG_VIDEO_BRIDGE + ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); + if (ret) + debug("No video bridge, or no backlight on bridge\n"); + + if (bridge) { + ret = video_bridge_attach(bridge); + if (ret) { + dev_err(dev, "fail to attach bridge\n"); + return ret; + } } - - debug("%s: Set pixel clock req %d hz get %d hz\n", __func__, - priv->timing.pixelclock.typ, rate); - +#endif /* TODO Below parameters are hard-coded for the moment... */ priv->l2bpp = VIDEO_BPP16; priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */ priv->crop_x = 0; priv->crop_y = 0; - priv->crop_w = priv->timing.hactive.typ; - priv->crop_h = priv->timing.vactive.typ; + priv->crop_w = timings.hactive.typ; + priv->crop_h = timings.vactive.typ; priv->alpha = 0xFF; debug("%s: %dx%d %dbpp frame buffer at 0x%lx\n", __func__, - priv->timing.hactive.typ, priv->timing.vactive.typ, + timings.hactive.typ, timings.vactive.typ, VNBITS(priv->l2bpp), uc_plat->base); debug("%s: crop %d,%d %dx%d bg 0x%08x alpha %d\n", __func__, priv->crop_x, priv->crop_y, priv->crop_w, priv->crop_h, priv->bg_col_argb, priv->alpha); /* Configure & start LTDC */ - stm32_ltdc_set_mode(priv); + stm32_ltdc_set_mode(priv, &timings); stm32_ltdc_set_layer1(priv, uc_plat->base); stm32_ltdc_enable(priv); - uc_priv->xsize = priv->timing.hactive.typ; - uc_priv->ysize = priv->timing.vactive.typ; + uc_priv->xsize = timings.hactive.typ; + uc_priv->ysize = timings.vactive.typ; uc_priv->bpix = priv->l2bpp; +#ifdef CONFIG_VIDEO_BRIDGE + if (bridge) { + ret = video_bridge_set_backlight(bridge, 80); + if (ret) { + dev_err(dev, "fail to set backlight\n"); + return ret; + } + } else { + ret = panel_enable_backlight(panel); + if (ret) { + dev_err(dev, "panel %s enable backlight error %d\n", + panel->name, ret); + return ret; + } + } +#else + ret = panel_enable_backlight(panel); + if (ret) { + dev_err(dev, "panel %s enable backlight error %d\n", + panel->name, ret); + return ret; + } +#endif video_set_flush_dcache(dev, true); return 0; diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 44dfa71b6f4b..5fe49a53032a 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -300,3 +300,17 @@ UCLASS_DRIVER(video) = { .per_device_auto_alloc_size = sizeof(struct video_priv), .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata), }; + +static int do_video_clear(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + + if (uclass_first_device_err(UCLASS_VIDEO, &dev)) + return CMD_RET_FAILURE; + video_clear(dev); + + return 0; +} + +U_BOOT_CMD(cls, 1, 1, do_video_clear, "clear screen", ""); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 02f4e1e32fc7..705fc7d746b6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -103,6 +103,21 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. +config STM32MP_WATCHDOG + bool "Enable IWDG watchdog driver for STM32 MP's family" + depends on ARCH_STM32MP + select HW_WATCHDOG + help + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. + +config STM32MP_WATCHDOG_TIMEOUT_SECS + int "IWDG watchdog timeout" + depends on STM32MP_WATCHDOG + default 32 + help + Configure the timeout for IWDG (default: 32s). + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 08406caa0f9c..25491cf70c42 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o +obj-$(CONFIG_STM32MP_WATCHDOG) += stm32mp_wdt.o \ No newline at end of file diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c new file mode 100644 index 000000000000..696be1b6d6a5 --- /dev/null +++ b/drivers/watchdog/stm32mp_wdt.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* IWDG registers */ +#define IWDG_KR 0x00 /* Key register */ +#define IWDG_PR 0x04 /* Prescaler Register */ +#define IWDG_RLR 0x08 /* ReLoad Register */ +#define IWDG_SR 0x0C /* Status Register */ + +/* IWDG_KR register bit mask */ +#define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */ +#define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */ +#define KR_KEY_EWA 0x5555 /* Write access enable */ + +/* IWDG_PR register bit values */ +#define PR_256 0x06 /* Prescaler set to 256 */ + +/* IWDG_RLR register values */ +#define RLR_MAX 0xFFF /* Max value supported by reload register */ + +static fdt_addr_t stm32mp_wdt_base + __attribute__((section(".data"))) = FDT_ADDR_T_NONE; + +void hw_watchdog_reset(void) +{ + if (stm32mp_wdt_base != FDT_ADDR_T_NONE) + writel(KR_KEY_RELOAD, stm32mp_wdt_base + IWDG_KR); +} + +void hw_watchdog_init(void) +{ + struct regmap *map; + + map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_IWDG); + if (!IS_ERR(map)) + stm32mp_wdt_base = map->ranges[0].start; + else + printf("%s: iwdg init error", __func__); +} + +static int stm32mp_wdt_probe(struct udevice *dev) +{ + struct regmap *map = syscon_get_regmap(dev); + struct clk clk; + int ret, reload; + u32 time_start; + ulong regmap_base = map->ranges[0].start; + + debug("IWDG init\n"); + + /* Enable clock */ + ret = clk_get_by_name(dev, "pclk", &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + /* Get LSI clock */ + ret = clk_get_by_name(dev, "lsi", &clk); + if (ret) + return ret; + + /* Prescaler fixed to 256 */ + reload = CONFIG_STM32MP_WATCHDOG_TIMEOUT_SECS * + clk_get_rate(&clk) / 256; + if (reload > RLR_MAX + 1) + /* Force to max watchdog counter reload value */ + reload = RLR_MAX + 1; + else if (!reload) + /* Force to min watchdog counter reload value */ + reload = clk_get_rate(&clk) / 256; + + /* Enable watchdog */ + writel(KR_KEY_ENABLE, regmap_base + IWDG_KR); + + /* Set prescaler & reload registers */ + writel(KR_KEY_EWA, regmap_base + IWDG_KR); + writel(PR_256, regmap_base + IWDG_PR); + writel(reload - 1, regmap_base + IWDG_RLR); + + /* Wait for the registers to be updated */ + time_start = get_timer(0); + while (readl(regmap_base + IWDG_SR)) { + if (get_timer(time_start) > CONFIG_SYS_HZ) { + pr_err("Updating IWDG registers timeout"); + return -ETIMEDOUT; + } + } + + debug("IWDG init done\n"); + + return 0; +} + +static const struct udevice_id stm32mp_wdt_match[] = { + { .compatible = "st,stm32mp1-iwdg", + .data = STM32MP_SYSCON_IWDG }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(stm32mp_wdt) = { + .name = "stm32mp-wdt", + .id = UCLASS_SYSCON, + .of_match = stm32mp_wdt_match, + .probe = stm32mp_wdt_probe, +}; diff --git a/include/adc.h b/include/adc.h index d04c9c49262d..5841dfb54b9f 100644 --- a/include/adc.h +++ b/include/adc.h @@ -218,6 +218,17 @@ int adc_channels_data(struct udevice *dev, unsigned int channel_mask, */ int adc_data_mask(struct udevice *dev, unsigned int *data_mask); +/** + * adc_channel_mask() - get channel mask for given ADC device + * + * This can be used if adc uclass platform data is filled. + * + * @dev: ADC device to check + * @channel_mask: pointer to the returned channel bitmask + * @return: 0 if OK, -ve on error + */ +int adc_channel_mask(struct udevice *dev, unsigned int *channel_mask); + /** * adc_channel_single_shot() - get output data of conversion for the ADC * device's channel. This function searches for the device with the given name, @@ -284,4 +295,14 @@ int adc_vss_value(struct udevice *dev, int *uV); */ int adc_stop(struct udevice *dev); +/** + * adc_raw_to_uV() - converts raw value to microvolts for given ADC device. + * + * @dev: ADC device used from conversion + * @raw: raw value to convert + * @uV: converted value in microvolts + * @return: 0 on success or -ve on error + */ +int adc_raw_to_uV(struct udevice *dev, unsigned int raw, int *uV); + #endif diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 701298cab88b..b4beaa757f64 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -10,17 +10,17 @@ #include #include -#define CONFIG_PREBOOT - /* * Number of clock ticks in 1 sec */ #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 @@ -33,6 +33,8 @@ #define CONFIG_SYS_SDRAM_BASE STM32_DDR_BASE #define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE +#define CONFIG_DISABLE_CONSOLE + /* * Console I/O buffer size */ @@ -53,6 +55,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 */ @@ -69,36 +74,118 @@ 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 -#if !defined(CONFIG_SPL) || !defined(CONFIG_SPL_BUILD) +/*****************************************************************************/ +#ifdef CONFIG_DISTRO_DEFAULTS +/*****************************************************************************/ + +/* NAND support */ +#define CONFIG_SYS_NAND_ONFI_DETECTION +#define CONFIG_SYS_MAX_NAND_DEVICE 1 + +/* SPI nand */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 + +/* SPI FLASH support */ +#if defined(CONFIG_SPL_BUILD) +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x80000 +#endif +/* FILE SYSTEM */ + +#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC2) +/* Dynamic MTD partition support */ +#define CONFIG_SYS_MTDPARTS_RUNTIME +#endif + +/* Ethernet need */ +#ifdef CONFIG_DWC_ETH_QOS +#define CONFIG_SYS_NONCACHED_MEMORY (1 * SZ_1M) /* 1M */ +#define CONFIG_SERVERIP 192.168.1.1 +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_SYS_AUTOLOAD "no" +#endif + +#ifdef CONFIG_DM_VIDEO +#define CONFIG_VIDEO_BMP_RLE8 +#define CONFIG_BMP_16BPP +#define CONFIG_BMP_24BPP +#define CONFIG_BMP_32BPP +#endif + +#if !defined(CONFIG_SPL_BUILD) + +/* default order is eMMC (SDMMC 1)/ NAND / SDCARD (SDMMC 0) / SDMMC2 */ #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ + func(UBIFS, ubifs, 0) \ func(MMC, mmc, 0) \ - func(MMC, mmc, 2) + func(MMC, mmc, 2) \ + func(PXE, pxe, na) #include -#define STM32MP_PREBOOT \ +#define CONFIG_PREBOOT \ "echo \"Boot over ${boot_device}${boot_instance}!\"; " \ - "if test \"${boot_device}\" = \"mmc\"; then " \ - "env set boot_targets \"mmc${boot_instance}\"; "\ - "fi;" + "if test ${boot_device} = serial; then " \ + "stm32prog serial ${boot_instance}; " \ + "else if test ${boot_device} = usb; then " \ + "stm32prog usb ${boot_instance}; " \ + "else " \ + "if test ${boot_device} = mmc; then " \ + "env set boot_targets \"mmc${boot_instance}\"; "\ + "else if test ${boot_device} = nand; then " \ + "env set boot_targets \"ubifs0\"; "\ + "fi; fi; fi; fi;" + +#ifdef CONFIG_STM32MP1_OPTEE +#define CONFIG_SYS_MEM_TOP_HIDE SZ_32M +/* with OPTEE: define specific MTD partitions = teeh, teed, teex */ +#define STM32MP_MTDPARTS \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI);\0" + +#else /* CONFIG_STM32MP1_OPTEE */ + +#define STM32MP_MTDPARTS \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),-(nor_user)\0" \ + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" + +#endif /* CONFIG_STM32MP1_OPTEE */ +/* + * 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" \ + "stdin=serial\0" \ + "stdout=serial\0" \ + "stderr=serial\0" \ + "bootdelay=1\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" \ - "preboot=" STM32MP_PREBOOT "\0" \ - BOOTENV + "bootlimit=0\0" \ + "altbootcmd=run bootcmd\0" \ + "usb_pgood_delay=2000\0" \ + STM32MP_MTDPARTS \ + BOOTENV \ + "boot_net_usb_start=true\0" #endif /* ifndef CONFIG_SPL_BUILD */ +#endif /* ifdef CONFIG_DISTRO_DEFAULTS*/ #endif /* __CONFIG_H */ diff --git a/include/dfu.h b/include/dfu.h index fbe978abdc26..36304c7ffc70 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -22,6 +22,7 @@ enum dfu_device_type { DFU_DEV_NAND, DFU_DEV_RAM, DFU_DEV_SF, + DFU_DEV_VIRT, }; enum dfu_layout { @@ -77,6 +78,12 @@ struct sf_internal_data { /* RAW programming */ u64 start; u64 size; + /* for sf/ubi use */ + unsigned int ubi; +}; + +struct virt_internal_data { + int dev_num; }; #define DFU_NAME_SIZE 32 @@ -107,6 +114,7 @@ struct dfu_entity { struct nand_internal_data nand; struct ram_internal_data ram; struct sf_internal_data sf; + struct virt_internal_data virt; } data; int (*get_medium_size)(struct dfu_entity *dfu, u64 *size); @@ -142,6 +150,8 @@ struct dfu_entity { #ifdef CONFIG_SET_DFU_ALT_INFO void set_dfu_alt_info(char *interface, char *devstr); #endif +int dfu_alt_init(int num, struct dfu_entity **dfu); +int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s); int dfu_config_entities(char *s, char *interface, char *devstr); void dfu_free_entities(void); void dfu_show_entities(void); @@ -161,6 +171,9 @@ bool dfu_usb_get_reset(void); int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num); int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num); int dfu_flush(struct dfu_entity *de, void *buf, int size, int blk_seq_num); +void dfu_flush_callback(struct dfu_entity *dfu); +void dfu_transaction_cleanup(struct dfu_entity *dfu); +int dfu_transaction_initiate(struct dfu_entity *dfu, bool read); /* * dfu_defer_flush - pointer to store dfu_entity for deferred flashing. @@ -246,6 +259,22 @@ static inline int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr, } #endif +#ifdef CONFIG_DFU_VIRT +int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, char *s); +int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len); +int dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size); +int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset, + void *buf, long *len); +#else +static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, + char *s) +{ + puts("VIRT support not available!\n"); + return -1; +} +#endif + /** * dfu_tftp_write - Write TFTP data to DFU medium * diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h index 80de3f3fed2b..63a7d55b8880 100644 --- a/include/dm/pinctrl.h +++ b/include/dm/pinctrl.h @@ -6,6 +6,9 @@ #ifndef __PINCTRL_H #define __PINCTRL_H +#define PINNAME_SIZE 10 +#define PINMUX_SIZE 40 + /** * struct pinconf_param - pin config parameters * @@ -66,6 +69,7 @@ struct pinconf_param { * pointing a config node. (necessary for pinctrl_full) * @set_state_simple: do needed pinctrl operations for a peripherl @periph. * (necessary for pinctrl_simple) + * @get_pin_muxing: display the muxing of a given pin. */ struct pinctrl_ops { int (*get_pins_count)(struct udevice *dev); @@ -129,6 +133,24 @@ struct pinctrl_ops { * @return mux value (SoC-specific, e.g. 0 for input, 1 for output) */ int (*get_gpio_mux)(struct udevice *dev, int banknum, int index); + + /** + * get_pin_muxing() - show pin muxing + * + * This allows to display the muxing of a given pin. It's useful for + * debug purpose to know if a pin is configured as GPIO or as an + * alternate function and which one. + * Typically it is used by a PINCTRL driver with knowledge of the SoC + * pinctrl setup. + * + * @dev: Pinctrl device to use + * @selector: Pin selector + * @buf Pin's muxing description + * @size Pin's muxing description length + * return 0 if OK, -ve on error + */ + int (*get_pin_muxing)(struct udevice *dev, unsigned int selector, + char *buf, int size); }; #define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops) @@ -348,4 +370,41 @@ int pinctrl_decode_pin_config(const void *blob, int node); */ int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index); +/** + * pinctrl_get_pin_muxing() - Returns the muxing description + * + * This allows to display the muxing description of the given pin for + * debug purpose + * + * @dev: Pinctrl device to use + * @selector Pin index within pin-controller + * @buf Pin's muxing description + * @size Pin's muxing description length + * @return 0 if OK, -ve on error + */ +int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf, + int size); + +/** + * pinctrl_get_pins_count() - display pin-controller pins number + * + * This allows to know the number of pins owned by a given pin-controller + * + * @dev: Pinctrl device to use + * @return pins number if OK, -ve on error + */ +int pinctrl_get_pins_count(struct udevice *dev); + +/** + * pinctrl_get_pin_name() - Returns the pin's name + * + * This allows to display the pin's name for debug purpose + * + * @dev: Pinctrl device to use + * @selector Pin index within pin-controller + * @buf Pin's name + * @return 0 if OK, -ve on error + */ +int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf, + int size); #endif /* __PINCTRL_H */ diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 269a2c6e7228..6193017432e6 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -40,6 +40,7 @@ enum uclass_id { UCLASS_ETH, /* Ethernet device */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ + UCLASS_HWSPINLOCK, /* Hardware semaphores */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_I2C, /* I2C bus */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ diff --git a/include/dm/uclass.h b/include/dm/uclass.h index eebf2d5614c4..11e6df391b20 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -305,6 +305,18 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp); */ int uclass_next_device(struct udevice **devp); +/** + * uclass_next_device_err() - Get the next device in a uclass + * + * The device returned is probed if necessary, and ready for use + * + * @devp: On entry, pointer to device to lookup. On exit, returns pointer + * to the next device in the uclass if no error occurred, or -ENODEV if + * there is no next device. + * @return 0 if found, -ENODEV if not found, other -ve on error + */ +int uclass_next_device_err(struct udevice **devp); + /** * uclass_first_device_check() - Get the first device in a uclass * @@ -379,4 +391,20 @@ int uclass_resolve_seq(struct udevice *dev); #define uclass_foreach_dev_safe(pos, next, uc) \ list_for_each_entry_safe(pos, next, &uc->dev_head, uclass_node) +/** + * uclass_foreach_dev_probe() - Helper function to iteration through devices + * of given uclass + * + * This creates a for() loop which works through the available devices in + * a uclass in order from start to end. Devices are probed if necessary, + * and ready for use. + * + * @id: Uclass ID + * @dev: struct udevice * to hold the current device. Set to NULL when there + * are no more devices. + */ +#define uclass_foreach_dev_probe(id, dev) \ + for (int _ret = uclass_first_device_err(id, &dev); !_ret && dev; \ + _ret = uclass_next_device_err(&dev)) + #endif diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h index 90ec780bfc68..4cdaf135829c 100644 --- a/include/dt-bindings/clock/stm32mp1-clks.h +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -248,7 +248,4 @@ #define STM32MP1_LAST_CLK 232 -#define LTDC_K LTDC_PX -#define ETHMAC_K ETHCK_K - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h new file mode 100644 index 000000000000..b2d6c83462a6 --- /dev/null +++ b/include/dt-bindings/mfd/st,stpmic1.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Philippe Peurichard , + * Pascal Paillet for STMicroelectronics. + */ + +#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_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_STPMIC1_H__ */ diff --git a/include/dt-bindings/mfd/st,stpmu1.h b/include/dt-bindings/mfd/st,stpmu1.h deleted file mode 100644 index 81982ebe2c25..000000000000 --- 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/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h index b5a2174a6386..e928aea7a6d2 100644 --- a/include/dt-bindings/pinctrl/stm32-pinfunc.h +++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h @@ -32,5 +32,11 @@ #define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode)) +/* package information */ +#define STM32MP157CAA 0x1 +#define STM32MP157CAB 0x2 +#define STM32MP157CAC 0x4 +#define STM32MP157CAD 0x8 + #endif /* _DT_BINDINGS_STM32_PINFUNC_H */ diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h new file mode 100644 index 000000000000..4373c4dea587 --- /dev/null +++ b/include/dt-bindings/rtc/rtc-stm32.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for STM32_RTC bindings. + */ + +#ifndef _DT_BINDINGS_RTC_RTC_STM32_H +#define _DT_BINDINGS_RTC_RTC_STM32_H + +#define RTC_OUT1 0 +#define RTC_OUT2 1 +#define RTC_OUT2_RMP 2 + +#endif diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h new file mode 100644 index 000000000000..d98665327281 --- /dev/null +++ b/include/dt-bindings/soc/stm32-hdp.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Roullier Christophe + * for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32_HDP_H +#define _DT_BINDINGS_STM32_HDP_H + +#define STM32_HDP(port, value) ((value) << ((port) * 4)) + +/* define HDP Pins number*/ +#define HDP0_PWR_PWRWAKE_SYS 0 +#define HDP0_CM4_SLEEPDEEP 1 +#define HDP0_PWR_STDBY_WKUP 2 +#define HDP0_PWR_ENCOMP_VDDCORE 3 +#define HDP0_BSEC_OUT_SEC_NIDEN 4 +#define HDP0_RCC_CM4_SLEEPDEEP 6 +#define HDP0_GPU_DBG7 7 +#define HDP0_DDRCTRL_LP_REQ 8 +#define HDP0_PWR_DDR_RET_ENABLE_N 9 +#define HDP0_GPOVAL_0 15 + +#define HDP1_PWR_PWRWAKE_MCU 0 +#define HDP1_CM4_HALTED 1 +#define HDP1_CA7_NAXIERRIRQ 2 +#define HDP1_PWR_OKIN_MR 3 +#define HDP1_BSEC_OUT_SEC_DBGEN 4 +#define HDP1_EXTI_SYS_WAKEUP 5 +#define HDP1_RCC_PWRDS_MPU 6 +#define HDP1_GPU_DBG6 7 +#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8 +#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9 +#define HDP1_GPOVAL_1 15 + +#define HDP2_PWR_PWRWAKE_MPU 0 +#define HDP2_CM4_RXEV 1 +#define HDP2_CA7_NPMUIRQ1 2 +#define HDP2_CA7_NFIQOUT1 3 +#define HDP2_BSEC_IN_RSTCORE_N 4 +#define HDP2_EXTI_C2_WAKEUP 5 +#define HDP2_RCC_PWRDS_MCU 6 +#define HDP2_GPU_DBG5 7 +#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8 +#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9 +#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10 +#define HDP2_GPOVAL_2 15 + +#define HDP3_PWR_SEL_VTH_VDD_CORE 0 +#define HDP3_CM4_TXEV 1 +#define HDP3_CA7_NPMUIRQ0 2 +#define HDP3_CA7_NFIQOUT0 3 +#define HDP3_BSEC_OUT_SEC_DFTLOCK 4 +#define HDP3_EXTI_C1_WAKEUP 5 +#define HDP3_RCC_PWRDS_SYS 6 +#define HDP3_GPU_DBG4 7 +#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8 +#define HDP3_DDRCTRL_CACTIVE_1 9 +#define HDP3_GPOVAL_3 15 + +#define HDP4_PWR_PDDS 0 +#define HDP4_CM4_SLEEPING 1 +#define HDP4_CA7_NRESET1 2 +#define HDP4_CA7_NIRQOUT1 3 +#define HDP4_BSEC_OUT_SEC_DFTEN 4 +#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5 +#define HDP4_ETH_OUT_PMT_INTR_O 6 +#define HDP4_GPU_DBG3 7 +#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8 +#define HDP4_DDRCTRL_CACTIVE_0 9 +#define HDP4_GPOVAL_4 15 + +#define HDP5_CA7_STANDBYWFIL2 0 +#define HDP5_PWR_VTH_VDDCORE_ACK 1 +#define HDP5_CA7_NRESET0 2 +#define HDP5_CA7_NIRQOUT0 3 +#define HDP5_BSEC_IN_PWROK 4 +#define HDP5_BSEC_OUT_SEC_DEVICEEN 5 +#define HDP5_ETH_OUT_LPI_INTR_O 6 +#define HDP5_GPU_DBG2 7 +#define HDP5_DDRCTRL_CACTIVE_DDRC 8 +#define HDP5_DDRCTRL_WR_CREDIT_CNT 9 +#define HDP5_GPOVAL_5 15 + +#define HDP6_CA7_STANDBYWFI1 0 +#define HDP6_CA7_STANDBYWFE1 1 +#define HDP6_CA7_EVENT0 2 +#define HDP6_CA7_DBGACK1 3 +#define HDP6_BSEC_OUT_SEC_SPNIDEN 5 +#define HDP6_ETH_OUT_MAC_SPEED_O1 6 +#define HDP6_GPU_DBG1 7 +#define HDP6_DDRCTRL_CSYSACK_DDRC 8 +#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9 +#define HDP6_GPOVAL_6 15 + +#define HDP7_CA7_STANDBYWFI0 0 +#define HDP7_CA7_STANDBYWFE0 1 +#define HDP7_CA7_DBGACK0 3 +#define HDP7_BSEC_OUT_FUSE_OK 4 +#define HDP7_BSEC_OUT_SEC_SPIDEN 5 +#define HDP7_ETH_OUT_MAC_SPEED_O0 6 +#define HDP7_GPU_DBG0 7 +#define HDP7_DDRCTRL_CSYSREQ_DDRC 8 +#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9 +#define HDP7_GPOVAL_7 15 + +#endif /* _DT_BINDINGS_STM32_HDP_H */ diff --git a/include/dw_mipi_dsi.h b/include/dw_mipi_dsi.h new file mode 100644 index 000000000000..ebf471326b04 --- /dev/null +++ b/include/dw_mipi_dsi.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2017-2018, STMicroelectronics - All Rights Reserved + * + * Authors: Yannick Fertre + * Philippe Cornu + * + * This generic Synopsys DesignWare MIPI DSI host include is based on + * the Linux Kernel include from include/drm/bridge/dw_mipi_dsi.h. + */ + +#ifndef __DW_MIPI_DSI__ +#define __DW_MIPI_DSI__ + +#include + +struct dw_mipi_dsi_phy_ops { + int (*init)(void *priv_data); + int (*get_lane_mbps)(void *priv_data, struct display_timing *timings, + u32 lanes, u32 format, unsigned int *lane_mbps); +}; + +struct dw_mipi_dsi_plat_data { + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; + struct udevice *panel; +}; + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device); +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device); + +#endif /* __DW_MIPI_DSI__ */ diff --git a/include/g_dnl.h b/include/g_dnl.h index 6d461c73d3d0..836ee602c8da 100644 --- a/include/g_dnl.h +++ b/include/g_dnl.h @@ -38,6 +38,7 @@ int g_dnl_board_usb_cable_connected(void); int g_dnl_register(const char *s); void g_dnl_unregister(void); void g_dnl_set_serialnumber(char *); +void g_dnl_set_product(const char *s); bool g_dnl_detach(void); void g_dnl_trigger_detach(void); diff --git a/include/hwspinlock.h b/include/hwspinlock.h new file mode 100644 index 000000000000..99389c13c24e --- /dev/null +++ b/include/hwspinlock.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef _HWSPINLOCK_H_ +#define _HWSPINLOCK_H_ + +/** + * Implement a hwspinlock uclass. + * Hardware spinlocks are used to perform hardware protection of + * critical sections and synchronisation between multiprocessors. + */ + +struct udevice; + +/** + * struct hwspinlock - A handle to (allowing control of) a single hardware + * spinlock. + * + * @dev: The device which implements the hardware spinlock. + * @id: The hardware spinlock ID within the provider. + */ +struct hwspinlock { + struct udevice *dev; + unsigned long id; +}; + +#if CONFIG_IS_ENABLED(DM_HWSPINLOCK) + +/** + * hwspinlock_get_by_index - Get a hardware spinlock by integer index + * + * This looks up and request a hardware spinlock. The index is relative to the + * client device; each device is assumed to have n hardware spinlock associated + * with it somehow, and this function finds and requests one of them. + * + * @dev: The client device. + * @index: The index of the hardware spinlock to request, within the + * client's list of hardware spinlock. + * @hws: A pointer to a hardware spinlock struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int hwspinlock_get_by_index(struct udevice *dev, + int index, struct hwspinlock *hws); + +/** + * Lock the hardware spinlock + * + * @hws: A hardware spinlock struct that previously requested by + * hwspinlock_get_by_index + * @timeout: Timeout value in msecs + * @return: 0 if OK, -ETIMEDOUT if timeout, -ve on other errors + */ +int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout); + +/** + * Unlock the hardware spinlock + * + * @hws: A hardware spinlock struct that previously requested by + * hwspinlock_get_by_index + * @return: 0 if OK, -ve on error + */ +int hwspinlock_unlock(struct hwspinlock *hws); + +#else + +static inline int hwspinlock_get_by_index(struct udevice *dev, + int index, + struct hwspinlock *hws) +{ + return -ENOSYS; +} + +static inline int hwspinlock_lock_timeout(struct hwspinlock *hws, + int timeout) +{ + return -ENOSYS; +} + +static inline int hwspinlock_unlock(struct hwspinlock *hws) +{ + return -ENOSYS; +} + +#endif /* CONFIG_DM_HWSPINLOCK */ + +struct ofnode_phandle_args; + +/** + * struct hwspinlock_ops - Driver model hwspinlock operations + * + * The uclass interface is implemented by all hwspinlock devices which use + * driver model. + */ +struct hwspinlock_ops { + /** + * of_xlate - Translate a client's device-tree (OF) hardware specifier. + * + * The hardware core calls this function as the first step in + * implementing a client's hwspinlock_get_by_*() call. + * + * @hws: The hardware spinlock struct to hold the translation + * result. + * @args: The hardware spinlock specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct hwspinlock *hws, + struct ofnode_phandle_args *args); + + /** + * Lock the hardware spinlock + * + * @dev: hwspinlock Device + * @index: index of the lock to be used + * @return 0 if OK, -ve on error + */ + int (*lock)(struct udevice *dev, int index); + + /** + * Unlock the hardware spinlock + * + * @dev: hwspinlock Device + * @index: index of the lock to be unlocked + * @return 0 if OK, -ve on error + */ + int (*unlock)(struct udevice *dev, int index); + + /** + * Relax - optional + * Platform-specific relax method, called by hwspinlock core + * while spinning on a lock, between two successive call to + * lock + * + * @dev: hwspinlock Device + */ + void (*relax)(struct udevice *dev); +}; + +#endif /* _HWSPINLOCK_H_ */ diff --git a/include/image.h b/include/image.h index 031c355b48d2..610da449eaf9 100644 --- a/include/image.h +++ b/include/image.h @@ -278,6 +278,7 @@ enum { IH_TYPE_PMMC, /* TI Power Management Micro-Controller Firmware */ IH_TYPE_STM32IMAGE, /* STMicroelectronics STM32 Image */ IH_TYPE_SOCFPGAIMAGE_V1, /* Altera SOCFPGA A10 Preloader */ + IH_TYPE_STM32COPRO, /* STMicroelectronics STM32 Coprocessor Image */ IH_TYPE_COUNT, /* Number of image types */ }; diff --git a/include/mipi_display.h b/include/mipi_display.h index ddcc8ca7316b..5c3dbbeffe53 100644 --- a/include/mipi_display.h +++ b/include/mipi_display.h @@ -4,12 +4,16 @@ * * Copyright (C) 2010 Guennadi Liakhovetski * Copyright (C) 2006 Nokia Corporation - * Author: Imre Deak + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Author(s): Imre Deak + * Yannick Fertre + * Philippe Cornu * * 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. */ + #ifndef MIPI_DISPLAY_H #define MIPI_DISPLAY_H @@ -115,6 +119,14 @@ enum { MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E, MIPI_DCS_SET_TEAR_SCANLINE = 0x44, MIPI_DCS_GET_SCANLINE = 0x45, + MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 0x51, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 0x52, /* MIPI DCS 1.3 */ + MIPI_DCS_WRITE_CONTROL_DISPLAY = 0x53, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_CONTROL_DISPLAY = 0x54, /* MIPI DCS 1.3 */ + MIPI_DCS_WRITE_POWER_SAVE = 0x55, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_POWER_SAVE = 0x56, /* MIPI DCS 1.3 */ + MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 0x5E, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F, /* MIPI DCS 1.3 */ MIPI_DCS_READ_DDB_START = 0xA1, MIPI_DCS_READ_DDB_CONTINUE = 0xA8, }; @@ -127,4 +139,247 @@ enum { #define MIPI_DCS_PIXEL_FMT_8BIT 2 #define MIPI_DCS_PIXEL_FMT_3BIT 1 +struct mipi_dsi_host; +struct mipi_dsi_device; + +/* request ACK from peripheral */ +#define MIPI_DSI_MSG_REQ_ACK BIT(0) +/* use Low Power Mode to transmit message */ +#define MIPI_DSI_MSG_USE_LPM BIT(1) + +/** + * struct mipi_dsi_msg - read/write DSI buffer + * @channel: virtual channel id + * @type: payload data type + * @flags: flags controlling this message transmission + * @tx_len: length of @tx_buf + * @tx_buf: data to be written + * @rx_len: length of @rx_buf + * @rx_buf: data to be read, or NULL + */ +struct mipi_dsi_msg { + u8 channel; + u8 type; + u16 flags; + + size_t tx_len; + const void *tx_buf; + + size_t rx_len; + void *rx_buf; +}; + +bool mipi_dsi_packet_format_is_short(u8 type); +bool mipi_dsi_packet_format_is_long(u8 type); + +/** + * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format + * @size: size (in bytes) of the packet + * @header: the four bytes that make up the header (Data ID, Word Count or + * Packet Data, and ECC) + * @payload_length: number of bytes in the payload + * @payload: a pointer to a buffer containing the payload, if any + */ +struct mipi_dsi_packet { + size_t size; + u8 header[4]; + size_t payload_length; + const u8 *payload; +}; + +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg); + +/** + * struct mipi_dsi_host_ops - DSI bus operations + * @attach: attach DSI device to DSI host + * @detach: detach DSI device from DSI host + * @transfer: transmit a DSI packet + * + * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg + * structures. This structure contains information about the type of packet + * being transmitted as well as the transmit and receive buffers. When an + * error is encountered during transmission, this function will return a + * negative error code. On success it shall return the number of bytes + * transmitted for write packets or the number of bytes received for read + * packets. + * + * Note that typically DSI packet transmission is atomic, so the .transfer() + * function will seldomly return anything other than the number of bytes + * contained in the transmit buffer on success. + */ +struct mipi_dsi_host_ops { + int (*attach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + int (*detach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + ssize_t (*transfer)(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg); +}; + +/** + * struct mipi_dsi_host - DSI host device + * @dev: driver model device node for this DSI host + * @ops: DSI host operations + * @list: list management + */ +struct mipi_dsi_host { + struct device *dev; + const struct mipi_dsi_host_ops *ops; + struct list_head list; +}; + +/* DSI mode flags */ + +/* video mode */ +#define MIPI_DSI_MODE_VIDEO BIT(0) +/* video burst mode */ +#define MIPI_DSI_MODE_VIDEO_BURST BIT(1) +/* video pulse mode */ +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) +/* enable auto vertical count mode */ +#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) +/* enable hsync-end packets in vsync-pulse and v-porch area */ +#define MIPI_DSI_MODE_VIDEO_HSE BIT(4) +/* disable hfront-porch area */ +#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) +/* disable hback-porch area */ +#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) +/* disable hsync-active area */ +#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) +/* flush display FIFO on vsync pulse */ +#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) +/* disable EoT packets in HS mode */ +#define MIPI_DSI_MODE_EOT_PACKET BIT(9) +/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ +#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) +/* transmit data in low power */ +#define MIPI_DSI_MODE_LPM BIT(11) + +enum mipi_dsi_pixel_format { + MIPI_DSI_FMT_RGB888, + MIPI_DSI_FMT_RGB666, + MIPI_DSI_FMT_RGB666_PACKED, + MIPI_DSI_FMT_RGB565, +}; + +#define DSI_DEV_NAME_SIZE 20 + +/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: DSI peripheral chip type + * @channel: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node or NULL + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; + u32 channel; + struct device_node *node; +}; + +/** + * struct mipi_dsi_device - DSI peripheral device + * @host: DSI host for this peripheral + * @dev: driver model device node for this peripheral + * @name: DSI peripheral chip type + * @channel: virtual channel assigned to the peripheral + * @format: pixel format for video mode + * @lanes: number of active data lanes + * @mode_flags: DSI operation mode related flags + */ +struct mipi_dsi_device { + struct mipi_dsi_host *host; + struct udevice *dev; + + char name[DSI_DEV_NAME_SIZE]; + unsigned int channel; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; +}; + +/** + * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode + * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking + * information only + * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both + * V-Blanking and H-Blanking information + */ +enum mipi_dsi_dcs_tear_mode { + MIPI_DSI_DCS_TEAR_MODE_VBLANK, + MIPI_DSI_DCS_TEAR_MODE_VHBLANK, +}; + +/** + * struct mipi_dsi_panel_plat - DSI panel platform data + * @device: DSI peripheral device + */ +struct mipi_dsi_panel_plat { + struct mipi_dsi_device *device; +}; + +int mipi_dsi_attach(struct mipi_dsi_device *dsi); +int mipi_dsi_detach(struct mipi_dsi_device *dsi); +int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt); + +/* bit compatible with the xrandr RR_ definitions (bits 0-13) + * + * ABI warning: Existing userspace really expects + * the mode flags to match the xrandr definitions. Any + * changes that don't match the xrandr definitions will + * likely need a new client cap or some other mechanism + * to avoid breaking existing userspace. This includes + * allocating new flags in the previously unused bits! + */ +#define MIPI_DSI_FLAG_PHSYNC BIT(0) +#define MIPI_DSI_FLAG_NHSYNC BIT(1) +#define MIPI_DSI_FLAG_PVSYNC BIT(2) +#define MIPI_DSI_FLAG_NVSYNC BIT(3) +#define MIPI_DSI_FLAG_INTERLACE BIT(4) +#define MIPI_DSI_FLAG_DBLSCAN BIT(5) +#define MIPI_DSI_FLAG_CSYNC BIT(6) +#define MIPI_DSI_FLAG_PCSYNC BIT(7) +#define MIPI_DSI_FLAG_NCSYNC BIT(8) +#define MIPI_DSI_FLAG_HSKEW BIT(9) /* hskew provided */ +#define MIPI_DSI_FLAG_BCAST BIT(10) +#define MIPI_DSI_FLAG_PIXMUX BIT(11) +#define MIPI_DSI_FLAG_DBLCLK BIT(12) +#define MIPI_DSI_FLAG_CLKDIV2 BIT(13) + +/* request ACK from peripheral */ +#define MIPI_DSI_MSG_REQ_ACK BIT(0) +/* use Low Power Mode to transmit message */ +#define MIPI_DSI_MSG_USE_LPM BIT(1) + +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len); +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode); +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format); +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode); +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format); +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); +int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, + u16 brightness); +int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, + u16 *brightness); + #endif diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h new file mode 100644 index 000000000000..d90a1a9c9398 --- /dev/null +++ b/include/power/stpmic1.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#ifndef __PMIC_STPMIC1_H_ +#define __PMIC_STPMIC1_H_ + +#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_DEBUG (STPMIC1_MRST_BUCK(STPMIC1_BUCK1) | \ + STPMIC1_MRST_BUCK(STPMIC1_BUCK3)) + +/* LDOS_MRST_CR */ +#define STPMIC1_MRST_LDO(ldo) BIT(ldo) +#define STPMIC1_MRST_LDO_DEBUG 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 STPMIC1_LDO_VOUT(9) + +#define STPMIC1_LDO4_UV 3300000 + +/* 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) + +/* NVM_SR */ +#define STPMIC1_NVM_BUSY BIT(0) + +/* 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 + +enum { + STPMIC1_BUCK1, + STPMIC1_BUCK2, + STPMIC1_BUCK3, + STPMIC1_BUCK4, + STPMIC1_MAX_BUCK, +}; + +enum { + STPMIC1_PREG_MODE_HP, + STPMIC1_PREG_MODE_LP, +}; + +enum { + STPMIC1_LDO1, + STPMIC1_LDO2, + STPMIC1_LDO3, + STPMIC1_LDO4, + STPMIC1_LDO5, + STPMIC1_LDO6, + STPMIC1_MAX_LDO, +}; + +enum { + STPMIC1_LDO_MODE_NORMAL, + STPMIC1_LDO_MODE_BYPASS, + STPMIC1_LDO_MODE_SINK_SOURCE, +}; + +enum { + STPMIC1_PWR_SW1, + 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 diff --git a/include/power/stpmu1.h b/include/power/stpmu1.h deleted file mode 100644 index 5906fbf832bf..000000000000 --- 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 diff --git a/include/remoteproc.h b/include/remoteproc.h index a59dba84810f..fa82531b9b51 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -63,6 +63,8 @@ struct dm_rproc_uclass_pdata { * Return 0 on success, 1 if not running, -ve on others errors * @ping: Ping the remote device for basic communication check(optional) * Return 0 on success, 1 if not responding, -ve on other errors + * @da_to_pa: Return translated physical address (device address different + * from physical address) */ struct dm_rproc_ops { int (*init)(struct udevice *dev); @@ -72,6 +74,7 @@ struct dm_rproc_ops { int (*reset)(struct udevice *dev); int (*is_running)(struct udevice *dev); int (*ping)(struct udevice *dev); + ulong (*da_to_pa)(struct udevice *dev, ulong da); }; /* Accessor */ @@ -101,7 +104,7 @@ int rproc_dev_init(int id); bool rproc_is_initialized(void); /** - * rproc_load() - load binary to a remote processor + * rproc_load() - load binary or elf to a remote processor * @id: id of the remote processor * @addr: address in memory where the binary image is located * @size: size of the binary image @@ -110,6 +113,19 @@ bool rproc_is_initialized(void); */ int rproc_load(int id, ulong addr, ulong size); +/** + * rproc_get_rsc_table() - get resource table address from elf image + * @id: id of the remote processor + * @addr: address in memory where the image is located + * @size: size of the image + * @rsc_addr: resource table address (device address) + * @rsc_size: resource table size + * + * Return: 0 if all ok, else appropriate error value. + */ +int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr, + unsigned int *rsc_size); + /** * rproc_start() - Start a remote processor * @id: id of the remote processor @@ -166,6 +182,8 @@ static inline int rproc_stop(int id) { return -ENOSYS; } static inline int rproc_reset(int id) { return -ENOSYS; } static inline int rproc_ping(int id) { return -ENOSYS; } static inline int rproc_is_running(int id) { return -ENOSYS; } +static int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr, + unsigned int *rsc_size) { return -ENOSYS; } #endif #endif /* _RPROC_H_ */ diff --git a/include/syscon.h b/include/syscon.h index 2aa73e520af1..1b9975186227 100644 --- a/include/syscon.h +++ b/include/syscon.h @@ -89,4 +89,13 @@ void *syscon_get_first_range(ulong driver_data); */ struct regmap *syscon_node_to_regmap(ofnode node); +/** + * syscon_phandle_to_regmap - get regmap from syscon phandle + * + * @parent: Parent device containing the phandle pointer + * @name: Name of property in the parent device node + */ +struct regmap *syscon_phandle_to_regmap(struct udevice *parent, + const char *name); + #endif diff --git a/include/usb/dwc2_udc.h b/include/usb/dwc2_udc.h index 62e32365e21d..3bd05fab50be 100644 --- a/include/usb/dwc2_udc.h +++ b/include/usb/dwc2_udc.h @@ -19,6 +19,7 @@ struct dwc2_plat_otg_data { unsigned int usb_phy_ctrl; unsigned int usb_flags; unsigned int usb_gusbcfg; + unsigned int usb_gotgctl; unsigned int rx_fifo_sz; unsigned int np_tx_fifo_sz; unsigned int tx_fifo_sz; diff --git a/test/dm/Makefile b/test/dm/Makefile index b490cf28623f..9b3b0bf2026a 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_CLK) += clk.o obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_DM_GPIO) += gpio.o +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o diff --git a/test/dm/hwspinlock.c b/test/dm/hwspinlock.c new file mode 100644 index 000000000000..09ec38b4f37f --- /dev/null +++ b/test/dm/hwspinlock.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Test that hwspinlock driver functions are called */ +static int dm_test_hwspinlock_base(struct unit_test_state *uts) +{ + struct sandbox_state *state = state_get_current(); + struct hwspinlock hws; + + ut_assertok(uclass_get_device(UCLASS_HWSPINLOCK, 0, &hws.dev)); + ut_assertnonnull(hws.dev); + ut_asserteq(false, state->hwspinlock); + + hws.id = 0; + ut_assertok(hwspinlock_lock_timeout(&hws, 1)); + ut_asserteq(true, state->hwspinlock); + + ut_assertok(hwspinlock_unlock(&hws)); + ut_asserteq(false, state->hwspinlock); + + ut_assertok(hwspinlock_lock_timeout(&hws, 1)); + ut_assertok(!hwspinlock_lock_timeout(&hws, 1)); + + ut_assertok(hwspinlock_unlock(&hws)); + ut_assertok(!hwspinlock_unlock(&hws)); + + return 0; +} + +DM_TEST(dm_test_hwspinlock_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py new file mode 100644 index 000000000000..f04a2796ee92 --- /dev/null +++ b/test/py/tests/test_pinmux.py @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 + +import pytest +import u_boot_utils + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_usage_1(u_boot_console): + """Test that 'pinmux' command without parameters displays + pinmux usage.""" + output = u_boot_console.run_command('pinmux') + assert 'Usage:' in output + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_usage_2(u_boot_console): + """Test that 'pinmux status' executed without previous "pinmux dev" + command displays pinmux usage.""" + output = u_boot_console.run_command('pinmux status') + assert 'Usage:' in output + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_status_all(u_boot_console): + """Test that 'pinmux status -a' displays pin's muxing.""" + output = u_boot_console.run_command('pinmux status -a') + assert ('SCL : I2C SCL' in output) + assert ('SDA : I2C SDA' in output) + assert ('TX : Uart TX' in output) + assert ('RX : Uart RX' in output) + assert ('W1 : 1-wire gpio' in output) + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_list(u_boot_console): + """Test that 'pinmux list' returns the pin-controller list.""" + output = u_boot_console.run_command('pinmux list') + assert 'sandbox_pinctrl' in output + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_dev_bad(u_boot_console): + """Test that 'pinmux dev' returns an error when trying to select a + wrong pin controller.""" + pincontroller = 'bad_pin_controller_name' + output = u_boot_console.run_command('pinmux dev ' + pincontroller) + expected_output = 'Can\'t get the pin-controller: ' + pincontroller + '!' + assert (expected_output in output) + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_dev(u_boot_console): + """Test that 'pinmux dev' select the wanted pin controller.""" + pincontroller = 'pinctrl' + output = u_boot_console.run_command('pinmux dev ' + pincontroller) + expected_output = 'dev: ' + pincontroller + assert (expected_output in output) + +@pytest.mark.buildconfigspec('cmd_pinmux') +def test_pinmux_status(u_boot_console): + """Test that 'pinmux status' displays selected pincontroller's pin + muxing descriptions.""" + output = u_boot_console.run_command('pinmux status') + assert ('SCL : I2C SCL' in output) + assert ('SDA : I2C SDA' in output) + assert ('TX : Uart TX' in output) + assert ('RX : Uart RX' in output) + assert ('W1 : 1-wire gpio' in output) diff --git a/tools/stm32image.c b/tools/stm32image.c index 08b32ba87dd5..ff3ec5f3f2b9 100644 --- a/tools/stm32image.c +++ b/tools/stm32image.c @@ -14,6 +14,8 @@ #define HEADER_VERSION_V1 0x1 /* default option : bit0 => no signature */ #define HEADER_DEFAULT_OPTION (cpu_to_le32(0x00000001)) +/* default binary type for U-Boot */ +#define HEADER_TYPE_UBOOT (cpu_to_le32(0x00000000)) struct stm32_header { uint32_t magic_number; @@ -29,7 +31,8 @@ struct stm32_header { uint32_t option_flags; uint32_t ecdsa_algorithm; uint32_t ecdsa_public_key[64 / 4]; - uint32_t padding[84 / 4]; + uint32_t padding[83 / 4]; + uint32_t binary_type; }; static struct stm32_header stm32image_header; @@ -43,6 +46,7 @@ static void stm32image_default_header(struct stm32_header *ptr) ptr->header_version[VER_MAJOR_IDX] = HEADER_VERSION_V1; ptr->option_flags = HEADER_DEFAULT_OPTION; ptr->ecdsa_algorithm = 1; + ptr->binary_type = HEADER_TYPE_UBOOT; } static uint32_t stm32image_checksum(void *start, uint32_t len) @@ -112,6 +116,8 @@ static void stm32image_print_header(const void *ptr) le32_to_cpu(stm32hdr->image_checksum)); printf("Option : 0x%08x\n", le32_to_cpu(stm32hdr->option_flags)); + printf("BinaryType : 0x%08x\n", + le32_to_cpu(stm32hdr->binary_type)); } static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd, From e1532f83da6aeb2ce7326f65bbed9f6ebf1e8988 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Jan 2019 17:12:35 +0100 Subject: [PATCH 002/244] cosmetic: video: rename priv variable to dsi Use proper variable name Change-Id: I213f95370c8876b93d59b4536b740e6571ff1893 Reviewed-on: https://gerrit.st.com/115485 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115487 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/video/stm32/stm32_dsi.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index 09266fe9a949..f5f02d046cc0 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -310,9 +310,9 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { static int stm32_dsi_attach(struct udevice *dev) { - struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct stm32_dsi_priv *dsi = dev_get_priv(dev); struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(dev); - struct mipi_dsi_device *device = &priv->device; + struct mipi_dsi_device *device = &dsi->device; int ret; platdata->max_data_lanes = 2; @@ -336,8 +336,8 @@ static int stm32_dsi_attach(struct udevice *dev) static int stm32_dsi_set_backlight(struct udevice *dev, int percent) { struct dw_mipi_dsi_plat_data *dplat = dev_get_platdata(dev); - struct stm32_dsi_priv *priv = dev_get_priv(dev); - struct mipi_dsi_device *device = &priv->device; + struct stm32_dsi_priv *dsi = dev_get_priv(dev); + struct mipi_dsi_device *device = &dsi->device; struct udevice *panel = dplat->panel; struct mipi_dsi_panel_plat *mplat; int ret; @@ -359,29 +359,29 @@ static int stm32_dsi_set_backlight(struct udevice *dev, int percent) static int stm32_dsi_probe(struct udevice *dev) { - struct stm32_dsi_priv *priv = dev_get_priv(dev); - struct mipi_dsi_device *device = &priv->device; + struct stm32_dsi_priv *dsi = dev_get_priv(dev); + struct mipi_dsi_device *device = &dsi->device; struct reset_ctl rst; struct clk clk; int ret; device->dev = dev; - priv->base = (void *)dev_read_addr(dev); - if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) { + dsi->base = (void *)dev_read_addr(dev); + if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) { dev_err(dev, "dsi dt register address error\n"); return -EINVAL; } if (IS_ENABLED(CONFIG_DM_REGULATOR)) { ret = device_get_supply_regulator(dev, "phy-dsi-supply", - &priv->vdd_reg); + &dsi->vdd_reg); if (ret && ret != -ENOENT) { dev_err(dev, "Warning: cannot get phy dsi supply\n"); return -ENODEV; } - ret = regulator_set_enable(priv->vdd_reg, true); + ret = regulator_set_enable(dsi->vdd_reg, true); if (ret) return -ENODEV; } @@ -389,14 +389,14 @@ static int stm32_dsi_probe(struct udevice *dev) ret = clk_get_by_name(device->dev, "pclk", &clk); if (ret) { dev_err(dev, "peripheral clock get error %d\n", ret); - regulator_set_enable(priv->vdd_reg, false); + regulator_set_enable(dsi->vdd_reg, false); return -ENODEV; } ret = clk_enable(&clk); if (ret) { dev_err(dev, "peripheral clock enable error %d\n", ret); - regulator_set_enable(priv->vdd_reg, false); + regulator_set_enable(dsi->vdd_reg, false); return -ENODEV; } @@ -404,17 +404,17 @@ static int stm32_dsi_probe(struct udevice *dev) if (ret) { dev_err(dev, "pll reference clock get error %d\n", ret); clk_disable(&clk); - regulator_set_enable(priv->vdd_reg, false); + regulator_set_enable(dsi->vdd_reg, false); return ret; } - priv->pllref_clk = (unsigned int)clk_get_rate(&clk); + dsi->pllref_clk = (unsigned int)clk_get_rate(&clk); ret = reset_get_by_index(device->dev, 0, &rst); if (ret) { dev_err(dev, "missing dsi hardware reset\n"); clk_disable(&clk); - regulator_set_enable(priv->vdd_reg, false); + regulator_set_enable(dsi->vdd_reg, false); return -ENODEV; } From 908c3bf50f28b25522c782011129a332d8a2794a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Jan 2019 17:11:52 +0100 Subject: [PATCH 003/244] video: check hardware version of DSI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the hardware version of DSI. Versions 1.30 & 1.31 are only supported. Rename the parameter priv by dsi into all functions. Change-Id: I31b7e9fb6169f1ab491aa2f5089650eff5e86d96 Reviewed-on: https://gerrit.st.com/115485 Signed-off-by: Yannick Fertré Reviewed-on: https://gerrit.st.com/115488 Tested-by: Patrick DELAUNAY Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY --- drivers/video/stm32/stm32_dsi.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index f5f02d046cc0..f8f7c8358d44 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -242,7 +242,6 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, u32 val; /* Update lane capabilities according to hw version */ - dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; dsi->lane_min_kbps = LANE_MIN_KBPS; dsi->lane_max_kbps = LANE_MAX_KBPS; if (dsi->hw_version == HWVER_131) { @@ -421,6 +420,16 @@ static int stm32_dsi_probe(struct udevice *dev) /* Reset */ reset_deassert(&rst); + /* check hardware version */ + dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; + if (dsi->hw_version != HWVER_130 && + dsi->hw_version != HWVER_131) { + dev_err(dev, "bad dsi hardware version\n"); + clk_disable(&clk); + regulator_set_enable(dsi->vdd_reg, false); + return -ENODEV; + } + return 0; } From 3c2227a329d6ca4ecf7c20557d83ec66814f4831 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 8 Jan 2019 11:56:17 +0100 Subject: [PATCH 004/244] stm32prog: force videoconsole output Allow user feedback on screen when available during STM32CubeProgrammer usage. Change-Id: I9ab57ae280011db6e95bb0d2b5bbd2a5edb8c683 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115358 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- .../cmd_stm32prog/cmd_stm32prog.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c index d1c07dc1f9fa..a6ee0f2dadbf 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c @@ -10,6 +10,26 @@ DECLARE_GLOBAL_DATA_PTR; +static void enable_vidconsole(void) +{ +#ifdef CONFIG_DM_VIDEO + char *stdname; + char buf[64]; + + stdname = env_get("stdout"); + if (!strstr(stdname, "vidconsole")) { + snprintf(buf, sizeof(buf), "%s,vidconsole", stdname); + env_set("stdout", buf); + } + + stdname = env_get("stderr"); + if (!strstr(stdname, "vidconsole")) { + snprintf(buf, sizeof(buf), "%s,vidconsole", stdname); + env_set("stderr", buf); + } +#endif +} + static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -44,6 +64,8 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc, if (argc > 4) size = simple_strtoul(argv[4], NULL, 16); + enable_vidconsole(); + data = stm32prog_init(link, dev, addr, size); if (!data) return CMD_RET_FAILURE; From 5b2ef8968deac1437425e21252d8909c0f4f7216 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 11 Jan 2019 11:11:12 +0100 Subject: [PATCH 005/244] dts: stm32mp1: alignment with kernel device tree Add stm32mp157c-m4-srm.dtsi include include to be align with the latest kernel device tree and avoid issue with device tree generated by CubeMX Change-Id: I229408e3ab28aae95d9e2f49ef74218033319efb Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115657 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/dts/stm32mp157a-dk1.dts | 1 + arch/arm/dts/stm32mp157c-ed1.dts | 1 + arch/arm/dts/stm32mp157c-m4-srm.dtsi | 436 +++++++++++++++++++++++++++ 3 files changed, 438 insertions(+) create mode 100644 arch/arm/dts/stm32mp157c-m4-srm.dtsi diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index e3d305a43fb5..7e911f3f4152 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -7,6 +7,7 @@ /dts-v1/; #include "stm32mp157c.dtsi" +#include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157cac-pinctrl.dtsi" #include #include diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 37edf87e68cc..cf2750ee7fc3 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "stm32mp157c.dtsi" +#include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157caa-pinctrl.dtsi" #include #include diff --git a/arch/arm/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/dts/stm32mp157c-m4-srm.dtsi new file mode 100644 index 000000000000..5ebe24b511a0 --- /dev/null +++ b/arch/arm/dts/stm32mp157c-m4-srm.dtsi @@ -0,0 +1,436 @@ +&m4_rproc { + m4_system_resources { + #address-cells = <1>; + #size-cells = <0>; + + m4_timers2: timer@40000000 { + compatible = "rproc-srm-dev"; + reg = <0x40000000>; + clocks = <&rcc TIM2_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers3: timer@40001000 { + compatible = "rproc-srm-dev"; + reg = <0x40001000>; + clocks = <&rcc TIM3_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers4: timer@40002000 { + compatible = "rproc-srm-dev"; + reg = <0x40002000>; + clocks = <&rcc TIM4_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers5: timer@40003000 { + compatible = "rproc-srm-dev"; + reg = <0x40003000>; + clocks = <&rcc TIM5_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers6: timer@40004000 { + compatible = "rproc-srm-dev"; + reg = <0x40004000>; + clocks = <&rcc TIM6_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers7: timer@40005000 { + compatible = "rproc-srm-dev"; + reg = <0x40005000>; + clocks = <&rcc TIM7_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers12: timer@40006000 { + compatible = "rproc-srm-dev"; + reg = <0x40006000>; + clocks = <&rcc TIM12_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers13: timer@40007000 { + compatible = "rproc-srm-dev"; + reg = <0x40007000>; + clocks = <&rcc TIM13_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers14: timer@40008000 { + compatible = "rproc-srm-dev"; + reg = <0x40008000>; + clocks = <&rcc TIM14_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_lptimer1: timer@40009000 { + compatible = "rproc-srm-dev"; + reg = <0x40009000>; + clocks = <&rcc LPTIM1_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_spi2: spi@4000b000 { + compatible = "rproc-srm-dev"; + reg = <0x4000b000>; + clocks = <&rcc SPI2_K>; + status = "disabled"; + }; + m4_i2s2: audio-controller@4000b000 { + compatible = "rproc-srm-dev"; + reg = <0x4000b000>; + status = "disabled"; + }; + m4_spi3: spi@4000c000 { + compatible = "rproc-srm-dev"; + reg = <0x4000c000>; + clocks = <&rcc SPI3_K>; + status = "disabled"; + }; + m4_i2s3: audio-controller@4000c000 { + compatible = "rproc-srm-dev"; + reg = <0x4000c000>; + status = "disabled"; + }; + m4_spdifrx: audio-controller@4000d000 { + compatible = "rproc-srm-dev"; + reg = <0x4000d000>; + clocks = <&rcc SPDIF_K>; + clock-names = "kclk"; + status = "disabled"; + }; + m4_usart2: serial@4000e000 { + compatible = "rproc-srm-dev"; + reg = <0x4000e000>; + interrupt-parent = <&exti>; + interrupts = <27 1>; + clocks = <&rcc USART2_K>; + status = "disabled"; + }; + m4_usart3: serial@4000f000 { + compatible = "rproc-srm-dev"; + reg = <0x4000f000>; + interrupt-parent = <&exti>; + interrupts = <28 1>; + clocks = <&rcc USART3_K>; + status = "disabled"; + }; + m4_uart4: serial@40010000 { + compatible = "rproc-srm-dev"; + reg = <0x40010000>; + interrupt-parent = <&exti>; + interrupts = <30 1>; + clocks = <&rcc UART4_K>; + status = "disabled"; + }; + m4_uart5: serial@40011000 { + compatible = "rproc-srm-dev"; + reg = <0x40011000>; + interrupt-parent = <&exti>; + interrupts = <31 1>; + clocks = <&rcc UART5_K>; + status = "disabled"; + }; + m4_i2c1: i2c@40012000 { + compatible = "rproc-srm-dev"; + reg = <0x40012000>; + interrupt-parent = <&exti>; + interrupts = <21 1>; + clocks = <&rcc I2C1_K>; + status = "disabled"; + }; + m4_i2c2: i2c@40013000 { + compatible = "rproc-srm-dev"; + reg = <0x40013000>; + interrupt-parent = <&exti>; + interrupts = <22 1>; + clocks = <&rcc I2C2_K>; + status = "disabled"; + }; + m4_i2c3: i2c@40014000 { + compatible = "rproc-srm-dev"; + reg = <0x40014000>; + interrupt-parent = <&exti>; + interrupts = <23 1>; + clocks = <&rcc I2C3_K>; + status = "disabled"; + }; + m4_i2c5: i2c@40015000 { + compatible = "rproc-srm-dev"; + reg = <0x40015000>; + interrupt-parent = <&exti>; + interrupts = <25 1>; + clocks = <&rcc I2C5_K>; + status = "disabled"; + }; + m4_cec: cec@40016000 { + compatible = "rproc-srm-dev"; + reg = <0x40016000>; + interrupt-parent = <&exti>; + interrupts = <69 1>; + clocks = <&rcc CEC_K>, <&rcc CK_LSE>; + clock-names = "cec", "hdmi-cec"; + status = "disabled"; + }; + m4_dac: dac@40017000 { + compatible = "rproc-srm-dev"; + reg = <0x40017000>; + clocks = <&rcc DAC12>; + clock-names = "pclk"; + status = "disabled"; + }; + m4_uart7: serial@40018000 { + compatible = "rproc-srm-dev"; + reg = <0x40018000>; + interrupt-parent = <&exti>; + interrupts = <32 1>; + clocks = <&rcc UART7_K>; + status = "disabled"; + }; + m4_uart8: serial@40019000 { + compatible = "rproc-srm-dev"; + reg = <0x40019000>; + interrupt-parent = <&exti>; + interrupts = <33 1>; + clocks = <&rcc UART8_K>; + status = "disabled"; + }; + m4_timers1: timer@44000000 { + compatible = "rproc-srm-dev"; + reg = <0x44000000>; + clocks = <&rcc TIM1_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers8: timer@44001000 { + compatible = "rproc-srm-dev"; + reg = <0x44001000>; + clocks = <&rcc TIM8_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_usart6: serial@44003000 { + compatible = "rproc-srm-dev"; + reg = <0x44003000>; + interrupt-parent = <&exti>; + interrupts = <29 1>; + clocks = <&rcc USART6_K>; + status = "disabled"; + }; + m4_spi1: spi@44004000 { + compatible = "rproc-srm-dev"; + reg = <0x44004000>; + clocks = <&rcc SPI1_K>; + status = "disabled"; + }; + m4_i2s1: audio-controller@44004000 { + compatible = "rproc-srm-dev"; + reg = <0x44004000>; + status = "disabled"; + }; + m4_spi4: spi@44005000 { + compatible = "rproc-srm-dev"; + reg = <0x44005000>; + clocks = <&rcc SPI4_K>; + status = "disabled"; + }; + m4_timers15: timer@44006000 { + compatible = "rproc-srm-dev"; + reg = <0x44006000>; + clocks = <&rcc TIM15_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers16: timer@44007000 { + compatible = "rproc-srm-dev"; + reg = <0x44007000>; + clocks = <&rcc TIM16_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers17: timer@44008000 { + compatible = "rproc-srm-dev"; + reg = <0x44008000>; + clocks = <&rcc TIM17_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_spi5: spi@44009000 { + compatible = "rproc-srm-dev"; + reg = <0x44009000>; + clocks = <&rcc SPI5_K>; + status = "disabled"; + }; + m4_sai1: sai@4400a000 { + compatible = "rproc-srm-dev"; + reg = <0x4400a000>; + clocks = <&rcc SAI1_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_sai2: sai@4400b000 { + compatible = "rproc-srm-dev"; + reg = <0x4400b000>; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_sai3: sai@4400c000 { + compatible = "rproc-srm-dev"; + reg = <0x4400c000>; + clocks = <&rcc SAI3_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_dfsdm: dfsdm@4400d000 { + compatible = "rproc-srm-dev"; + reg = <0x4400d000>; + clocks = <&rcc DFSDM_K>; + clock-names = "dfsdm"; + status = "disabled"; + }; + m4_m_can1: can@4400e000 { + compatible = "rproc-srm-dev"; + reg = <0x4400e000>, <0x44011000>; + clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + status = "disabled"; + }; + m4_m_can2: can@4400f000 { + compatible = "rproc-srm-dev"; + reg = <0x4400f000>, <0x44011000>; + clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clock-names = "hclk", "cclk"; + status = "disabled"; + }; + m4_dma1: dma@48000000 { + compatible = "rproc-srm-dev"; + reg = <0x48000000>; + clocks = <&rcc DMA1>; + status = "disabled"; + }; + m4_dma2: dma@48001000 { + compatible = "rproc-srm-dev"; + reg = <0x48001000>; + clocks = <&rcc DMA2>; + status = "disabled"; + }; + m4_dmamux1: dma-router@48002000 { + compatible = "rproc-srm-dev"; + reg = <0x48002000>; + clocks = <&rcc DMAMUX>; + status = "disabled"; + }; + m4_adc: adc@48003000 { + compatible = "rproc-srm-dev"; + reg = <0x48003000>; + clocks = <&rcc ADC12>, <&rcc ADC12_K>; + clock-names = "bus", "adc"; + status = "disabled"; + }; + m4_sdmmc3: sdmmc@48004000 { + compatible = "rproc-srm-dev"; + reg = <0x48004000>, <0x48005000>; + clocks = <&rcc SDMMC3_K>; + status = "disabled"; + }; + m4_usbotg_hs: usb-otg@49000000 { + compatible = "rproc-srm-dev"; + reg = <0x49000000>; + clocks = <&rcc USBO_K>; + clock-names = "otg"; + status = "disabled"; + }; + m4_hash2: hash@4c002000 { + compatible = "rproc-srm-dev"; + reg = <0x4c002000>; + clocks = <&rcc HASH2>; + status = "disabled"; + }; + m4_rng2: rng@4c003000 { + compatible = "rproc-srm-dev"; + reg = <0x4c003000>; + clocks = <&rcc RNG2_K>; + status = "disabled"; + }; + m4_crc2: crc@4c004000 { + compatible = "rproc-srm-dev"; + reg = <0x4c004000>; + clocks = <&rcc CRC2>; + status = "disabled"; + }; + m4_cryp2: cryp@4c005000 { + compatible = "rproc-srm-dev"; + reg = <0x4c005000>; + clocks = <&rcc CRYP2>; + status = "disabled"; + }; + m4_dcmi: dcmi@4c006000 { + compatible = "rproc-srm-dev"; + reg = <0x4c006000>; + clocks = <&rcc DCMI>; + clock-names = "mclk"; + status = "disabled"; + }; + m4_lptimer2: timer@50021000 { + compatible = "rproc-srm-dev"; + reg = <0x50021000>; + clocks = <&rcc LPTIM2_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer3: timer@50022000 { + compatible = "rproc-srm-dev"; + reg = <0x50022000>; + clocks = <&rcc LPTIM3_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer4: timer@50023000 { + compatible = "rproc-srm-dev"; + reg = <0x50023000>; + clocks = <&rcc LPTIM4_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer5: timer@50024000 { + compatible = "rproc-srm-dev"; + reg = <0x50024000>; + clocks = <&rcc LPTIM5_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_sai4: sai@50027000 { + compatible = "rproc-srm-dev"; + reg = <0x50027000>; + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_qspi: qspi@58003000 { + compatible = "rproc-srm-dev"; + reg = <0x58003000>, <0x70000000>; + clocks = <&rcc QSPI_K>; + status = "disabled"; + }; + m4_ethernet0: ethernet@5800a000 { + compatible = "rproc-srm-dev"; + reg = <0x5800a000>; + clock-names = "stmmaceth", + "mac-clk-tx", + "mac-clk-rx", + "ethstp", + "syscfg-clk"; + clocks = <&rcc ETHMAC>, + <&rcc ETHTX>, + <&rcc ETHRX>, + <&rcc ETHSTP>, + <&rcc SYSCFG>; + status = "disabled"; + }; + }; +}; + From 6893b88a4a877e7ae35d0ed0ba99a7761f75ef22 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 14 Jan 2019 13:10:55 +0100 Subject: [PATCH 006/244] remoteproc: stm32m: update translation support After update of device tree, update the driver to support the translate for the RETRAM region only in stm32_copro_da_to_pa() to avoid probe error.. Change-Id: I6d008d10a51ad9fbc671e662027d6db3d9590b03 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115696 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Arnaud POULIQUEN Reviewed-on: https://gerrit.st.com/115964 --- arch/arm/mach-stm32mp/include/mach/stm32.h | 3 ++ drivers/remoteproc/stm32_copro.c | 44 +++++++++------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 41478733d7e9..36b885b108aa 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -35,6 +35,9 @@ #define STM32_DDR_BASE 0xC0000000 #define STM32_DDR_SIZE SZ_1G +#define STM32_RETRAM_BASE 0x38000000 +#define STM32_RETRAM_SIZE 0x00010000 + #ifndef __ASSEMBLY__ #include diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 310d077ed818..44230ff4a6bc 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -18,7 +18,6 @@ /** * struct stm32_copro_privdata - power processor private data - * @loadaddr: base address for loading the power processor * @reset_ctl: reset controller handle * @hold_boot_regmap * @hold_boot_offset @@ -26,7 +25,6 @@ * @secured_soc: TZEN flag (register protection) */ struct stm32_copro_privdata { - phys_addr_t loadaddr; struct reset_ctl reset_ctl; struct regmap *hold_boot_regmap; uint hold_boot_offset; @@ -46,21 +44,9 @@ static int st_of_to_priv(struct udevice *dev, { struct regmap *regmap; const fdt32_t *cell; - const void *blob = gd->fdt_blob; uint tz_offset, tz_mask, tzen; int len, ret; - if (!blob) { - dev_dbg(dev, "no dt?\n"); - return -EINVAL; - } - - priv->loadaddr = dev_read_addr(dev); - if (priv->loadaddr == FDT_ADDR_T_NONE) { - dev_dbg(dev, "no 'reg' property\n"); - return -EINVAL; - } - regmap = syscon_phandle_to_regmap(dev, "st,syscfg-holdboot"); if (IS_ERR(regmap)) { dev_dbg(dev, "unable to find holdboot regmap (%ld)\n", @@ -123,8 +109,7 @@ static int stm32_copro_probe(struct udevice *dev) ret = st_of_to_priv(dev, priv); - dev_dbg(dev, "probed with slave_addr=0x%08lX (%d)\n", - priv->loadaddr, ret); + dev_dbg(dev, "probed (%d)\n", ret); return ret; } @@ -163,6 +148,17 @@ static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold) return ret; } +static ulong stm32_copro_da_to_pa(struct udevice *dev, ulong da) +{ + /* to update with address translate by DT range */ + + /* CM4 boot at address 0x0 = RETRAM alias, not available for CA7 load */ + if (da >= 0 && da < STM32_RETRAM_SIZE) + return (da + STM32_RETRAM_BASE); + + return da; +} + /** * stm32_copro_load() - Loadup the STM32 Cortex-M4 remote processor * @dev: corresponding STM32 remote processor device @@ -174,6 +170,7 @@ static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold) static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) { struct stm32_copro_privdata *priv; + phys_addr_t loadaddr; int ret; priv = dev_get_priv(dev); @@ -186,10 +183,12 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) return ret; } + /* by default load for copro BOOT address = 0x0 */ + loadaddr = stm32_copro_da_to_pa(dev, 0x0); dev_dbg(dev, "Loading binary from 0x%08lX, size 0x%08lX to 0x%08lX\n", - addr, size, priv->loadaddr); + addr, size, loadaddr); - memcpy((void *)priv->loadaddr, (void *)addr, size); + memcpy((void *)loadaddr, (void *)addr, size); dev_dbg(dev, "Complete!\n"); return 0; @@ -241,15 +240,6 @@ static int stm32_copro_reset(struct udevice *dev) return 0; } -ulong stm32_copro_da_to_pa(struct udevice *dev, ulong da) -{ - /* to update according to lastest DT */ - if (da >= 0 && da < 0x10000) - return (da + 0x38000000); - - return da; -} - static const struct dm_rproc_ops stm32_copro_ops = { .load = stm32_copro_load, .start = stm32_copro_start, From ffe232a956d76469abf9e90d0e981665e21c5c92 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 15 Jan 2019 10:25:15 +0100 Subject: [PATCH 007/244] remoteproc: align flush operation Align flush operation at the cache line size (ARCH_DMA_MINALIGN) This patch avoid error= CACHE: Misaligned operation at range Change-Id: I5252c5ea5c0cb44062d37c0e0729343d59879df5 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115943 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-on: https://gerrit.st.com/115965 --- drivers/remoteproc/rproc-uclass.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 8ea92f753bbd..204e6e848ffe 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -449,7 +449,10 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, if (phdr->p_filesz != phdr->p_memsz) memset(dst + phdr->p_filesz, 0x00, phdr->p_memsz - phdr->p_filesz); - flush_cache((unsigned long)dst, phdr->p_filesz); + flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), + roundup((int)dst + phdr->p_filesz, + ARCH_DMA_MINALIGN) - + rounddown((int)dst, ARCH_DMA_MINALIGN)); ++phdr; } @@ -561,7 +564,10 @@ static int rproc_elf_find_load_rsc_table(struct udevice *dev, src = (void *)fw_addr + shdr->sh_offset; memcpy(dst, src, shdr->sh_size); - flush_cache((unsigned long)dst, shdr->sh_size); + flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), + roundup((int)dst + shdr->sh_size, + ARCH_DMA_MINALIGN) - + rounddown((int)dst, ARCH_DMA_MINALIGN)); return 0; } From 85e745715549be8b4134ba85c08ed7793b6a48b8 Mon Sep 17 00:00:00 2001 From: Lionel Debieve Date: Thu, 17 Jan 2019 12:32:50 +0100 Subject: [PATCH 008/244] dts: stm32mp1: change default minimal buck1 value Minimal value is the value set during boot or before suspend. We must ensure that the value is a functional value to boot. Change-Id: Ie46314ea2dde2125f2f34f0c926b9c7d61ea3f39 Signed-off-by: Lionel Debieve Reviewed-on: https://gerrit.st.com/116153 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Reviewed-on: https://gerrit.st.com/116259 Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157a-dk1.dts | 2 +- arch/arm/dts/stm32mp157c-ed1.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 7e911f3f4152..8e0944797430 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -310,7 +310,7 @@ vddcore: buck1 { regulator-name = "vddcore"; - regulator-min-microvolt = <800000>; + regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index cf2750ee7fc3..0f70bb72266a 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -203,7 +203,7 @@ vddcore: buck1 { regulator-name = "vddcore"; - regulator-min-microvolt = <800000>; + regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; From 62f620eb8de60ca8e19c2659030fc74c3fe6260c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 17 Jan 2019 16:26:54 +0100 Subject: [PATCH 009/244] stm32mp1: add a delay loop early in SPL for debugger attach Current Soc revision has a known limitation regarding debug linked to reset halt. For this purpose we couldn't attach inside the rom code. We may integrate a delay loop early in the SPL boot process to wait for the debugger to attach. Today, we use a backup register bit to know if we are in debug mode and add a loop at the beginning of SPL execution, in the weak function save_boot_params() called by reset function in arch/cpu/armv7/start.S. This can be removed when using the Soc revision that fixes the limitation. Anyway, this source code identifies the Soc revision and is only executed if it corresponds, so it can be kept on other revisions without any consequence. Change-Id: Idd0ff0d790010e29bb6f644b8923c802d191fc1d Depends-On: I459ee5bd294660ec6cc48cd8ea08ba35be0c51ba Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/116178 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-on: https://gerrit.st.com/116368 --- arch/arm/mach-stm32mp/Kconfig | 13 +++ arch/arm/mach-stm32mp/Makefile | 1 + arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S | 113 ++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 0c68c24c09b1..fbc81953d72d 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -47,6 +47,19 @@ config TARGET_STM32MP1 STMicroelectronics MPU with core ARMv7 dual core A7 for STM32MP153, monocore for STM32MP151 +config STM32MP1_RESET_HALT_WORKAROUND + bool "workaround for reset halt deubg on stm32mp15x" + depends on TARGET_STM32MP1 + default y + help + Activate a workaround for current STM32MP15x revision B + limitation on debug reset halt not handle by ROM code: + add a delay loop early in the SPL boot process to wait for + the debugger to attach + it can be removed when using the Soc revision + that fixes the limitation. + + config STM32MP1_TRUSTED bool "Support trusted boot with TF-A" default y if !SPL diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 09636db01b35..c67bccea8c8c 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -9,6 +9,7 @@ obj-y += syscon.o ifdef CONFIG_SPL_BUILD obj-y += spl.o +obj-$(CONFIG_STM32MP1_RESET_HALT_WORKAROUND) += stm32mp1_helper_dgb.o else obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S new file mode 100644 index 000000000000..f7d8f65e44e8 --- /dev/null +++ b/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * + */ + +/***************************************************************************** + * This file is only needed for current Soc revision which has a limitation on + * debug reset halt. This can be removed when using the Soc revision that + * fixes the limitation. Anyway, this source code identifies the Soc revision + * and is only executed if it corresponds, so it can be kept on other + * revisions without any consequence. + ****************************************************************************/ + +#include +#include + +#define BIT(nr) (1 << (nr)) + +#define DBG_DSCR_ADDR 0x500D0088 +#define DBG_DSCR_HDBGEN BIT(14) + +#define PWR_CR1_ADDR 0x50001000 +#define PWR_CR1_DBP BIT(8) + +#define TAMP_BKP_REGISTER_20 (0x5C00A100 + (20 << 2)) + +#define BOOT_CONTEXT_ROM_VER_OFFSET 156 +#define BOOT_CONTEXT_CUT_VER_OFFSET 4 +#define BOOT_CONTEXT_CUT_VER_VALUE 0x00000200 + + .globl save_boot_params + +ENTRY(save_boot_params) + /* + * This function is the first call after reset. + * Boot rom parameters are stored in r0..r3, so we mustn't use them + * here. And because they are saved in r9..r12 just after the + * execution of this function, we should firstly use these registers. + * And then, if more registers needed, we have to start by using + * r8, and then r7 and so on. By this way, debug will be done in + * conditions closed to the initial context. + */ + + /* Check Soc revision */ + mov r12, r0 + ldr r12, [r12, #BOOT_CONTEXT_ROM_VER_OFFSET] + ldr r12, [r12, #BOOT_CONTEXT_CUT_VER_OFFSET] + teq r12, #BOOT_CONTEXT_CUT_VER_VALUE + bne func_exit + + /* Disable the backup domain write protection */ + ldr r12, =PWR_CR1_ADDR + ldr r11, [r12] + orr r11, r11, #PWR_CR1_DBP + str r11, [r12] +poll_dbp: + ldr r11, [r12] + tst r11, #PWR_CR1_DBP + beq poll_dbp + + /* Clear tamper 20 bit 16 if set */ + ldr r12, =TAMP_BKP_REGISTER_20 + ldr r11, [r12] + tst r11, #(BIT(16)) + beq func_exit + bic r11, #(BIT(16)) + str r11, [r12] + + /* Re-enable the backup domain write protection */ + ldr r12, =PWR_CR1_ADDR + ldr r11, [r12] + bic r11, #PWR_CR1_DBP + str r11, [r12] +poll_dbp_2: + ldr r11, [r12] + tst r11, #PWR_CR1_DBP + bne poll_dbp_2 + + /* Get current time + 1 second */ + /* CNTFRQ */ + mrc p15, 0, r12, c14, c0, 0 + /* CNTPCT_64 */ + mrrc p15, 0, r11, r10, c14 + add r12, r12, r11 + +loop: + /* Check A7 DBG_DSCR HDBGEN bit value */ + ldr r10, =DBG_DSCR_ADDR + ldr r10, [r10] + tst r10, #DBG_DSCR_HDBGEN + beq loop_continue + /* Sw break */ + bkpt 5 + /* Jump entrypoint */ + b reset +loop_continue: + /* Check 1 second expiration */ + mrrc p15, 0, r10, r9, c14 + /* Check if MSB 64-bit increment needed */ + cmp r12, r11 + bmi msb_incr + cmp r12, r10 + bmi func_exit + b loop +msb_incr: + cmp r12, r10 + bpl loop + cmp r11, r10 + bmi loop +func_exit: + b save_boot_params_ret +ENDPROC(save_boot_params) From 3b9e8d9000a082c3be43a0c00e4b5c415d852219 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 22 Jan 2019 11:01:00 +0100 Subject: [PATCH 010/244] stm32mp1: use DBGMCU register to detect the revision Avoid issue when boot context is invalid, for engineering boot mode for example. Change-Id: Ie286490790ba4bb2bdee2ee923f23a5ba1f9eb96 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/116448 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Nicolas LE BAYON Reviewed-by: Jean Michel SIMON Tested-by: Jean Michel SIMON Reviewed-on: https://gerrit.st.com/116498 --- arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S | 25 +++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S index f7d8f65e44e8..29f8e1f8ee17 100644 --- a/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S +++ b/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S @@ -20,14 +20,18 @@ #define DBG_DSCR_ADDR 0x500D0088 #define DBG_DSCR_HDBGEN BIT(14) +#define RCC_DBGCFGR_ADDR 0x5000080C +#define RCC_DBGCFGR_DBGCKEN BIT(8) + #define PWR_CR1_ADDR 0x50001000 #define PWR_CR1_DBP BIT(8) +#define DBGMCU_IDC_ADDR 0x50081000 +#define DBGMCU_IDC_MASK 0xFFFF0FFF +#define DBGMCU_IDC_VALUE 0x20000500 + #define TAMP_BKP_REGISTER_20 (0x5C00A100 + (20 << 2)) -#define BOOT_CONTEXT_ROM_VER_OFFSET 156 -#define BOOT_CONTEXT_CUT_VER_OFFSET 4 -#define BOOT_CONTEXT_CUT_VER_VALUE 0x00000200 .globl save_boot_params @@ -43,10 +47,17 @@ ENTRY(save_boot_params) */ /* Check Soc revision */ - mov r12, r0 - ldr r12, [r12, #BOOT_CONTEXT_ROM_VER_OFFSET] - ldr r12, [r12, #BOOT_CONTEXT_CUT_VER_OFFSET] - teq r12, #BOOT_CONTEXT_CUT_VER_VALUE + ldr r12, =RCC_DBGCFGR_ADDR + ldr r11, [r12] /* read RCC_DBGCFGR (r11) */ + orr r10, r11, #RCC_DBGCFGR_DBGCKEN + str r10, [r12] /* update RCC_DBGCFGR */ + ldr r10, =DBGMCU_IDC_ADDR + ldr r10, [r10] /* read DBGMCU_IDC (r10) */ + str r11, [r12] /* restore RCC_DBGCFGR (r11) */ + ldr r12, =DBGMCU_IDC_MASK + and r10, r12 /* mask reserved bits */ + ldr r11, =DBGMCU_IDC_VALUE + teq r10, r11 /* test DBGMCU_IDC */ bne func_exit /* Disable the backup domain write protection */ From 00a5933e98dee8e45668d29478e495c2f9bdad9d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 24 Jan 2019 10:35:25 +0100 Subject: [PATCH 011/244] stm32mp1: update RCC binding after kernel realignment RCC is no more a mfd and add a complete example and alignment with lastest TF-A binding Change-Id: Icb3a5f234a55e87e718a4e7cd2baea7cdbc80db0 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/116650 Reviewed-by: CIBUILD Reviewed-by: Nicolas LE BAYON Reviewed-by: CITOOLS --- .../clock/st,stm32mp1.txt | 427 ++++++++++++------ 1 file changed, 287 insertions(+), 140 deletions(-) diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt index 6a9397e1054a..02e14609bb77 100644 --- a/doc/device-tree-bindings/clock/st,stm32mp1.txt +++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt @@ -1,185 +1,186 @@ STMicroelectronics STM32MP1 clock tree initialization ===================================================== -The STM32MP clock tree initialization is based on device tree information -for RCC IP and on fixed clocks. +The STM32MP1 clock tree initialization is based on device tree information +for RCC IP node (st,stm32mp1-rcc) and on fixed-clock nodes. -------------------------------- -RCC CLOCK = st,stm32mp1-rcc-clk -------------------------------- +RCC IP = st,stm32mp1-rcc +======================== The RCC IP is both a reset and a clock controller but this documentation only describes the fields added for clock tree initialization which are not present -in Linux binding. +in Linux binding for compatible "st,stm32mp1-rcc" defined in st,stm32mp1-rcc.txt +file. -Please refer to ../mfd/st,stm32-rcc.txt for all the other properties common -with Linux. +The added properties for clock tree initialization are: Required properties: +- st,clksrc : The clock sources configuration array in a platform specific + order. -- compatible: Should be "st,stm32mp1-rcc-clk" + For the STM32MP15x family there are 9 clock sources selector which are + configured in the following order: + MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2 -- st,clksrc : The clock source in this order + Clock source configuration values are defined by macros CLK__ + from dt-bindings/clock/stm32mp1-clksrc.h. - for STM32MP15x: 9 clock sources are requested - MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2 - - with value equals to RCC clock specifier as defined in - dt-bindings/clock/stm32mp1-clksrc.h: CLK__ - -- st,clkdiv : The div parameters in this order - for STM32MP15x: 11 dividers value are requested + Example: + 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 : The clock main dividers value specified in an array + in a platform specific order. + + When used, it shall describe the whole clock dividers tree. + + For the STM32MP15x family there are 11 dividers values expected. + They shall be configured in the following order: MPU AXI MCU APB1 APB2 APB3 APB4 APB5 RTC MCO1 MCO2 - with DIV coding defined in RCC associated register RCC_xxxDIVR - - most the case, it is: + The each divider value uses the DIV coding defined in RCC associated + register RCC_xxxDIVR. In most the case, it is: 0x0: not divided 0x1: division by 2 0x2: division by 4 0x3: division by 8 ... - but for RTC MCO1 MCO2, the coding is different: + Note that for RTC MCO1 MCO2, the coding is different: 0x0: not divided 0x1: division by 2 0x2: division by 3 0x3: division by 4 ... -Optional Properties: -- st,pll - PLL children node for PLL1 to PLL4 : (see ref manual for details) - with associated index 0 to 3 (st,pll@0 to st,pll@4) - PLLx is off when the associated node is absent + Example: + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; - - Sub-nodes: +Optional Properties: +- st,pll : A specific PLL configuration, including frequency. - - cfg: The parameters for PLL configuration in this order: - DIVM DIVN DIVP DIVQ DIVR Output + PLL children nodes for PLL1 to PLL4 (see ref manual for details) + are listed with associated index 0 to 3 (st,pll@0 to st,pll@3). + PLLx is off when the associated node is absent. - with DIV value as defined in RCC spec: - 0x0: bypass (division by 1) - 0x1: division by 2 - 0x2: division by 3 - 0x3: division by 4 - ... + Here are the available properties for each PLL node: - and Output = bitfield for each output value = 1:ON/0:OFF - BIT(0) => output P : DIVPEN - BIT(1) => output Q : DIVQEN - BIT(2) => output R : DIVREN - NB : macro PQR(p,q,r) can be used to build this value - with p,p,r = 0 or 1 + - cfg: The parameters for PLL configuration in the following order: + DIVM DIVN DIVP DIVQ DIVR Output. - - frac : Fractional part of the multiplication factor - (optional, PLL is in integer mode when absent) + DIVx values are defined as in RCC spec: + 0x0: bypass (division by 1) + 0x1: division by 2 + 0x2: division by 3 + 0x3: division by 4 + ... - - csg : Clock Spreading Generator (optional) - with parameters in this order: - MOD_PER INC_STEP SSCG_MODE + Output contains a bitfield for each output value (1:ON/0:OFF) + BIT(0) => output P : DIVPEN + BIT(1) => output Q : DIVQEN + BIT(2) => output R : DIVREN + NB: macro PQR(p,q,r) can be used to build this value + with p,q,r = 0 or 1. + + - frac : Fractional part of the multiplication factor + (optional, PLL is in integer mode when absent). + + - csg : Clock Spreading Generator (optional) with parameters in the + following order: MOD_PER INC_STEP SSCG_MODE. + + MOD_PER: Modulation Period Adjustment + INC_STEP: Modulation Depth Adjustment + SSCG_MODE: Spread spectrum clock generator mode, with associated + defined from stm32mp1-clksrc.h: + - SSCG_MODE_CENTER_SPREAD = 0 + - SSCG_MODE_DOWN_SPREAD = 1 + + Example: + st,pll@0 { + cfg = < 1 53 0 0 0 1 >; + frac = < 0x810 >; + }; + st,pll@1 { + cfg = < 1 43 1 0 0 PQR(0,1,1) >; + csg = < 10 20 1 >; + }; + st,pll@2 { + cfg = < 2 85 3 13 3 0 >; + csg = < 10 20 SSCG_MODE_CENTER_SPREAD >; + }; + st,pll@3 { + cfg = < 2 78 4 7 9 3 >; + }; - * MOD_PER: Modulation Period Adjustment - * INC_STEP: Modulation Depth Adjustment - * SSCG_MODE: Spread spectrum clock generator mode - you can use associated defines from stm32mp1-clksrc.h - * SSCG_MODE_CENTER_SPREAD = 0 - * SSCG_MODE_DOWN_SPREAD = 1 +- st,pkcs : used to configure the peripherals kernel clock selection. + The property is a list of peripheral kernel clock source identifiers defined + by macros CLK__ as defined by header file + dt-bindings/clock/stm32mp1-clksrc.h. -- st,pkcs : used to configure the peripherals kernel clock selection - containing a list of peripheral kernel clock source identifier as defined - in the file dt-bindings/clock/stm32mp1-clksrc.h + st,pkcs may not list all the kernel clocks and has no ordering requirements. Example: + st,pkcs = < + CLK_STGEN_HSE + CLK_CKPER_HSI + CLK_USBPHY_PLL2P + CLK_DSI_PLL2Q + CLK_I2C46_HSI + CLK_UART1_HSI + CLK_UART24_HSI + >; - rcc: rcc@50000000 { - compatible = "syscon", "simple-mfd"; - - reg = <0x50000000 0x1000>; - - rcc_clk: rcc-clk@50000000 { - #clock-cells = <1>; - compatible = "st,stm32mp1-rcc-clk"; - - st,clksrc = < CLK_MPU_PLL1P - CLK_AXI_PLL2P - CLK_MCU_HSI - CLK_PLL12_HSE - CLK_PLL3_HSE - CLK_PLL4_HSE - CLK_RTC_HSE - CLK_MCO1_DISABLED - CLK_MCO2_DISABLED - >; - - st,clkdiv = < - 1 /*MPU*/ - 0 /*AXI*/ - 0 /*MCU*/ - 1 /*APB1*/ - 1 /*APB2*/ - 1 /*APB3*/ - 1 /*APB4*/ - 5 /*APB5*/ - 23 /*RTC*/ - 0 /*MCO1*/ - 0 /*MCO2*/ - >; - - st,pll@0 { - cfg = < 1 53 0 0 0 1 >; - frac = < 0x810 >; - }; - st,pll@1 { - cfg = < 1 43 1 0 0 PQR(0,1,1)>; - csg = <10 20 1>; - }; - st,pll@2 { - cfg = < 2 85 3 13 3 0>; - csg = <10 20 SSCG_MODE_CENTER_SPREAD>; - }; - st,pll@3 { - cfg = < 2 78 4 7 9 3>; - }; - st,pkcs = < - CLK_STGEN_HSE - CLK_CKPER_HSI - CLK_USBPHY_PLL2P - CLK_DSI_PLL2Q - >; - }; - }; - --------------------------- other clocks = fixed-clock --------------------------- +========================== + The clock tree is also based on 5 fixed-clock in clocks node used to define the state of associated ST32MP1 oscillators: -- clk-lsi -- clk-lse -- clk-hsi -- clk-hse -- clk-csi + - clk-lsi + - clk-lse + - clk-hsi + - clk-hse + - clk-csi At boot the clock tree initialization will -- enable the oscillator present in device tree -- disable HSI oscillator if the node is absent (always activated by bootrom) + - enable oscillators present in device tree + - disable HSI oscillator if the node is absent (always activated by bootrom) Optional properties : a) for external oscillator: "clk-lse", "clk-hse" - 4 optional fields are managed - - "st,bypass" Configure the oscillator bypass mode (HSEBYP, LSEBYP) - - "st,digbypass" Configure the bypass mode as full-swing digital signal - (DIGBYP) - - "st,css" Activate the clock security system (HSECSSON, LSECSSON) - - "st,drive" (only for LSE) value of the drive for the oscillator - (see LSEDRV_ define in the file dt-bindings/clock/stm32mp1-clksrc.h) - - Example board file: + 4 optional fields are managed + - "st,bypass" configures the oscillator bypass mode (HSEBYP, LSEBYP) + - "st,digbypass" configures the bypass mode as full-swing digital + signal (DIGBYP) + - "st,css" activates the clock security system (HSECSSON, LSECSSON) + - "st,drive" (only for LSE) contains the value of the drive for the + oscillator (see LSEDRV_ defined in the file + dt-bindings/clock/stm32mp1-clksrc.h) + Example board file: / { clocks { clk_hse: clk-hse { @@ -200,13 +201,12 @@ a) for external oscillator: "clk-lse", "clk-hse" b) for internal oscillator: "clk-hsi" - internally HSI clock is fixed to 64MHz for STM32MP157 soc - in device tree clk-hsi is the clock after HSIDIV (ck_hsi in RCC doc) - So this clock frequency is used to compute the expected HSI_DIV - for the clock tree initialisation - - ex: for HSIDIV = /1 + Internally HSI clock is fixed to 64MHz for STM32MP157 SoC. + In device tree, clk-hsi is the clock after HSIDIV (clk_hsi in RCC + doc). So this clock frequency is used to compute the expected HSI_DIV + for the clock tree initialization. + Example with HSIDIV = /1: / { clocks { clk_hsi: clk-hsi { @@ -216,8 +216,7 @@ b) for internal oscillator: "clk-hsi" }; }; - ex: for HSIDIV = /2 - + Example with HSIDIV = /2 / { clocks { clk_hsi: clk-hsi { @@ -226,3 +225,151 @@ b) for internal oscillator: "clk-hsi" clock-frequency = <32000000>; }; }; + +Example of clock tree initialization +==================================== + +/ { + clocks { + u-boot,dm-pre-reloc; + clk_hse: clk-hse { + u-boot,dm-pre-reloc; + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + st,digbypass; + }; + + clk_hsi: clk-hsi { + u-boot,dm-pre-reloc; + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <64000000>; + }; + + clk_lse: clk-lse { + u-boot,dm-pre-reloc; + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + + clk_lsi: clk-lsi { + u-boot,dm-pre-reloc; + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32000>; + }; + + clk_csi: clk-csi { + u-boot,dm-pre-reloc; + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <4000000>; + }; + }; + + soc { + + rcc: rcc@50000000 { + u-boot,dm-pre-reloc; + compatible = "st,stm32mp1-rcc", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + interrupts = ; + + 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; + }; + }; + }; +}; From a120b9bdb3e656bb2f0485924d77d58e2281311a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 23 Jan 2019 13:38:41 +0100 Subject: [PATCH 012/244] Prepare v2018.11-stm32mp-r2 U-Boot v2018.11 delivery for STMP32MP15x Series support For build details see board/st/stm32mp1/README - add architecture stm32mp (arch/arm/mach-stm32mp) with STMP32MP15x Serie support - add the STMicroelectronics board stm32mp1 (board/st/stm32mp1). This generic board supports all the bootable devices for all STM32MP1 boards with generic distribution feature (CONFIG_DISTRO). The supported bootable devices are: + SDCard + eMMC + NOR (SF) + NAND devices - Add device tree for the supported boards + stm32mp157c-ev1 + stm32mp157c-ed1 + stm32mp157a-dk1 + stm32mp157c-dk2 - Add defconfig for the 2 supported boot chain : ROM code => FSBL => SSBL => OS (Linux Kernel) SYSRAM DDR with First Stage Bootloader (FSBL) and Second Stage Bootloader (SSBL) + The "Trusted" boot chain (defconfig_file : stm32mp15_trusted_defconfig) ROM code => FSBL = Trusted Firmware-A (TF-A) => SSBL = U-Boot + The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig) ROM code => FSBL = U-Boot SPL => SSBL = U-Boot - Add/Supports drivers in U-Boot: + RCC drivers for Clock, Reset, Sysreset * drivers/clk/clk_stm32mp1.c * drivers/reset/stm32-reset.c + GPIO (drivers/gpio/stm32f7_gpio.c) + PINCONTROL (drivers/pinctrl/pinctrl_stm32.c) + UART/USART (drivers/serial/serial_stm32.c) + DDR controller and PHY (drivers/ram/stm32mp1) + SDCard/MMC controller = SDMMC (drivers/mmc/stm32_sdmmc2.c) + NAND controller FMC (drivers/mtd/nand/raw/stm32_fmc2_nand.c) + NOR controller QSPI (drivers/spi/stm32_qspi.c) + USB OTG controller (OTG DWC2) and PHY (USBPHYC) * drivers/phy/phy-stm32-usbphyc.c * drivers/usb/gadget/dwc2_udc_otg.c * drivers/usb/gadget/gen_udc_otg_phy.c * drivers/usb/host/dwc2.c + ETH (drivers/net/dwc_eth_qos.c) + I2C (drivers/i2c/stm32f7_i2c.c) + PWR regulator (arch/arm/mach-stm32mp/pwr_regulator.c) + VREF regulator (drivers/power/regulator/stm32-vrefbuf.c) + STPMIC1 (PMIC and regulator) * drivers/power/pmic/stpmic1.c * drivers/power/regulator/stpmic1.c + BSEC for OTP (arch/arm/mach-stm32mp/bsec.c) + WATCHDOG (drivers/watchdog/stm32mp_wdt.c) + ADC (drivers/adc/stm32-adc.c and stm32-adc-core.c) + HWSINLOCK (drivers/hwspinlock/stm32_hwspinlock.c) + IPCC mailbox (drivers/mailbox/stm32-ipcc.c) + VIDEO drivers for LTDC and DSI * drivers/video/stm32/stm32_dsi.c * drivers/video/stm32/stm32_ltdc.c + Panels drivers * drivers/video/dw_mipi_dsi.c * drivers/video/mipi_display.c * drivers/video/orisetech_otm8009a.c * drivers/video/raydium-rm68200.c + SYSCFG init (in board: board/st/stm32mp1/stm32mp1.c) + STMFX gpio expendeur (drivers/pinctrl/pinctrl-stmfx.c) - Added, supported or modified commands are + stm32prog for STM32CubeProgrammer tools support (USB or UART) in U-Boot (arch/arm/mach-stm32mp/cmd_stm32prog) + rproc for M4 firmware load (drivers/remoteproc/stm32_copro.c) + fuse support with 2 banks for OTP (BSEC) and STMPIC1 non volatile memory (drivers/misc/stm32mp_fuse.c) + poweroff (arch/arm/mach-stm32mp/cmd_poweroff.c) + stm32key (arch/arm/mach-stm32mp/cmd_stm32key.c) Information - savenv is not supported (CONFIG_ENV_IS_NOWHERE is activated by default) - boot from NAND is not supported for basic boot Change-Id: Iac367a1a414b5444a0800e0e88839b54c341355e Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/115489 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 84cb3727e10e..693ffaeb04fe 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r1 +EXTRAVERSION = -stm32mp-r2 NAME = # *DOCUMENTATION* From b6d9a0f0caa8be76a29bde69974107f4729d46e1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 29 Jan 2019 15:26:33 +0100 Subject: [PATCH 013/244] stm32mp1: clk: correctly handle Clock Spreading Generator To activate the csg option, the driver need to set the bit2 of PLLNCR register = SSCG_CTRL: Spread Spectrum Clock Generator of PLLn enable. Change-Id: Id93643ef505310bef65e0e025753abc0da7ba43e Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119871 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/clk/clk_stm32mp1.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 79f834b77b1f..20156acbd6a7 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -171,6 +171,7 @@ DECLARE_GLOBAL_DATA_PTR; /* used for ALL PLLNCR registers */ #define RCC_PLLNCR_PLLON BIT(0) #define RCC_PLLNCR_PLLRDY BIT(1) +#define RCC_PLLNCR_SSCG_CTRL BIT(2) #define RCC_PLLNCR_DIVPEN BIT(4) #define RCC_PLLNCR_DIVQEN BIT(5) #define RCC_PLLNCR_DIVREN BIT(6) @@ -1340,7 +1341,10 @@ static void pll_start(struct stm32mp1_clk_priv *priv, int pll_id) { const struct stm32mp1_clk_pll *pll = priv->data->pll; - writel(RCC_PLLNCR_PLLON, priv->base + pll[pll_id].pllxcr); + clrsetbits_le32(priv->base + pll[pll_id].pllxcr, + RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | + RCC_PLLNCR_DIVREN, + RCC_PLLNCR_PLLON); } static int pll_output(struct stm32mp1_clk_priv *priv, int pll_id, int output) @@ -1459,6 +1463,8 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg) RCC_PLLNCSGR_SSCG_MODE_MASK); writel(pllxcsg, priv->base + pll[pll_id].pllxcsgr); + + setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL); } static __maybe_unused int pll_set_rate(struct udevice *dev, From aaef786348f01013c2d30ceeaef54422ae097a85 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 28 Jan 2019 19:02:23 +0100 Subject: [PATCH 014/244] stm32mp1: correct management for SYSCFG.BOOTR Correct bit operation (miss-placed parenthesis) and add define for register bits of SYSCFG_BOOTR register. Change-Id: I05d52be3c8ce4016ed8e56b91c8fcc02b311a104 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119872 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/stm32mp1.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 5dc62965b092..1c282eb19bae 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -37,6 +37,9 @@ #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) @@ -451,7 +454,8 @@ static void sysconf_init(void) /* disable Pull-Down for boot pin connected to VDD */ bootr = readl(syscfg + SYSCFG_BOOTR); - bootr |= (bootr & 0x7 << 4); + bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT); + bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT; writel(bootr, syscfg + SYSCFG_BOOTR); debug("[0x%x] SYSCFG.bootr = 0x%08x\n", (u32)syscfg + SYSCFG_BOOTR, readl(syscfg + SYSCFG_BOOTR)); From 3de73fb9d1868566d761f2108101d3bb5e8a6ec7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 17 Jan 2019 18:35:11 +0100 Subject: [PATCH 015/244] stm32mp1: basic boot: SPL enable access to GPIOZ bank SPL need to set GPIOZ_SECCFGR = 0 to enable access to GPIOZ bank (open security). Change-Id: I33f322625c31c9f05ab5a8eca9f7ca30adaabd71 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119874 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- 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 5d5ce4a50107..24f72a18ec15 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -22,6 +22,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) @@ -49,6 +50,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 @@ -142,6 +146,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 */ From 146431276cc356515dc67f8b6ec08c24b41b217e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 6 Feb 2019 15:46:44 +0100 Subject: [PATCH 016/244] net: dwc_eth_qos: Fix error path return value In two error cases, eqos_probe() returns 0 as return value. Force ret variable with correct value. Change-Id: Ie7808bd6b83515465be4e578fc629024d909d18a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/120660 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 072b8c80b141..a523465af102 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1721,6 +1721,7 @@ static int eqos_probe(struct udevice *dev) eqos->mii = mdio_alloc(); if (!eqos->mii) { pr_err("mdio_alloc() failed"); + ret = -ENOMEM; goto err_remove_resources_tegra; } eqos->mii->read = eqos_mdio_read; @@ -1745,6 +1746,7 @@ static int eqos_probe(struct udevice *dev) eqos->config->interface(dev)); if (!eqos->phy) { pr_err("phy_connect() failed"); + ret = -ENODEV; goto err_stop_resets; } ret = phy_config(eqos->phy); From 76eea16eb02fa03e3cd846698be1d958151046d9 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 4 Feb 2019 13:57:51 +0100 Subject: [PATCH 017/244] Revert "net: dwc_eth_qos: initialize PHY in probe() once" Issue detected when executing command "dhcp" twice with no ethernet cable plugged. First "dhcp" execution, phy_startup() failed then eqos->phy is set to NULL. Second "dhcp" execution, eqos->phy is still NULL and phy_startup() is called and crashed due to NULL pointer. Reverting this patch restores a correct behaviour. This reverts commit 0a465ee1f6230797ceee213743ef89e30fe2e98f. Change-Id: I3f0c84a2fdef06c7796940f88972cfff9e2cdbf2 Reviewed-on: https://gerrit.st.com/125865 Reviewed-by: CITOOLS Tested-by: Patrice CHOTARD Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 60 ++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index a523465af102..e45f0b894382 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1004,10 +1004,16 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; + ret = eqos->config->ops->eqos_start_clks(dev); + if (ret < 0) { + pr_err("eqos_start_clks() failed: %d", ret); + goto err; + } + ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { pr_err("eqos_start_resets() failed: %d", ret); - goto err; + goto err_stop_clks; } udelay(10); @@ -1031,6 +1037,17 @@ static int eqos_start(struct udevice *dev) val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); + eqos->phy = phy_connect(eqos->mii, 0, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -1258,6 +1275,8 @@ static int eqos_start(struct udevice *dev) eqos->phy = NULL; err_stop_resets: eqos->config->ops->eqos_stop_resets(dev); +err_stop_clks: + eqos->config->ops->eqos_stop_clks(dev); err: pr_err("FAILED: %d", ret); return ret; @@ -1308,7 +1327,12 @@ void eqos_stop(struct udevice *dev) clrbits_le32(&eqos->dma_regs->ch0_rx_control, EQOS_DMA_CH0_RX_CONTROL_SR); + if (eqos->phy) { + phy_shutdown(eqos->phy); + eqos->phy = NULL; + } eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); debug("%s: OK\n", __func__); } @@ -1735,35 +1759,9 @@ static int eqos_probe(struct udevice *dev) goto err_free_mdio; } - // Bring up PHY - ret = eqos->config->ops->eqos_start_clks(dev); - if (ret < 0) { - pr_err("eqos_start_clks() failed: %d", ret); - goto err_free_mdio; - } - - eqos->phy = phy_connect(eqos->mii, 0, dev, - eqos->config->interface(dev)); - if (!eqos->phy) { - pr_err("phy_connect() failed"); - ret = -ENODEV; - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; - } - debug("%s: OK\n", __func__); return 0; -err_shutdown_phy: - phy_shutdown(eqos->phy); - eqos->phy = NULL; -err_stop_resets: - eqos->config->ops->eqos_stop_resets(dev); - eqos->config->ops->eqos_stop_clks(dev); err_free_mdio: mdio_free(eqos->mii); err_remove_resources_tegra: @@ -1783,14 +1781,6 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); - - if (eqos->phy) { - phy_shutdown(eqos->phy); - eqos->phy = NULL; - } - - eqos->config->ops->eqos_stop_resets(dev); - eqos->config->ops->eqos_stop_clks(dev); eqos->config->ops->eqos_remove_resources(dev); eqos_probe_resources_core(dev); From b4172191365fd2ca9e4b625ca5f5b65b236fa525 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 6 Feb 2019 11:56:09 +0100 Subject: [PATCH 018/244] configs: stm32mp15: no need to select PHY_FIXED By default we use the Generic PHY, no need to select PHY_FIXED. So remove it. Change-Id: I18abe24d61cab1dd883566bb3c4a1c86c2c03758 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125866 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 1 - configs/stm32mp15_optee_defconfig | 1 - configs/stm32mp15_trusted_defconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index ad3424e844f9..d04e1d74fcae 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -74,7 +74,6 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y -CONFIG_PHY_FIXED=y CONFIG_DM_ETH=y CONFIG_DWC_ETH_QOS=y CONFIG_PHY=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index a24727c8d624..076eab61b282 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -64,7 +64,6 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y -CONFIG_PHY_FIXED=y CONFIG_DM_ETH=y CONFIG_DWC_ETH_QOS=y CONFIG_PHY=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index e41506ba9c45..90a6adc46d0c 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -63,7 +63,6 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y -CONFIG_PHY_FIXED=y CONFIG_DM_ETH=y CONFIG_DWC_ETH_QOS=y CONFIG_PHY=y From 72b346ed2474ad5b52754a1fb1141054c905b9d0 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 6 Feb 2019 14:51:16 +0100 Subject: [PATCH 019/244] net: dwc_eth_qos: Don't reconnect phy if previously done This avoid to connect and configure an already configured PHY and more precisely autonegotiation steps which takes several seconds. Change-Id: Ie0b0f343f547508c32282d3f010fc98a51640075 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125867 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index e45f0b894382..dddbf1f546b6 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1037,17 +1037,24 @@ static int eqos_start(struct udevice *dev) val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); - eqos->phy = phy_connect(eqos->mii, 0, dev, - eqos->config->interface(dev)); + /* + * if PHY was already connected and configured, + * don't need to reconnect/reconfigure again + */ if (!eqos->phy) { - pr_err("phy_connect() failed"); - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; + eqos->phy = phy_connect(eqos->mii, 0, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } } + ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -1272,7 +1279,6 @@ static int eqos_start(struct udevice *dev) err_shutdown_phy: phy_shutdown(eqos->phy); - eqos->phy = NULL; err_stop_resets: eqos->config->ops->eqos_stop_resets(dev); err_stop_clks: @@ -1329,7 +1335,6 @@ void eqos_stop(struct udevice *dev) if (eqos->phy) { phy_shutdown(eqos->phy); - eqos->phy = NULL; } eqos->config->ops->eqos_stop_resets(dev); eqos->config->ops->eqos_stop_clks(dev); From 6b420c01c28b4b1b314e12c0e9fea76530d2626d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 29 Jan 2019 09:46:21 +0100 Subject: [PATCH 020/244] stm32mp1: skip sysconf init in trusted mode This part is done in TF-A in trusted mode. Change-Id: I3087e8a8d64200cdbbb5c979a99cf85457c2ee54 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/120673 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/stm32mp1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 1c282eb19bae..ab64f410b96f 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -431,6 +431,7 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) static void sysconf_init(void) { +#ifndef CONFIG_STM32MP1_TRUSTED u8 *syscfg; #ifdef CONFIG_DM_REGULATOR struct udevice *pwr_dev; @@ -529,6 +530,7 @@ static void sysconf_init(void) debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n", (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR)); +#endif } /* board interface eth init */ From e3a6e5a5e6741910e344919c321d39711384f641 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 30 Jan 2019 09:54:32 +0100 Subject: [PATCH 021/244] cmd: fastboot: add reload of watchdog Add reload of watchdog for fastboot command, as it was done for DFU in run_usb_dnl_gadget() Change-Id: If24f5763db534fa440675f2e5b75a7684e6471d1 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119945 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- cmd/fastboot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/fastboot.c b/cmd/fastboot.c index ae3a5f627f11..e3d67b2159b2 100644 --- a/cmd/fastboot.c +++ b/cmd/fastboot.c @@ -13,6 +13,7 @@ #include #include #include +#include static int do_fastboot_udp(int argc, char *const argv[], uintptr_t buf_addr, size_t buf_size) @@ -74,6 +75,7 @@ static int do_fastboot_usb(int argc, char *const argv[], break; if (ctrlc()) break; + WATCHDOG_RESET(); usb_gadget_handle_interrupts(controller_index); } From afbdd009be92e1020a5931b273b1b6ec8751ae12 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 13 Feb 2019 11:51:15 +0100 Subject: [PATCH 022/244] stm32mp1: update bootcmd Clearly separate bootcmd for stm32mp1 board (bootcmd_stm32mp) and preboot management. That solve issue for fastboot continue command. Change-Id: Ifbb9eadbc9dd0c0bed13fb88dc06feb809990afa Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125562 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/cpu.c | 13 ++++++++----- include/configs/stm32mp1.h | 32 ++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 24f72a18ec15..8d8ade38e992 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -407,14 +407,16 @@ static void setup_boot_mode(void) env_set("boot_instance", cmd); break; case BOOT_FLASH_NAND: - sprintf(cmd, "%d", instance); env_set("boot_device", "nand"); - env_set("boot_instance", cmd); + env_set("boot_instance", "0"); break; case BOOT_FLASH_NOR: env_set("boot_device", "nor"); env_set("boot_instance", "0"); break; + default: + pr_debug("unexpected boot mode = %x\n", boot_mode); + break; } switch (forced_mode) { @@ -423,8 +425,8 @@ static void setup_boot_mode(void) env_set("preboot", "env set preboot; fastboot 0"); break; case BOOT_STM32PROG: - printf("Enter STM32CubeProgrammer mode!\n"); - env_set("preboot", "env set preboot; stm32prog usb 0"); + env_set("boot_device", "usb"); + env_set("boot_instance", "0"); break; case BOOT_UMS_MMC0: case BOOT_UMS_MMC1: @@ -438,8 +440,9 @@ static void setup_boot_mode(void) env_set("preboot", "env set preboot; run altbootcmd"); break; case BOOT_NORMAL: + break; default: - pr_debug("unexpected boot mode = %x\n", boot_mode); + pr_debug("unexpected forced boot mode = %x\n", forced_mode); break; } diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index b4beaa757f64..abbfe3f3d03c 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -130,20 +130,27 @@ func(MMC, mmc, 2) \ func(PXE, pxe, na) -#include +/* + * 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 +#undef CONFIG_BOOTCOMMAND +#define CONFIG_BOOTCOMMAND "echo \"Boot over ${boot_device}${boot_instance}!\";run bootcmd_stm32mp" -#define CONFIG_PREBOOT \ - "echo \"Boot over ${boot_device}${boot_instance}!\"; " \ - "if test ${boot_device} = serial; then " \ - "stm32prog serial ${boot_instance}; " \ - "else if test ${boot_device} = usb; then " \ - "stm32prog usb ${boot_instance}; " \ +#define STM32MP_BOOTCMD "bootcmd_stm32mp=" \ + "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}\"; "\ - "else if test ${boot_device} = nand; then " \ - "env set boot_targets \"ubifs0\"; "\ - "fi; fi; fi; fi;" + "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" + +#include #ifdef CONFIG_STM32MP1_OPTEE #define CONFIG_SYS_MEM_TOP_HIDE SZ_32M @@ -181,6 +188,7 @@ "bootlimit=0\0" \ "altbootcmd=run bootcmd\0" \ "usb_pgood_delay=2000\0" \ + STM32MP_BOOTCMD \ STM32MP_MTDPARTS \ BOOTENV \ "boot_net_usb_start=true\0" From f9171debe03783075cf270df5a23adf5a4d35da2 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 6 Feb 2019 14:06:12 +0100 Subject: [PATCH 023/244] dts: alignment with v4.19-stm32mp-r1 Device tree alignment with the latest labels: + v4.19-stm32mp-r1 Change-Id: Ia2dc2a012c6e6bb6db6bb5ef5063715f33adf173 Reviewed-on: https://gerrit.st.com/120639 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 73 ++++++++++++++++++++++++ arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 7 --- arch/arm/dts/stm32mp157a-dk1.dts | 25 +++++++- arch/arm/dts/stm32mp157c-dk2.dts | 7 ++- arch/arm/dts/stm32mp157c-ed1.dts | 2 +- arch/arm/dts/stm32mp157c.dtsi | 38 +++++++----- 6 files changed, 127 insertions(+), 25 deletions(-) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 183d7ba7ebd7..6e4e5c923f2a 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -1249,6 +1249,49 @@ }; }; + sdmmc2_b4_pins_b: sdmmc2-b4-1 { + pins1 { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ + ; /* SDMMC2_CMD */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* SDMMC2_CK */ + slew-rate = <2>; + drive-push-pull; + bias-disable; + }; + }; + + sdmmc2_b4_od_pins_b: sdmmc2-b4-od-1 { + pins1 { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + ; /* SDMMC2_D3 */ + slew-rate = <1>; + drive-push-pull; + bias-disable; + }; + pins2 { + pinmux = ; /* SDMMC2_CK */ + slew-rate = <2>; + drive-push-pull; + bias-disable; + }; + pins3 { + pinmux = ; /* SDMMC2_CMD */ + slew-rate = <1>; + drive-open-drain; + bias-disable; + }; + }; + sdmmc2_d47_pins_a: sdmmc2-d47-0 { pins { pinmux = , /* SDMMC2_D4 */ @@ -1413,6 +1456,36 @@ }; }; + uart7_pins_a: uart7-0 { + pins1 { + pinmux = ; /* USART7_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* USART7_RX */ + bias-disable; + }; + }; + + uart7_idle_pins_a: uart7-idle-0 { + pins1 { + pinmux = ; /* USART7_TX */ + }; + pins2 { + pinmux = ; /* USART7_RX */ + bias-disable; + }; + }; + + uart7_sleep_pins_a: uart7-sleep-0 { + pins { + pinmux = , /* USART7_TX */ + ; /* USART7_RX */ + }; + }; + usart2_pins_a: usart2-0 { pins1 { pinmux = , /* USART2_TX */ diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 0f9ed9f47ac0..09794ba4dbe2 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -39,13 +39,6 @@ &i2c4 { u-boot,dm-pre-reloc; - - stusb1600: typec@28 { - #extcon-cells = <0>; - compatible = "st,stusb1600"; - reg = <0x28>; - status = "okay"; - }; }; &i2c4_pins_a { diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 8e0944797430..e3a36d3cdb45 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -20,6 +20,8 @@ aliases { ethernet0 = ðernet0; serial0 = &uart4; + serial1 = &usart3; + serial2 = &uart7; }; chosen { @@ -287,6 +289,19 @@ /delete-property/dmas; /delete-property/dma-names; + typec: stusb1600@28 { + compatible = "st,stusb1600"; + reg = <0x28>; + status = "okay"; + + typec_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "sink"; + power-opmode = "default"; + }; + }; + pmic: stpmic@33 { compatible = "st,stpmic1"; reg = <0x33>; @@ -297,7 +312,7 @@ st,main-control-register = <0x04>; st,vin-control-register = <0xc0>; - st,usb-control-register = <0x30>; + st,usb-control-register = <0x20>; regulators { compatible = "st,stpmic1-regulators"; @@ -658,6 +673,14 @@ status = "okay"; }; +&uart7 { + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&uart7_pins_a>; + pinctrl-1 = <&uart7_sleep_pins_a>; + pinctrl-2 = <&uart7_idle_pins_a>; + status = "disabled"; +}; + &usart3 { pinctrl-names = "default", "sleep", "idle"; pinctrl-0 = <&usart3_pins_b>; diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts index c276c59590fc..20a86f1b9abc 100644 --- a/arch/arm/dts/stm32mp157c-dk2.dts +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -14,7 +14,7 @@ compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; aliases { - serial1 = &usart2; + serial3 = &usart2; }; wifi_pwrseq: wifi-pwrseq { @@ -106,9 +106,10 @@ /* Wifi */ &sdmmc2 { + arm,primecell-periphid = <0x10153180>; pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc2_b4_pins_a>; - pinctrl-1 = <&sdmmc2_b4_od_pins_a>; + pinctrl-0 = <&sdmmc2_b4_pins_b>; + pinctrl-1 = <&sdmmc2_b4_od_pins_b>; pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; non-removable; st,neg-edge; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 0f70bb72266a..780c992a3ad7 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -188,7 +188,7 @@ st,main-control-register = <0x04>; st,vin-control-register = <0xc0>; - st,usb-control-register = <0x30>; + st,usb-control-register = <0x20>; regulators { compatible = "st,stpmic1-regulators"; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 4de499e1e409..5581a1cdbc5e 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -58,6 +58,7 @@ , ; interrupt-parent = <&intc>; + always-on; }; clocks { @@ -430,8 +431,8 @@ interrupts = ; clocks = <&rcc SPI2_K>; resets = <&rcc SPI2_R>; - dmas = <&dmamux1 39 0x400 0x05>, - <&dmamux1 40 0x400 0x05>; + dmas = <&dmamux1 39 0x400 0x01>, + <&dmamux1 40 0x400 0x01>; dma-names = "rx", "tx"; power-domains = <&pd_core>; status = "disabled"; @@ -456,8 +457,8 @@ interrupts = ; clocks = <&rcc SPI3_K>; resets = <&rcc SPI3_R>; - dmas = <&dmamux1 61 0x400 0x05>, - <&dmamux1 62 0x400 0x05>; + dmas = <&dmamux1 61 0x400 0x01>, + <&dmamux1 62 0x400 0x01>; dma-names = "rx", "tx"; power-domains = <&pd_core>; status = "disabled"; @@ -756,8 +757,8 @@ interrupts = ; clocks = <&rcc SPI1_K>; resets = <&rcc SPI1_R>; - dmas = <&dmamux1 37 0x400 0x05>, - <&dmamux1 38 0x400 0x05>; + dmas = <&dmamux1 37 0x400 0x01>, + <&dmamux1 38 0x400 0x01>; dma-names = "rx", "tx"; power-domains = <&pd_core>; status = "disabled"; @@ -782,8 +783,8 @@ interrupts = ; clocks = <&rcc SPI4_K>; resets = <&rcc SPI4_R>; - dmas = <&dmamux1 83 0x400 0x05>, - <&dmamux1 84 0x400 0x05>; + dmas = <&dmamux1 83 0x400 0x01>, + <&dmamux1 84 0x400 0x01>; dma-names = "rx", "tx"; power-domains = <&pd_core>; status = "disabled"; @@ -870,8 +871,8 @@ interrupts = ; clocks = <&rcc SPI5_K>; resets = <&rcc SPI5_R>; - dmas = <&dmamux1 85 0x400 0x05>, - <&dmamux1 86 0x400 0x05>; + dmas = <&dmamux1 85 0x400 0x01>, + <&dmamux1 86 0x400 0x01>; dma-names = "rx", "tx"; power-domains = <&pd_core>; status = "disabled"; @@ -892,6 +893,8 @@ compatible = "st,stm32-sai-sub-a"; reg = <0x4 0x1c>; + clocks = <&rcc SAI1_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 87 0x400 0x01>; status = "disabled"; }; @@ -900,6 +903,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; reg = <0x24 0x1c>; + clocks = <&rcc SAI1_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 88 0x400 0x01>; status = "disabled"; }; @@ -919,6 +924,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-a"; reg = <0x4 0x1c>; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 89 0x400 0x01>; status = "disabled"; }; @@ -927,6 +934,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; reg = <0x24 0x1c>; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 90 0x400 0x01>; status = "disabled"; }; @@ -946,6 +955,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-a"; reg = <0x04 0x1c>; + clocks = <&rcc SAI3_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 113 0x400 0x01>; status = "disabled"; }; @@ -954,6 +965,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; reg = <0x24 0x1c>; + clocks = <&rcc SAI3_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 114 0x400 0x01>; status = "disabled"; }; @@ -1221,7 +1234,6 @@ g-tx-fifo-size = <128 128 64 64 64 64 32 32>; dr_mode = "otg"; usb33d-supply = <&usb33>; - power-domains = <&pd_core>; status = "disabled"; }; @@ -1442,6 +1454,8 @@ #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; reg = <0x24 0x1c>; + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; dmas = <&dmamux1 100 0x400 0x01>; status = "disabled"; }; @@ -1756,7 +1770,6 @@ clocks = <&rcc USBH>; resets = <&rcc USBH_R>; interrupts = ; - power-domains = <&pd_core>; status = "disabled"; }; @@ -1767,7 +1780,6 @@ resets = <&rcc USBH_R>; interrupts = ; companion = <&usbh_ohci>; - power-domains = <&pd_core>; status = "disabled"; }; From 3cbc4657ac31d104d8366b6d35368c667efc8b27 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 25 Feb 2019 10:16:07 +0100 Subject: [PATCH 024/244] dts: alignment with v4.19-stm32mp-r1.1 Device tree alignment with the latest labels: + v4.19-stm32mp-r1.1 Change-Id: I56b20bed29da44f6aa57cd31320ca449cba5604b Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126378 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 7 +++++++ arch/arm/dts/stm32mp157a-dk1.dts | 5 +++++ arch/arm/dts/stm32mp157c.dtsi | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 6e4e5c923f2a..970a4105b170 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -1418,6 +1418,13 @@ }; }; + stusb1600_pins_a: stusb1600-0 { + pins { + pinmux = ; + bias-pull-up; + }; + }; + spi5_sleep_pins_a: spi5-sleep-0 { pins { pinmux = , /* SPI5_SCK */ diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index e3a36d3cdb45..1194e972510f 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -292,6 +292,11 @@ typec: stusb1600@28 { compatible = "st,stusb1600"; reg = <0x28>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpioi>; + pinctrl-names = "default"; + pinctrl-0 = <&stusb1600_pins_a>; + status = "okay"; typec_con: connector { diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 5581a1cdbc5e..6d3642d13095 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -556,6 +556,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x1>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x1>; status = "disabled"; }; @@ -575,6 +576,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x2>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x2>; status = "disabled"; }; @@ -594,6 +596,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x4>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x4>; status = "disabled"; }; @@ -613,6 +616,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x10>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x10>; status = "disabled"; }; @@ -1890,6 +1894,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x8>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x8>; status = "disabled"; }; @@ -1932,6 +1937,7 @@ dma-names = "rx", "tx"; power-domains = <&pd_core>; st,syscfg-fmp = <&syscfg 0x4 0x20>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x20>; status = "disabled"; }; From 62e1fc096910a58d1cf7ab5e9f0028307ae0990c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 18 Feb 2019 15:42:13 +0100 Subject: [PATCH 025/244] stm32mp1: clk: use the correct identifier for ethck ETHCK_K is the identifier the kernel clock for ETH in kernel binding, selected by ETHKSELR / gated by ETHCKEN = BIT(7). U-Boot driver need to use the same identifier, so change ETHCK to ETHCK_K. Change-Id: I8c8544168618709193838cd16cc20b193ca0760f Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125929 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe ROULLIER Tested-by: Christophe ROULLIER --- drivers/clk/clk_stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 20156acbd6a7..aecd004161c1 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -575,7 +575,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK, _ETH_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK_K, _ETH_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 9, ETHRX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK), From 161ca183f164d65e0c05affd618e07b85ab7edba Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 17:55:03 +0100 Subject: [PATCH 026/244] Prepare v2018.11-stm32mp-r2.1 Change-Id: I0b0cb81b650ac0c0d86154a54c00ab6c03fb47a5 Signed-off-by: Patrick Delaunay --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 693ffaeb04fe..e69c2ee90824 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2 +EXTRAVERSION = -stm32mp-r2.1 NAME = # *DOCUMENTATION* From 41b168d1cadcb75a8fd1c946d2f6d3cfcb3fe81e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 6 Feb 2019 15:54:10 +0100 Subject: [PATCH 027/244] ARM: dts: stm32: DDR config to v1.43 - fix LPDDR2/3 timing_calc to step RL/WL in relaxed timings mode - remove LPDDR3 RL3 (optional) support vs MR0[7] because MR0[7] can't be read instead always apply worse RL/WL for LPDDR3 when freq < 166MHz) - change MR3 to 48ohm drive for LPDDR2/3 - change default ZPROG[7:4] = 0x1 for LPDDR2/3 , '0' is not allowed even when ODT not used - use DQSTRN for LPDDR2/3 (it was not set in PIR) - LPDDR3: set dqsge/dwsgx gate extension to 2,2 like LPDDR2 -DDRCTRL.dfitmg0: + for LPDDR3 tphy_wrlat = WL (as LPDDR2) + improvement for relaxed mode vs RL/Wl at corner case. For example @533MHz RL/WL (relaxed) = 9/5 for LPDDR2/3 and correction to MR2 accordingly Change-Id: I28070897a5ca8fa5f2eb137ac40196cdfd6ebb81 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/120661 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi | 6 +++--- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 7 +++---- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi | 6 +++--- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 8 +++----- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi index da8331034294..307021906211 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ -/* STM32MP157C DK1/DK2 BOARD configuration + * + * STM32MP157C DK1/DK2 BOARD configuration * 1x DDR3L 4Gb, 16-bit, 533MHz. * Reference used NT5CC256M16DP-DI from NANYA * @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.41" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.43" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi index 16b8cf623be3..b86a1c02c941 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ -/* STM32MP157C DK1/DK2 BOARD configuration + * + * STM32MP157C DK1/DK2 BOARD configuration * 1x DDR3L 4Gb, 16-bit, 533MHz. * Reference used NT5CC256M16DP-DI from NANYA * @@ -16,8 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ - -#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.41" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.43" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi index 82781e713b81..066d4e3b78da 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ -/* STM32MP157C ED1 BOARD configuration + * + * STM32MP157C ED1 BOARD configuration * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. * Reference used NT5CC256M16DP-DI from NANYA * @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.41" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.43" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi index 82e710468d5c..260cfd6a7486 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ - -/* STM32MP157C ED1 BOARD configuration + * + * STM32MP157C ED1 BOARD configuration * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. * Reference used NT5CC256M16DP-DI from NANYA * @@ -17,8 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ - -#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.41" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.43" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 From e3614a1c5c56cdac07946fbf157e0ba9aef515d3 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 6 Mar 2019 17:02:02 +0100 Subject: [PATCH 028/244] ARM: dts: stm32: DDR config to v1.44 PUBL_regs: DXnGCR[0]= according to ddr_width to disable Byte lane 2/3 in 16bit Change-Id: I3a40805de6d1a245dcad45e4663e5f9e8010d93e Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/127270 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi | 6 +++--- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 6 +++--- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi | 2 +- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi index 307021906211..e22b3fea67fa 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.43" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.44" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 @@ -108,11 +108,11 @@ #define DDR_DX1DLLCR 0x40000000 #define DDR_DX1DQTR 0xFFFFFFFF #define DDR_DX1DQSTR 0x3DB02000 -#define DDR_DX2GCR 0x0000CE81 +#define DDR_DX2GCR 0x0000CE80 #define DDR_DX2DLLCR 0x40000000 #define DDR_DX2DQTR 0xFFFFFFFF #define DDR_DX2DQSTR 0x3DB02000 -#define DDR_DX3GCR 0x0000CE81 +#define DDR_DX3GCR 0x0000CE80 #define DDR_DX3DLLCR 0x40000000 #define DDR_DX3DQTR 0xFFFFFFFF #define DDR_DX3DQSTR 0x3DB02000 diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi index b86a1c02c941..dc30360b0a41 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.43" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.44" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 @@ -108,11 +108,11 @@ #define DDR_DX1DLLCR 0x40000000 #define DDR_DX1DQTR 0xFFFFFFFF #define DDR_DX1DQSTR 0x3DB02000 -#define DDR_DX2GCR 0x0000CE81 +#define DDR_DX2GCR 0x0000CE80 #define DDR_DX2DLLCR 0x40000000 #define DDR_DX2DQTR 0xFFFFFFFF #define DDR_DX2DQSTR 0x3DB02000 -#define DDR_DX3GCR 0x0000CE81 +#define DDR_DX3GCR 0x0000CE80 #define DDR_DX3DLLCR 0x40000000 #define DDR_DX3DQTR 0xFFFFFFFF #define DDR_DX3DQSTR 0x3DB02000 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi index 066d4e3b78da..99dbc6e2bd85 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.43" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.44" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi index 260cfd6a7486..772ef7d03a9c 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.43" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.44" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 From dafa5e1643c1b8e194ff7e1848af84717e9ac890 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 28 Feb 2019 14:36:50 +0100 Subject: [PATCH 029/244] clk: stm32mp1: Fix msk value for stm32mp1_clk_sel array Change-Id: I45f9a75a7b08202b753ba3b4d6bc9aa7b121ccf4 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126713 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/clk/clk_stm32mp1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index aecd004161c1..96595504150c 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -626,13 +626,13 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), STM32MP1_CLK_PARENT(_ETH_SEL, RCC_ETHCKSELR, 0, 0x3, eth_parents), - STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), - STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), + STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0x3, qspi_parents), + STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0x3, fmc_parents), STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), - STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), + STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT From aacb637b69faa7b5c444386758b1b59c4089329d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 26 Mar 2019 09:57:33 +0100 Subject: [PATCH 030/244] ARM: dts: stm32: update power supply of rm68200 on stm32mp157c-ev1 Supply of panel rm68200 has been modified (1v8 > 3v3). Property power-supply need also to be modified. Change-Id: I603e160c0c531f80f765934fad8f3c1b3dd2c0c6 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/128878 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157c-ev1.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 18742e83f159..9f0ee3d16388 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -330,7 +330,7 @@ compatible = "raydium,rm68200"; reg = <0>; reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; - power-supply = <&v1v8>; + power-supply = <&v3v3>; backlight = <&panel_backlight>; status = "okay"; From f55001ad5e8bca2d474f3bcf696a15bc4ea1f78e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 21 Mar 2019 17:21:49 +0100 Subject: [PATCH 031/244] Prepare v2018.11-stm32mp-r2.2 Change-Id: Ibc9e493c51009d22339cf3b4f9b48b18897b1515 Signed-off-by: Patrick Delaunay --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e69c2ee90824..340287108a1e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2.1 +EXTRAVERSION = -stm32mp-r2.2 NAME = # *DOCUMENTATION* From 6b6506fcca767a701469f7afbdb39162365eafdf Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 12 Apr 2019 18:55:16 +0200 Subject: [PATCH 032/244] dk1: add pull-up on serial rx of console connected to STLINK Avoid U-Boot auto-boot interruption for line break detection on console when the RX line connected to STLINK is floating (-IO error in getc cause by framing error and testc return 1) Change-Id: Id723ae5228bdc54827f0997e1a4c6ad7da4a77f5 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/130968 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Antonio Maria BORNEO Reviewed-by: Jean Philippe ROMAIN Reviewed-by: Patrice CHOTARD Tested-by: Jean Philippe ROMAIN --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 09794ba4dbe2..08b198eb9275 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -170,6 +170,8 @@ }; pins2 { u-boot,dm-pre-reloc; + /* pull-up on rx to avoid floating level */ + bias-pull-up; }; }; From be710c5302651f035110277eae6b207e17a77ec1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Apr 2019 15:54:12 +0200 Subject: [PATCH 033/244] ed1: add pull-up on serial rx of console connected to STLINK Avoid U-Boot auto-boot interruption for line break detection on console when the RX line connected to STLINK is floating (-IO error in getc cause by framing error and testc return 1) Change-Id: I4ba0e1f4e3430157833dfda483c754f7da129d24 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131191 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Gerald BAEZA --- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index b6bf6f105331..546129efd5a3 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -195,5 +195,7 @@ }; pins2 { u-boot,dm-pre-reloc; + /* pull-up on rx to avoid floating level */ + bias-pull-up; }; }; From 7414eea7e03ace214964a81806d7232bd0ec31fa Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Apr 2019 12:49:24 +0200 Subject: [PATCH 034/244] Prepare v2018.11-stm32mp-r2.3 Change-Id: I7a86fd4f95d536f6926c13c0ca4ea98337e65046 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131170 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 340287108a1e..1d89b31d78b0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2.2 +EXTRAVERSION = -stm32mp-r2.3 NAME = # *DOCUMENTATION* From 9b08cfac3769e60241ba2c590056c14459dff318 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 17 Apr 2019 14:20:08 +0200 Subject: [PATCH 035/244] usb: dwc2: fix gadget disconnect This fixes a disconnect issue detected with fastboot command, when using dwc2 driver. - On u-boot side: uboot>$ fastboot 0 - On USB host PC side, few seconds after PC>$ fastboot reboot # Get stuck, uboot target never reboots By enabling DEBUG_ISR logs, the bus suspend interrupt is seen before the PC command has been issued. When the USB bus suspend occurs, there's a HACK that disables the fastboot (composite driver). Here is the call stack upon USB bus suspend: - dwc2_handle_usb_suspend_intr() - dev->driver->disconnect() - composite_disconnect() - reset_config() - f->disable() - fastboot_disable() - usb_ep_disable(f_fb->out_ep); - usb_ep_disable(f_fb->in_ep); .. other disable calls. When the resume interrupt happens, everything has been disabled, then nothing happens. fastboot command gets stuck on HOST side. Remove original HACK, that disconnects the composite driver upon USB bus suspend. Implement disconnect detection instead: - check GINTSTS OTG interrupt - read GOTGINT register - check GOTGINT, SesEndDet bit (e.g. session end) This is inspired by what is implemented currently in Linux dwc2 driver. Reviewed-by: Marek Vasut [backport of 7fd9f31c6bd13609da61b985cf8f5f65ebebd913] Change-Id: I1eb776d1032222d5320408172206bb37465d2430 Signed-off-by: Fabrice Gasnier Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131243 Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/usb/gadget/dwc2_udc_otg_regs.h | 6 +++++- drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index a1829b3fd121..b6852561914e 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -86,6 +86,9 @@ struct dwc2_usbotg_reg { #define B_SESSION_VALID (0x1<<19) #define A_SESSION_VALID (0x1<<18) +/* DWC2_UDC_OTG_GOTINT */ +#define GOTGINT_SES_END_DET (1<<2) + /* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) #define PTXFE_ZERO (1<<8) @@ -118,6 +121,7 @@ struct dwc2_usbotg_reg { #define INT_NP_TX_FIFO_EMPTY (0x1<<5) #define INT_RX_FIFO_NOT_EMPTY (0x1<<4) #define INT_SOF (0x1<<3) +#define INT_OTG (0x1<<2) #define INT_DEV_MODE (0x0<<0) #define INT_HOST_MODE (0x1<<1) #define INT_GOUTNakEff (0x01<<7) @@ -246,7 +250,7 @@ struct dwc2_usbotg_reg { /* Masks definitions */ #define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\ - | INT_RESET | INT_SUSPEND) + | INT_RESET | INT_SUSPEND | INT_OTG) #define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) #define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) #define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index a75af4987f8f..7eb632d3b141 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -467,7 +467,7 @@ static void process_ep_out_intr(struct dwc2_udc *dev) static int dwc2_udc_irq(int irq, void *_dev) { struct dwc2_udc *dev = _dev; - u32 intr_status; + u32 intr_status, gotgint; u32 usb_status, gintmsk; unsigned long flags = 0; @@ -521,14 +521,24 @@ static int dwc2_udc_irq(int irq, void *_dev) && dev->driver) { if (dev->driver->suspend) dev->driver->suspend(&dev->gadget); + } + } + + if (intr_status & INT_OTG) { + gotgint = readl(®->gotgint); + debug_cond(DEBUG_ISR, + "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint); - /* HACK to let gadget detect disconnected state */ + if (gotgint & GOTGINT_SES_END_DET) { + debug_cond(DEBUG_ISR, "\t\tSession End Detected\n"); + /* Let gadget detect disconnected state */ if (dev->driver->disconnect) { spin_unlock_irqrestore(&dev->lock, flags); dev->driver->disconnect(&dev->gadget); spin_lock_irqsave(&dev->lock, flags); } } + writel(gotgint, ®->gotgint); } if (intr_status & INT_RESUME) { From 57588fa01f4007ae3e89d66c018c3096fac96e75 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 13 May 2019 10:40:57 +0200 Subject: [PATCH 036/244] Prepare v2018.11-stm32mp-r2.4 Change-Id: Idbdfb5b27599270d724e6a01fd82c20585d3c28a Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133208 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1d89b31d78b0..687817c51017 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2.3 +EXTRAVERSION = -stm32mp-r2.4 NAME = # *DOCUMENTATION* From a9501c3eb8d2f3b3f96a60494a479f7a0c15e5d5 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 10 Jun 2019 14:38:02 +0200 Subject: [PATCH 037/244] stm32mp1: Add PSCI node access before relocation Add node in DT and avoid error to search UCLASS_SYSRESET in board_f.c::print_resetinfo() and lost 1.6s in U-Boot for the trusted boot chain. Signed-off-by: Patrick Delaunay Change-Id: I47ef11c3363be3aaba73a588107e2a876c0eb953 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135443 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157-u-boot.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 035b1c608fbf..a7db47339aa5 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -21,6 +21,11 @@ pinctrl1 = &pinctrl_z; }; + /* need PSCI for sysreset during board_f */ + psci { + u-boot,dm-pre-proper; + }; + clocks { u-boot,dm-pre-reloc; }; From 4d63375083a5e23375707c82efaf64368ec43cf8 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 11 Jun 2019 16:54:17 +0200 Subject: [PATCH 038/244] psci: protect variable used before relocation Move the variable invoke_psci_fn in .data section and the driver access it safely it before relocation. Without patch the variable is located in .bss section and the probe requested relocation corrupt the device tree (probe requested by board_f.c::print_resetinfo()). Change-Id: If993a440864151e93451cb3a25496e76e3006e9c Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135581 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/firmware/psci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 2cb35f356f40..5609b693fae7 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -15,7 +15,7 @@ #include #include -psci_fn *invoke_psci_fn; +psci_fn *invoke_psci_fn __attribute__((section(".data"))); static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, unsigned long arg0, unsigned long arg1, From e8cc04677d02f98a25240e4dd0d1e6fb056fe980 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 10 Jun 2019 14:15:42 +0200 Subject: [PATCH 039/244] Prepare v2018.11-stm32mp-r2.5 Signed-off-by: Patrick Delaunay Change-Id: I7dd4371d7b19443d75b04bc5a5b989b2e3099603 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135441 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 687817c51017..5cd64b52cc46 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2.4 +EXTRAVERSION = -stm32mp-r2.5 NAME = # *DOCUMENTATION* From f7503df12ad5542866272ed545ff50874035c245 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 17 Jan 2019 12:49:35 +0100 Subject: [PATCH 040/244] stm32mp1: enable TAMP clock before access to register Normally RTCAPBEN is already enable by ROM code, but it is safe to enable the clock in all the case. Change-Id: I288096ee787bbaf8a7eb291e3792c4e1eb46a417 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119875 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 8d8ade38e992..15e379c8d570 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -173,6 +173,9 @@ static u32 get_bootmode(void) 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; From 5fe1f7750b0b51858cf564634766f7a64b74d8df Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Jan 2019 10:13:59 +0100 Subject: [PATCH 041/244] power: regulator: Return success on attempt to disable an always-on regulator commit 4f86a724e82c0 ("power: regulator: denied disable on always-on regulator") throws an error when requested to disable an always-on regulator. It is right that an always-on regulator should not be attempted to be disabled. But at the same time regulator framework should not return an error when such request is received. Instead it should just return success without attempting to disable the specified regulator. This is because the requesting driver will not have the idea if the regulator is always-on or not. The requesting driver will always try to enable/disable regulator as per the required flow. So it is upto regulator framework to not break such scenarios. Change-Id: Ib01b40775cd3d4314ac00c26afdc4fd316e6511b Fixes: 4f86a724e82c0 ("power: regulator: denied disable on always-on regulator") Reported-by: Jean-Jacques Hiblot Reviewed-by: Faiz Abbas Signed-off-by: Lokesh Vutla Reviewed-on: https://gerrit.st.com/119873 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/power/regulator/regulator-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4511625ff251..39e46279d533 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -113,7 +113,7 @@ int regulator_set_enable(struct udevice *dev, bool enable) uc_pdata = dev_get_uclass_platdata(dev); if (!enable && uc_pdata->always_on) - return -EACCES; + return 0; return ops->set_enable(dev, enable); } From 54fe4129a6ea0aa0473f4ed204742a2846237c96 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 31 Jan 2019 20:36:57 +0100 Subject: [PATCH 042/244] fdt: Allow indicating a node is for U-Boot proper only This add missing parts for previous commit 06f94461a9f4 ("fdt: Allow indicating a node is for U-Boot proper only") At present it is not possible to specify that a node should be used before relocation (in U-Boot proper) without it also ending up in SPL and TPL device trees. Add a new "u-boot,dm-pre-proper" boolean property for this. Tested with "u-boot,dm-pre-proper" for video driver, without live tree. Change-Id: I456de145f4689539dfa0c9fcda8ff0b6be0238a7 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/120645 Reviewed-by: CITOOLS --- drivers/core/root.c | 3 ++- drivers/core/util.c | 2 ++ drivers/video/video-uclass.c | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/core/root.c b/drivers/core/root.c index b54bf5bcdc59..ab63bc043afe 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -223,7 +223,8 @@ static int dm_scan_fdt_live(struct udevice *parent, for (np = node_parent->child; np; np = np->sibling) { if (pre_reloc_only && - !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) + !of_find_property(np, "u-boot,dm-pre-reloc", NULL) && + !of_find_property(np, "u-boot,dm-pre-proper", NULL)) continue; if (!of_device_is_available(np)) { pr_debug(" - ignoring disabled device\n"); diff --git a/drivers/core/util.c b/drivers/core/util.c index 451d4766d08c..0db01ebc2222 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -34,6 +34,8 @@ bool dm_fdt_pre_reloc(const void *blob, int offset) { if (fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) return true; + if (fdt_getprop(blob, offset, "u-boot,dm-pre-proper", NULL)) + return true; #ifdef CONFIG_TPL_BUILD if (fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL)) diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 5fe49a53032a..367d81197877 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -277,7 +277,9 @@ static int video_post_bind(struct udevice *dev) return 0; size = alloc_fb(dev, &addr); if (addr < gd->video_bottom) { - /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */ + /* Device tree node may need the 'u-boot,dm-pre-reloc' or + * 'u-boot,dm-pre-proper' tag + */ printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n", dev->name); return -ENOSPC; From cb5e4e89b3f89922912e46d862c14a4e233686ba Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 6 Feb 2019 15:16:28 +0100 Subject: [PATCH 043/244] dts: stm32mp1: use u-boot,dm-pre-proper replace property u-boot,dm-pre-reloc by new property u-boot,dm-pre-proper when it is possible Change-Id: I1b0c04f33bbbcf48df35e9083674bd36c358d739 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/120646 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157-u-boot.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index a7db47339aa5..9203106f0889 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -57,7 +57,7 @@ }; &bsec { - u-boot,dm-pre-reloc; + u-boot,dm-pre-proper; }; &clk_csi { @@ -146,7 +146,7 @@ /* pre-reloc probe = reserve video frame buffer in video_reserve() */ <dc { - u-boot,dm-pre-reloc; + u-boot,dm-pre-proper; }; &pinctrl { From 4efe255dddf062453b95e0222cbb26eb51ab5175 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 29 Jan 2019 18:46:20 +0100 Subject: [PATCH 044/244] ram: stm32mp1: update help message for interactive mode Alignment with last WIKI page. Change-Id: I87b6de232e889e351af328c55d4007c85483a3c5 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/119929 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_interactive.c | 39 ++++++++++++--------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index 3840af54ec82..a5a24a2b1118 100644 --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -99,25 +99,30 @@ static void stm32mp1_do_usage(void) { const char *usage = { "commands:\n\n" - "help this message\n" - "info [ ] display/change DDR information\n" - "freq [freq] display/change the DDR frequency\n" - "param [type|reg] print input parameters\n" - "param edit parameters in step 0\n" - "print [type|reg] dump register\n" - "edit modify register\n" - " all registers if [type|reg] is absent\n" - " = ctl, phy\n" - " or one category (static, timing, map, perf, cal, dyn)\n" - " = name of the register\n" - "step [n] list the step / go to the step \n" - "next go to the next step\n" - "go continue SPL execution\n" - "reset reboot machine\n" - "test [help] | [...] list (with help) or execute test \n" + "help displays help\n" + "info displays DDR information\n" + "info changes DDR information\n" + " with = step, name, size or speed\n" + "freq displays the DDR PHY frequency in kHz\n" + "freq changes the DDR PHY frequency\n" + "param [type|reg] prints input parameters\n" + "param edits parameters in step 0\n" + "print [type|reg] dumps registers\n" + "edit modifies one register\n" + "step lists the available step\n" + "step go to the step \n" + "next goes to the next step\n" + "go continues the U-Boot SPL execution\n" + "reset reboots machine\n" + "test [help] | [...] lists (with help) or executes test \n" #ifdef CONFIG_STM32MP1_DDR_TUNING - "tuning [help] | [...] list (with help) or execute test \n" + "tuning [help] | [...] lists (with help) or execute tuning \n" #endif + "\nwith for [type|reg]:\n" + " all registers if absent\n" + " = ctl, phy\n" + " or one category (static, timing, map, perf, cal, dyn)\n" + " = name of the register\n" }; puts(usage); From 0f02fac2203508abd6154d3f677286d1d5ef7bb1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 1 Feb 2019 19:05:33 +0100 Subject: [PATCH 045/244] stm32mp1: ram: add some dynamic register Add useful register access with interactive mode: dxngsr0/1 and zq0sr0/1 Change-Id: Ie86672e607029afb7fe564f219661e4096ade68a Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/120663 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index a83ea39162ad..7b28f6308192 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -189,6 +189,16 @@ static const struct reg_desc ddr_dyn[] = { static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(pir), DDRPHY_REG_DYN(pgsr), + DDRPHY_REG_DYN(zq0sr0), + DDRPHY_REG_DYN(zq0sr1), + DDRPHY_REG_DYN(dx0gsr0), + DDRPHY_REG_DYN(dx0gsr1), + DDRPHY_REG_DYN(dx1gsr0), + DDRPHY_REG_DYN(dx1gsr1), + DDRPHY_REG_DYN(dx2gsr0), + DDRPHY_REG_DYN(dx2gsr1), + DDRPHY_REG_DYN(dx3gsr0), + DDRPHY_REG_DYN(dx3gsr1), }; enum reg_type { From 5f708b807b2390bcb1b34de8292157bc04e12989 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 17 Jan 2019 14:45:26 +0100 Subject: [PATCH 046/244] env: ext4: Allow overriding interface, device and partition For platform which can boot on different device, this allows to override interface, device and partition from board code. Change-Id: Iaa3dfcd07cb86e2ea705922744cdca3da5f0bb5a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121322 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- env/ext4.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/env/ext4.c b/env/ext4.c index 09c5e4a49101..d027a702c8d1 100644 --- a/env/ext4.c +++ b/env/ext4.c @@ -30,6 +30,16 @@ #include #include +__weak const char *env_ext4_get_intf(void) +{ + return (const char *)CONFIG_ENV_EXT4_INTERFACE; +} + +__weak const char *env_ext4_get_dev_part(void) +{ + return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; +} + #ifdef CONFIG_CMD_SAVEENV static int env_ext4_save(void) { @@ -38,13 +48,14 @@ static int env_ext4_save(void) disk_partition_t info; int dev, part; int err; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); err = env_export(&env_new); if (err) return err; - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) return 1; @@ -54,8 +65,7 @@ static int env_ext4_save(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for saveenv **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); return 1; } @@ -65,8 +75,7 @@ static int env_ext4_save(void) if (err == -1) { printf("\n** Unable to write \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); return 1; } @@ -83,14 +92,15 @@ static int env_ext4_load(void) int dev, part; int err; loff_t off; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); #ifdef CONFIG_MMC - if (!strcmp(CONFIG_ENV_EXT4_INTERFACE, "mmc")) + if (!strcmp(ifname, "mmc")) mmc_initialize(NULL); #endif - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) goto err_env_relocate; @@ -100,8 +110,7 @@ static int env_ext4_load(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for loading the env **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); goto err_env_relocate; } @@ -111,8 +120,7 @@ static int env_ext4_load(void) if (err == -1) { printf("\n** Unable to read \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); goto err_env_relocate; } From 4e5a7e85a4fb002cc700885486ce7972aa2d3330 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Jan 2019 18:11:03 +0100 Subject: [PATCH 047/244] stm32mp1: Give access to get_bootmode() outside cpu.c Allow to call get_bootmode() outside cpu.c to be able to retrieve the boot device instance. This is needed to save the environment on the correct boot device instance. Change-Id: I85c0985aae7a9c81db0643b343e80445206b0cec Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121323 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/cpu.c | 21 +++++++++++-------- .../arm/mach-stm32mp/include/mach/sys_proto.h | 2 ++ arch/arm/mach-stm32mp/spl.c | 3 +-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 15e379c8d570..5384dff96905 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -165,11 +165,12 @@ 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; @@ -190,12 +191,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; } /* @@ -212,10 +215,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) diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index c5657489fc99..71a3ba794d11 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -19,3 +19,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 fa393ccbfa17..b47e74dcfbaa 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -24,8 +24,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: From c488932624289428752383e318f7cd97a8227609 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 18 Jan 2019 09:58:48 +0100 Subject: [PATCH 048/244] board: stm32mp1: Add env_ext4_get_dev_part() and env_ext4_get_intf() This allows to : - select the current device to save the environment file - select the correct EXT4 boot device instance and partition to save the environment file. For EXT4, device is mmc, device instance is 0 for sdcard or 1 for eMMC. The partition is set to "auto" to select the first partition with bootable flag. Change-Id: I164197cc99cc670a1ede39131089bc4fd1445797 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121324 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index ab64f410b96f..0502ced6ab7c 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -793,6 +794,29 @@ static int dk2_i2c1_fix(void) } #endif +#if defined(CONFIG_ENV_IS_IN_EXT4) +const char *env_ext4_get_intf(void) +{ + u32 bootmode = get_bootmode(); + + switch (bootmode & TAMP_BOOT_DEVICE_MASK) { + case BOOT_FLASH_SD: + case BOOT_FLASH_EMMC: + return "mmc"; + default: + return ""; + } +} + +const char *env_ext4_get_dev_part(void) +{ + static char *const dev_part[] = {"0:auto", "1:auto", "2:auto"}; + u32 bootmode = get_bootmode(); + + return dev_part[(bootmode & TAMP_BOOT_INSTANCE_MASK) - 1]; +} +#endif + /* board dependent setup after realloc */ int board_init(void) { From 60d5ed2593c943d289f71a7ca180325c667fbe65 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 8 Feb 2019 09:42:38 +0100 Subject: [PATCH 049/244] env: allow ENV_IS_NOWHERE with other storage target Allow U-Boot to get default environment for some boot mode (USB for example), and to select storage location when it is booting from flash device; ENVL_NOWHERE is present in env_locations with other one. Change-Id: I0363120e7e18660c35572dc380527df6da2923a0 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125071 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- env/Kconfig | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/env/Kconfig b/env/Kconfig index 9011109b47b7..b304451e043a 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -2,18 +2,12 @@ menu "Environment" config ENV_IS_NOWHERE bool "Environment is not stored" - depends on !ENV_IS_IN_EEPROM - depends on !ENV_IS_IN_EXT4 - depends on !ENV_IS_IN_FAT - depends on !ENV_IS_IN_FLASH - depends on !ENV_IS_IN_MMC - depends on !ENV_IS_IN_NAND - depends on !ENV_IS_IN_NVRAM - depends on !ENV_IS_IN_ONENAND - depends on !ENV_IS_IN_REMOTE - depends on !ENV_IS_IN_SPI_FLASH - depends on !ENV_IS_IN_UBI - default y + default y if !ENV_IS_IN_EEPROM && !ENV_IS_IN_EXT4 && \ + !ENV_IS_IN_FAT && !ENV_IS_IN_FLASH && \ + !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \ + !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \ + !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \ + !ENV_IS_IN_UBI help Define this if you don't want to or can't have an environment stored on a storage medium. In this case the environment will still exist From 953db29a1e9c668b478270d816eb517db33458c1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 18 Feb 2019 10:58:16 +0100 Subject: [PATCH 050/244] env: enable saveenv command when one CONFIG_ENV_IS_IN is activated Introduce ENV_IS_IN_DEVICE to test if one the CONFIG_ENV_IS_IN_ is defined and support the command saveenv even if CONFIG_ENV_IS_NOWHERE is activated Change-Id: I1d5c3ed7085398cf9a28f2cb2eb11fc090cb203d Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125906 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- cmd/nvedit.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index de16c72c23f2..767e824dfc3f 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -39,18 +39,24 @@ DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \ - !defined(CONFIG_ENV_IS_IN_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_MMC) && \ - !defined(CONFIG_ENV_IS_IN_FAT) && \ - !defined(CONFIG_ENV_IS_IN_EXT4) && \ - !defined(CONFIG_ENV_IS_IN_NAND) && \ - !defined(CONFIG_ENV_IS_IN_NVRAM) && \ - !defined(CONFIG_ENV_IS_IN_ONENAND) && \ - !defined(CONFIG_ENV_IS_IN_SATA) && \ - !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_REMOTE) && \ - !defined(CONFIG_ENV_IS_IN_UBI) && \ +#if defined(CONFIG_ENV_IS_IN_EEPROM) || \ + defined(CONFIG_ENV_IS_IN_FLASH) || \ + defined(CONFIG_ENV_IS_IN_MMC) || \ + defined(CONFIG_ENV_IS_IN_FAT) || \ + defined(CONFIG_ENV_IS_IN_EXT4) || \ + defined(CONFIG_ENV_IS_IN_NAND) || \ + defined(CONFIG_ENV_IS_IN_NVRAM) || \ + defined(CONFIG_ENV_IS_IN_ONENAND) || \ + defined(CONFIG_ENV_IS_IN_SATA) || \ + defined(CONFIG_ENV_IS_IN_SPI_FLASH) || \ + defined(CONFIG_ENV_IS_IN_REMOTE) || \ + defined(CONFIG_ENV_IS_IN_UBI) + +#define ENV_IS_IN_DEVICE + +#endif + +#if !defined(ENV_IS_IN_DEVICE) && \ !defined(CONFIG_ENV_IS_NOWHERE) # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE @@ -738,7 +744,7 @@ ulong env_get_ulong(const char *name, int base, ulong default_val) } #ifndef CONFIG_SPL_BUILD -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -1194,7 +1200,7 @@ static cmd_tbl_t cmd_env_sub[] = { #if defined(CONFIG_CMD_RUN) U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""), #endif U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""), @@ -1266,7 +1272,7 @@ static char env_help_text[] = #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) "env save - save environment\n" #endif "env set [-f] name [arg ...]\n"; From 03dd632d3d76fb42a42bab14b908785d0247bbab Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 18:04:08 +0100 Subject: [PATCH 051/244] configs: stm32mp15: Enable ENV_IS_IN_EXT4 and all relative flags Enable ENV_IS_IN_EXT4 and all relative flags to be able to load/save environment in EXT4 partition. This will allows to load/save environment on both sdcard and eMMC. As for stm32mp15, bootfs has not the same partition number on sdcard and on eMMC, we use "auto" key which allows to find the first partition in device with bootable flag which is partition 4 on sdcard and partition 2 on eMMC. Change-Id: Iecda1a27a04db9aedcf1f10764c7b3b692e40863 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121325 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 5 +++++ configs/stm32mp15_optee_defconfig | 5 +++++ configs/stm32mp15_trusted_defconfig | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index d04e1d74fcae..75081de184a6 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -45,6 +45,11 @@ CONFIG_CMD_MTDPARTS=y CONFIG_CMD_UBI=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="mmc" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" +CONFIG_ENV_EXT4_FILE="/uboot.env" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 076eab61b282..ac76febb50b9 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -35,6 +35,11 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="mmc" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" +CONFIG_ENV_EXT4_FILE="/uboot.env" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 90a6adc46d0c..0008ba070274 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -34,6 +34,11 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="mmc" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" +CONFIG_ENV_EXT4_FILE="/uboot.env" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 From 10f73393dccae4d15d688262bac9a6ba11e2499f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 22 Jan 2019 09:49:23 +0100 Subject: [PATCH 052/244] stm32mp1: Add env_get_location() In case of several environment location support, env_get_location is needed to select the correct location depending of the boot device . Change-Id: Ia0c9a265e78a5fc49f0870323f8e644093abae5f Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121326 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 0502ced6ab7c..06c9edcf0875 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -794,6 +795,28 @@ static int dk2_i2c1_fix(void) } #endif +enum env_location env_get_location(enum env_operation op, int prio) +{ + u32 bootmode = get_bootmode(); + + if (prio) + return ENVL_UNKNOWN; + + switch (bootmode & TAMP_BOOT_DEVICE_MASK) { +#ifdef CONFIG_ENV_IS_IN_EXT4 + case BOOT_FLASH_SD: + case BOOT_FLASH_EMMC: + return ENVL_EXT4; +#endif +#ifdef CONFIG_ENV_IS_IN_UBI + case BOOT_FLASH_NAND: + return ENVL_UBI; +#endif + default: + return ENVL_NOWHERE; + } +} + #if defined(CONFIG_ENV_IS_IN_EXT4) const char *env_ext4_get_intf(void) { From 1c0f4f647a87db5592f4b23c8e87156cfaaa79d0 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 23 Jan 2019 18:12:48 +0100 Subject: [PATCH 053/244] mtd: Fix get_mtdparts() When ENV_IS_IN_UBI is enable, get_mtdparts is called before relocation. During first get_mtdparts() call, mtdparts is not available in environment, it can be retrieved by calling board_mtdparts_default(), but following env_set() do nothing as we are before relocation. Finally mtdparts is still not available in environment. At second get_mtdparts() call, use_defaults is false, but mtdparts is still not in environment and is NULL. Remove use_defaults bool, only mtdparts criteria is useful. Fixes: commit 5ffcd50612f6 ("mtd: Use default mtdparts/mtids when not defined in the environment") Change-Id: Ibf57c68b062fc0e86f701dbb881c1f49a1086046 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121327 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/mtd/mtd_uboot.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index 5ca560c96879..6c11810b94cb 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -123,7 +123,6 @@ static const char *get_mtdparts(void) { __maybe_unused const char *mtdids = NULL; static char tmp_parts[MTDPARTS_MAXLEN]; - static bool use_defaults = true; const char *mtdparts = NULL; if (gd->flags & GD_FLG_ENV_READY) @@ -131,7 +130,7 @@ static const char *get_mtdparts(void) else if (env_get_f("mtdparts", tmp_parts, sizeof(tmp_parts)) != -1) mtdparts = tmp_parts; - if (mtdparts || !use_defaults) + if (mtdparts) return mtdparts; #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) @@ -145,8 +144,6 @@ static const char *get_mtdparts(void) if (mtdparts) env_set("mtdparts", mtdparts); - use_defaults = false; - return mtdparts; } From 16d61238756f38b8cfc8337873a13282aeaff3b3 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 24 Jan 2019 09:17:55 +0100 Subject: [PATCH 054/244] stm32mp1: Fix board_mtdparts_default When ENV_IS_IN_UBI is enable, board_mtdparts_default() is called early, before relocation. At this step, GD_FLG_ENV_READY flag is not set, env_get() always returns the same buffer reference on consecutive call. As consequence, s_nand0 is set, in case s_nor0 is set, s_nand0 is then updated with same value than s_nor0. To take care of that, use a temporary buffer which is copied into s_nor0 and/or s_nand0. As s_nand0 and s_nor0 are long string, the gd->env_buf[32] is too small, apply same solution than in commit a7eb1d66c704 ("mtd: Make mtdparts work with pre-reloc env") to avoid the following message: "env_buf [32 bytes] too small for value of ..." Change-Id: I404cdb25de197dcada3fb266dc1e5d3465ac9a91 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121328 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 06c9edcf0875..5c96e69a8a0c 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -896,29 +896,57 @@ void board_quiesce_devices(void) } #ifdef CONFIG_SYS_MTDPARTS_RUNTIME + +#define MTDPARTS_LEN 256 + +/** + * The mtdparts_nand0 and mtdparts_nor0 variable tends to be long. + * If we need to access it before the env is relocated, then we need + * to use our own stack buffer. gd->env_buf will be too small. + * + * @param buf temporary buffer pointer MTDPARTS_LEN long + * @return mtdparts variable string, NULL if not found + */ +static const char *env_get_mtdparts(char *str, char *buf) +{ + if (gd->flags & GD_FLG_ENV_READY) + return env_get(str); + if (env_get_f(str, buf, MTDPARTS_LEN) != -1) + return buf; + return NULL; +} + void board_mtdparts_default(const char **mtdids, const char **mtdparts) { struct udevice *dev; - char *s_nand0 = NULL, *s_nor0 = NULL; + char s_nand0[128] = {0}, s_nor0[128] = {0}; + char mtdparts_buf[MTDPARTS_LEN]; + const char *temp; static char parts[256]; static char ids[22]; - if (!uclass_get_device(UCLASS_MTD, 0, &dev)) - s_nand0 = env_get("mtdparts_nand0"); + if (!uclass_get_device(UCLASS_MTD, 0, &dev)) { + temp = env_get_mtdparts("mtdparts_nand0", mtdparts_buf); + if (temp) + snprintf(s_nand0, sizeof(s_nand0), temp); + } - if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) - s_nor0 = env_get("mtdparts_nor0"); + if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) { + temp = env_get_mtdparts("mtdparts_nor0", mtdparts_buf); + if (temp) + snprintf(s_nor0, sizeof(s_nor0), temp); + } strcpy(ids, ""); strcpy(parts, ""); - if (s_nand0 && s_nor0) { + if (strlen(s_nand0) && strlen(s_nor0)) { snprintf(ids, sizeof(ids), "nor0=nor0,nand0=nand0"); snprintf(parts, sizeof(parts), "mtdparts=nor0:%s;nand0:%s", s_nor0, s_nand0); - } else if (s_nand0) { + } else if (strlen(s_nand0)) { snprintf(ids, sizeof(ids), "nand0=nand0"); snprintf(parts, sizeof(parts), "mtdparts=nand0:%s", s_nand0); - } else if (s_nor0) { + } else if (strlen(s_nor0)) { snprintf(ids, sizeof(ids), "nor0=nor0"); snprintf(parts, sizeof(parts), "mtdparts=nor0:%s", s_nor0); } From 5788a42f1af00e90164d44255493404a2d2b8efd Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 22 Jan 2019 09:50:30 +0100 Subject: [PATCH 055/244] configs: stm32mp15: Enable ENV_IS_IN_UBI Add all relative flags needed by ENV_IS_IN_UBI Change-Id: I299b6f66a3aeb5b31c32d884d554385760bdec01 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121329 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + include/configs/stm32mp1.h | 6 ++++++ 4 files changed, 9 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 75081de184a6..b38a4574015c 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -47,6 +47,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" CONFIG_ENV_EXT4_FILE="/uboot.env" diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index ac76febb50b9..853f98acf880 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -37,6 +37,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" CONFIG_ENV_EXT4_FILE="/uboot.env" diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 0008ba070274..3a279003c138 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -36,6 +36,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" CONFIG_ENV_EXT4_FILE="/uboot.env" diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index abbfe3f3d03c..4a5bb0b197ff 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -50,6 +50,12 @@ */ #define CONFIG_ENV_SIZE SZ_4K +#if defined(CONFIG_ENV_IS_IN_UBI) +#define CONFIG_ENV_UBI_PART "UBI" +#define CONFIG_ENV_UBI_VOLUME "uboot_config" +#define CONFIG_ENV_UBI_VOLUME_REDUND "uboot_config_r" +#endif + /* ATAGs */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS From b377093fcab94794b0138d3603bfbc60a46ded17 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 29 Jan 2019 14:52:32 +0100 Subject: [PATCH 056/244] dm: spi: Read default speed and mode values from DT This patch update the behavior introduced by commit 96907c0fe50a ("dm: spi: Read default speed and mode values from DT") In case of DT boot, don't read default speed and mode for SPI from CONFIG_*, instead read from DT node. This will make sure that boards with multiple SPI/QSPI controllers can be probed at different bus frequencies and SPI modes. DT values will be always used when available (full DM support of SPI slave with DT node); for example splash (in splash_sf_read_raw) or SPL boot (in spl_spi_load_image). The caller of spi_get_bus_and_cs() don't need to force speed=0. And the current behavior don't change if the SPI slave is not present (device with generic driver is created automatically) or if platdata is used (CONFIG_OF_PLATDATA). Change-Id: Ia3eb3f02b0006148c86c19e60d4b552b81744ed6 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/121330 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- README | 3 +++ cmd/sf.c | 3 +-- common/spl/spl_spi.c | 2 ++ drivers/spi/spi-uclass.c | 4 +++- include/spi.h | 9 +++++---- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/README b/README index a46c7c63a4fe..788858cc42c1 100644 --- a/README +++ b/README @@ -2192,6 +2192,9 @@ The following options need to be configured: CONFIG_SF_DEFAULT_MODE (see include/spi.h) CONFIG_SF_DEFAULT_SPEED in Hz + In case of DT boot, SPI don't read default speed and mode + from CONFIG_*, but from platdata values computed from available + DT node - TFTP Fixed UDP Port: CONFIG_TFTP_PORT diff --git a/cmd/sf.c b/cmd/sf.c index 84bb0575f233..f1811d2ef8e5 100644 --- a/cmd/sf.c +++ b/cmd/sf.c @@ -81,14 +81,13 @@ static int do_spi_flash_probe(int argc, char * const argv[]) { unsigned int bus = CONFIG_SF_DEFAULT_BUS; unsigned int cs = CONFIG_SF_DEFAULT_CS; + /* In DM mode, defaults speed and mode will be taken from DT */ unsigned int speed = CONFIG_SF_DEFAULT_SPEED; unsigned int mode = CONFIG_SF_DEFAULT_MODE; char *endp; #ifdef CONFIG_DM_SPI_FLASH struct udevice *new, *bus_dev; int ret; - /* In DM mode defaults will be taken from DT */ - speed = 0, mode = 0; #else struct spi_flash *new; #endif diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index 3cefc9a32703..3d2111070bec 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -77,6 +77,8 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, /* * Load U-Boot image from SPI flash into RAM + * In DM mode: defaults speed and mode will be + * taken from DT when available */ #ifdef CONFIG_DM_SPI_FLASH /* In DM mode defaults will be taken from DT */ diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index b84255bd2743..856c5339856a 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -320,7 +320,9 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, } plat = dev_get_parent_platdata(dev); - if (!speed) { + + /* get speed and mode from platdata when available */ + if (plat->max_hz) { speed = plat->max_hz; mode = plat->mode; } diff --git a/include/spi.h b/include/spi.h index 938627bc012b..7c8abc09b0c0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -503,14 +503,15 @@ int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, * device and slave device. * * If no such slave exists, and drv_name is not NULL, then a new slave device - * is automatically bound on this chip select. + * is automatically bound on this chip select with requested speed and mode. * - * Ths new slave device is probed ready for use with the given speed and mode. + * Ths new slave device is probed ready for use with the speed and mode + * from platdata, when available, or the requested value. * * @busnum: SPI bus number * @cs: Chip select to look for - * @speed: SPI speed to use for this slave - * @mode: SPI mode to use for this slave + * @speed: SPI speed to use for this slave when not available in platdata + * @mode: SPI mode to use for this slave when not available in platdata * @drv_name: Name of driver to attach to this chip select * @dev_name: Name of the new device thus created * @busp: Returns bus device From 940ddbc9009b67909cd2184060154f7408850be6 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 24 Jan 2019 11:33:29 +0100 Subject: [PATCH 057/244] configs: stm32mp15: Enable ENV_IS_SPI_FLASH Add all relative flags needed by ENV_IS_IN_SPI_FLASH Previously, a 256KB partition in NOR was reserved for the BMP splashscreen which is now located in the bootfs partition. We can reuse this partition to save the U-Boot environment. Change-Id: I9434585d2dbcfbb37a1f543fe0ae540ac1509c37 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121331 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + include/configs/stm32mp1.h | 9 +++++++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index b38a4574015c..c4e235b975d8 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -47,6 +47,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 853f98acf880..ad1bf46fd523 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -37,6 +37,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 3a279003c138..d5767e798732 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -36,6 +36,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 4a5bb0b197ff..9000495a42ad 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -56,6 +56,11 @@ #define CONFIG_ENV_UBI_VOLUME_REDUND "uboot_config_r" #endif +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH) +#define CONFIG_ENV_SECT_SIZE SZ_256K +#define CONFIG_ENV_OFFSET 0x00280000 +#endif + /* ATAGs */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS @@ -162,13 +167,13 @@ #define CONFIG_SYS_MEM_TOP_HIDE SZ_32M /* with OPTEE: define specific MTD partitions = teeh, teed, teex */ #define STM32MP_MTDPARTS \ - "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI);\0" #else /* CONFIG_STM32MP1_OPTEE */ #define STM32MP_MTDPARTS \ - "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),-(nor_user)\0" \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),-(nor_user)\0" \ "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" #endif /* CONFIG_STM32MP1_OPTEE */ From 21c58294241854ac5c1ea51cf425a996caf9cb46 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 29 Jan 2019 14:10:45 +0100 Subject: [PATCH 058/244] stm32mp1: Update env_get_location for NOR support Update env_get_location() to be able to save environment into NOR (SPI_FLASH). Change-Id: I04e6d8142ff182325d4a754bf13cdccf5902e59d Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121332 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 5c96e69a8a0c..c8bab44efa35 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -811,6 +811,10 @@ enum env_location env_get_location(enum env_operation op, int prio) #ifdef CONFIG_ENV_IS_IN_UBI case BOOT_FLASH_NAND: return ENVL_UBI; +#endif +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH + case BOOT_FLASH_NOR: + return ENVL_SPI_FLASH; #endif default: return ENVL_NOWHERE; From 8c5d675f524fbbaac0b9884ab56da1ff19865668 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 4 Feb 2019 09:44:43 +0100 Subject: [PATCH 059/244] remoteproc: rproc-uclass: Fix warnings for aarch64 platforms drivers/remoteproc/rproc-uclass.c:452:25: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), ^ include/linux/kernel.h:81:9: note: in definition of macro 'rounddown' typeof(x) __x = (x); \ ^ include/linux/kernel.h:81:19: note: in definition of macro 'rounddown' ^ drivers/remoteproc/rproc-uclass.c:453:16: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] roundup((int)dst + phdr->p_filesz, ^ include/linux/kernel.h:76:5: note: in definition of macro 'roundup' (((x) + (__y - 1)) / __y) * __y; \ ^ drivers/remoteproc/rproc-uclass.c:455:18: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] rounddown((int)dst, ARCH_DMA_MINALIGN)); ^ drivers/remoteproc/rproc-uclass.c: In function 'rproc_elf_find_load_rsc_table': drivers/remoteproc/rproc-uclass.c:559:9: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] dst = (void *)shdr->sh_addr; drivers/remoteproc/rproc-uclass.c:567:24: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), ^ drivers/remoteproc/rproc-uclass.c:568:15: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] roundup((int)dst + shdr->sh_size, ^ drivers/remoteproc/rproc-uclass.c:570:17: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] rounddown((int)dst, ARCH_DMA_MINALIGN)); Change-Id: I89846ee5080752bfe7fe5d95d58ce538c571671a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/121432 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/remoteproc/rproc-uclass.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 204e6e848ffe..36f1e971fc16 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -449,10 +449,10 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, if (phdr->p_filesz != phdr->p_memsz) memset(dst + phdr->p_filesz, 0x00, phdr->p_memsz - phdr->p_filesz); - flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), - roundup((int)dst + phdr->p_filesz, + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + phdr->p_filesz, ARCH_DMA_MINALIGN) - - rounddown((int)dst, ARCH_DMA_MINALIGN)); + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); ++phdr; } @@ -564,10 +564,10 @@ static int rproc_elf_find_load_rsc_table(struct udevice *dev, src = (void *)fw_addr + shdr->sh_offset; memcpy(dst, src, shdr->sh_size); - flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), - roundup((int)dst + shdr->sh_size, + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + shdr->sh_size, ARCH_DMA_MINALIGN) - - rounddown((int)dst, ARCH_DMA_MINALIGN)); + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); return 0; } From aebd74760b1cde5816a2f30a7a5d71200355a38c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 7 Feb 2019 11:13:05 +0100 Subject: [PATCH 060/244] stm32mp1: dts: remove dm-pre-reloc for config node This tag is not necessary as always added in SPL device tree (see cmd_fdtgrep in scripts/Makefile.lib). Change-Id: I035b38233874824ffa1a14d4d44d4532de7fbce6 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/121421 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/dts/stm32mp157-u-boot.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 9203106f0889..e425932b999a 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -30,10 +30,6 @@ u-boot,dm-pre-reloc; }; - config { - u-boot,dm-pre-reloc; - }; - reboot { u-boot,dm-pre-reloc; }; From fbc47b135ba311225de84a1b985690b92bce37a9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 11 Feb 2019 17:55:43 +0100 Subject: [PATCH 061/244] stm32mp1: configs: Add CONFIG_OF_SPL_REMOVE_PROPS Removes unused device tree property in SPL to reduce the SPL size by 1kB Change-Id: Id0eff5b025dfb0603e640d70640a221d35f25b38 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/121420 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- configs/stm32mp15_basic_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index c4e235b975d8..7230feb442e0 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -45,6 +45,7 @@ CONFIG_CMD_MTDPARTS=y CONFIG_CMD_UBI=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-names interrupts-extended interrupt-controller \\\#interrupt-cells interrupt-parent dmas dma-names assigned-clocks assigned-clock-rates assigned-clock-parents hwlocks" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_IS_IN_SPI_FLASH=y From 13da1491925216b66278c5bc8d11ff0b054efaf4 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 13 Feb 2019 17:39:02 +0100 Subject: [PATCH 062/244] pinctrl: stmfx: add .get_pin_muxing callback support This is needed to get pin muxing state of STMFX GPIO expander. Change-Id: I43ac3bf12810b8b3e20d791814cbed6ec83220f1 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125687 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/pinctrl/pinctrl-stmfx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 9b5009aaf83c..275fdbff771d 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -286,6 +286,23 @@ static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev, 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); @@ -306,6 +323,7 @@ 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), From 4c1f94966f12ce84b143f97ec2cb8214fbbe179a Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Feb 2019 09:45:45 +0100 Subject: [PATCH 063/244] watchdog: Kconfig: Sort entry alphabetically Change-Id: I487a163d25b15b0f98f521e1a2f9b36503948d44 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125381 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/watchdog/Kconfig | 66 ++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 705fc7d746b6..85579327dc1a 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -20,6 +20,13 @@ config BCM2835_WDT This provides basic infrastructure to support BCM2835/2836 watchdog hardware, with a max timeout of ~15secs. +config IMX_WATCHDOG + bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + select HW_WATCHDOG + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver. + config OMAP_WATCHDOG bool "TI OMAP watchdog driver" depends on ARCH_OMAP2PLUS @@ -28,6 +35,21 @@ config OMAP_WATCHDOG help Say Y here to enable the OMAP3+ watchdog driver. +config STM32MP_WATCHDOG + bool "Enable IWDG watchdog driver for STM32 MP's family" + depends on ARCH_STM32MP + select HW_WATCHDOG + help + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. + +config STM32MP_WATCHDOG_TIMEOUT_SECS + int "IWDG watchdog timeout" + depends on STM32MP_WATCHDOG + default 32 + help + Configure the timeout for IWDG (default: 32s). + config TANGIER_WATCHDOG bool "Intel Tangier watchdog" depends on INTEL_MID @@ -52,14 +74,6 @@ config WDT What exactly happens when the timer expires is up to a particular device/driver. -config WDT_SANDBOX - bool "Enable Watchdog Timer support for Sandbox" - depends on SANDBOX && WDT - help - Enable Watchdog Timer support in Sandbox. This is a dummy device that - can be probed and supports all of the methods of WDT, but does not - really do anything. - config WDT_ARMADA_37XX bool "Marvell Armada 37xx watchdog timer support" depends on WDT && ARMADA_3700 @@ -88,13 +102,6 @@ config WDT_BCM6345 The watchdog timer is stopped when initialized. It performs full SoC reset. -config WDT_ORION - bool "Orion watchdog timer support" - depends on WDT - help - Select this to enable Orion watchdog timer, which can be found on some - Marvell Armada chips. - config WDT_CDNS bool "Cadence watchdog timer support" depends on WDT @@ -103,20 +110,20 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. -config STM32MP_WATCHDOG - bool "Enable IWDG watchdog driver for STM32 MP's family" - depends on ARCH_STM32MP - select HW_WATCHDOG +config WDT_ORION + bool "Orion watchdog timer support" + depends on WDT help - Enable the STM32 watchdog (IWDG) driver. Enable support to - configure STM32's on-SoC watchdog. + Select this to enable Orion watchdog timer, which can be found on some + Marvell Armada chips. -config STM32MP_WATCHDOG_TIMEOUT_SECS - int "IWDG watchdog timeout" - depends on STM32MP_WATCHDOG - default 32 +config WDT_SANDBOX + bool "Enable Watchdog Timer support for Sandbox" + depends on SANDBOX && WDT help - Configure the timeout for IWDG (default: 32s). + Enable Watchdog Timer support in Sandbox. This is a dummy device that + can be probed and supports all of the methods of WDT, but does not + really do anything. config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" @@ -126,11 +133,4 @@ config XILINX_TB_WATCHDOG Select this to enable Xilinx Axi watchdog timer, which can be found on some Xilinx Microblaze Platforms. -config IMX_WATCHDOG - bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" - select HW_WATCHDOG - help - Select this to enable the IMX and LSCH2 of Layerscape watchdog - driver. - endmenu From 36a7d40ef974b0cea328bf02a77307561a7e3d78 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 8 Feb 2019 11:29:33 +0100 Subject: [PATCH 064/244] watchdog: stm32mp: Convert driver to use WDT UCLASS Change-Id: I7f129ade72164bae91d8805b2eb9468f9b70101a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125146 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- common/board_f.c | 2 +- configs/stm32mp15_basic_defconfig | 1 - configs/stm32mp15_optee_defconfig | 1 - configs/stm32mp15_trusted_defconfig | 1 - drivers/watchdog/Kconfig | 23 ++---- drivers/watchdog/Makefile | 2 +- drivers/watchdog/stm32mp_wdt.c | 120 ++++++++++++++++------------ 7 files changed, 81 insertions(+), 69 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index 59745d5bf704..1a3b1c71ca0a 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -92,7 +92,7 @@ static int init_func_watchdog_init(void) (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ - defined(CONFIG_IMX_WATCHDOG) || defined(CONFIG_STM32MP_WATCHDOG)) + defined(CONFIG_IMX_WATCHDOG)) hw_watchdog_init(); puts(" Watchdog enabled\n"); # endif diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 7230feb442e0..e1ae9af20592 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -120,6 +120,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_STM32MP_WATCHDOG=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index ad1bf46fd523..bebc823130ca 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -106,6 +106,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_STM32MP_WATCHDOG=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index d5767e798732..f7af5c8fcf61 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -105,6 +105,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_STM32MP_WATCHDOG=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 85579327dc1a..5bae563ae660 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -35,21 +35,6 @@ config OMAP_WATCHDOG help Say Y here to enable the OMAP3+ watchdog driver. -config STM32MP_WATCHDOG - bool "Enable IWDG watchdog driver for STM32 MP's family" - depends on ARCH_STM32MP - select HW_WATCHDOG - help - Enable the STM32 watchdog (IWDG) driver. Enable support to - configure STM32's on-SoC watchdog. - -config STM32MP_WATCHDOG_TIMEOUT_SECS - int "IWDG watchdog timeout" - depends on STM32MP_WATCHDOG - default 32 - help - Configure the timeout for IWDG (default: 32s). - config TANGIER_WATCHDOG bool "Intel Tangier watchdog" depends on INTEL_MID @@ -125,6 +110,14 @@ config WDT_SANDBOX can be probed and supports all of the methods of WDT, but does not really do anything. +config WDT_STM32MP + bool "IWDG watchdog driver for STM32 MP's family" + depends on WDT + imply WATCHDOG + help + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 25491cf70c42..6374b5b30054 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -23,4 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o -obj-$(CONFIG_STM32MP_WATCHDOG) += stm32mp_wdt.o \ No newline at end of file +obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c index 696be1b6d6a5..ea85e41daee3 100644 --- a/drivers/watchdog/stm32mp_wdt.c +++ b/drivers/watchdog/stm32mp_wdt.c @@ -1,16 +1,15 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include #include #include -#include #include -#include +#include #include -#include +#include /* IWDG registers */ #define IWDG_KR 0x00 /* Key register */ @@ -29,36 +28,78 @@ /* IWDG_RLR register values */ #define RLR_MAX 0xFFF /* Max value supported by reload register */ -static fdt_addr_t stm32mp_wdt_base - __attribute__((section(".data"))) = FDT_ADDR_T_NONE; +/* IWDG_SR register bit values */ +#define SR_PVU BIT(0) /* Watchdog prescaler value update */ +#define SR_RVU BIT(1) /* Watchdog counter reload value update */ -void hw_watchdog_reset(void) +#define DEFAULT_TIMEOUT_SECS 32 /* default timeout */ + +struct stm32mp_wdt_priv { + fdt_addr_t base; /* registers addr in physical memory */ + u32 timeout; /* timeout in seconds */ + unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ +}; + +static int stm32mp_wdt_reset(struct udevice *dev) { - if (stm32mp_wdt_base != FDT_ADDR_T_NONE) - writel(KR_KEY_RELOAD, stm32mp_wdt_base + IWDG_KR); + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + + writel(KR_KEY_RELOAD, priv->base + IWDG_KR); + + return 0; } -void hw_watchdog_init(void) +static int stm32mp_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { - struct regmap *map; + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + int reload; + u32 val; + int ret; + + /* Prescaler fixed to 256 */ + reload = (priv->timeout * 1000) * priv->wdt_clk_rate / 256; + if (reload > RLR_MAX + 1) + /* Force to max watchdog counter reload value */ + reload = RLR_MAX + 1; + else if (!reload) + /* Force to min watchdog counter reload value */ + reload = priv->wdt_clk_rate / 256; + + /* Set prescaler & reload registers */ + writel(KR_KEY_EWA, priv->base + IWDG_KR); + writel(PR_256, priv->base + IWDG_PR); + writel(reload - 1, priv->base + IWDG_RLR); - map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_IWDG); - if (!IS_ERR(map)) - stm32mp_wdt_base = map->ranges[0].start; - else - printf("%s: iwdg init error", __func__); + /* Enable watchdog */ + writel(KR_KEY_ENABLE, priv->base + IWDG_KR); + + /* Wait for the registers to be updated */ + ret = readl_poll_timeout(priv->base + IWDG_SR, val, + val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ); + + if (ret < 0) { + pr_err("Updating IWDG registers timeout"); + return -ETIMEDOUT; + } + + return 0; } static int stm32mp_wdt_probe(struct udevice *dev) { - struct regmap *map = syscon_get_regmap(dev); + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); struct clk clk; - int ret, reload; - u32 time_start; - ulong regmap_base = map->ranges[0].start; + int ret; debug("IWDG init\n"); + priv->base = devfdt_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->timeout = dev_read_u32_default(dev, "timeout-sec", + DEFAULT_TIMEOUT_SECS); + /* Enable clock */ ret = clk_get_by_name(dev, "pclk", &clk); if (ret) @@ -73,47 +114,28 @@ static int stm32mp_wdt_probe(struct udevice *dev) if (ret) return ret; - /* Prescaler fixed to 256 */ - reload = CONFIG_STM32MP_WATCHDOG_TIMEOUT_SECS * - clk_get_rate(&clk) / 256; - if (reload > RLR_MAX + 1) - /* Force to max watchdog counter reload value */ - reload = RLR_MAX + 1; - else if (!reload) - /* Force to min watchdog counter reload value */ - reload = clk_get_rate(&clk) / 256; - - /* Enable watchdog */ - writel(KR_KEY_ENABLE, regmap_base + IWDG_KR); - - /* Set prescaler & reload registers */ - writel(KR_KEY_EWA, regmap_base + IWDG_KR); - writel(PR_256, regmap_base + IWDG_PR); - writel(reload - 1, regmap_base + IWDG_RLR); - - /* Wait for the registers to be updated */ - time_start = get_timer(0); - while (readl(regmap_base + IWDG_SR)) { - if (get_timer(time_start) > CONFIG_SYS_HZ) { - pr_err("Updating IWDG registers timeout"); - return -ETIMEDOUT; - } - } + priv->wdt_clk_rate = clk_get_rate(&clk); debug("IWDG init done\n"); return 0; } +static const struct wdt_ops stm32mp_wdt_ops = { + .start = stm32mp_wdt_start, + .reset = stm32mp_wdt_reset, +}; + static const struct udevice_id stm32mp_wdt_match[] = { - { .compatible = "st,stm32mp1-iwdg", - .data = STM32MP_SYSCON_IWDG }, + { .compatible = "st,stm32mp1-iwdg" }, { /* sentinel */ } }; U_BOOT_DRIVER(stm32mp_wdt) = { .name = "stm32mp-wdt", - .id = UCLASS_SYSCON, + .id = UCLASS_WDT, .of_match = stm32mp_wdt_match, + .priv_auto_alloc_size = sizeof(struct stm32mp_wdt_priv), .probe = stm32mp_wdt_probe, + .ops = &stm32mp_wdt_ops, }; From 6f250948c25532bdb63d32ed1c0210f1b4486bca Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 8 Feb 2019 16:09:31 +0100 Subject: [PATCH 065/244] board: stm32mp1: Start watchdog Add watchdog_start() call in both basic and trusted mode. Add also the watchdog_reset(). Change-Id: I4a94420abe5b5603bedbf72dee58effad7d08b70 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125147 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/cpu.c | 54 +++++++++++++++++++ .../arm/mach-stm32mp/include/mach/sys_proto.h | 2 + arch/arm/mach-stm32mp/spl.c | 2 + 3 files changed, 58 insertions(+) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 5384dff96905..11f32367e94a 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -528,8 +529,61 @@ static int setup_serial_number(void) return 0; } + +#if defined(CONFIG_WDT) && \ +(defined(CONFIG_SPL_WATCHDOG_SUPPORT) || !defined(CONFIG_SPL_BUILD)) +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ + static ulong next_reset; + struct udevice *watchdog_dev; + ulong now; + + now = timer_get_us(); + + /* Do not reset the watchdog too often, only every 1 sec */ + if (now > next_reset) { + /* + * Watchdog has been enabled at SPL stage, to avoid + * watchdog_dev bad reference after relocation, we don't save + * it in a static variable, we retrieve it each time using + * uclass_get_device() call. + */ + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) + return; + + wdt_reset(watchdog_dev); + next_reset = now + 1000000; + } +} + +int watchdog_start(void) +{ + struct udevice *watchdog_dev; + + if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) { + debug("Watchdog: Not found by seq!\n"); + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + return 0; + } + } + + wdt_start(watchdog_dev, 0, 0); + printf("Watchdog: Started\n"); + + return 0; +} +#else +int watchdog_start(void) +{ + return 0; +} +#endif + int arch_misc_init(void) { + watchdog_start(); setup_boot_mode(); setup_mac_address(); setup_serial_number(); diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 71a3ba794d11..7ff9067a2348 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -21,3 +21,5 @@ u32 get_cpu_type(void); u32 get_cpu_rev(void); /* return boot mode */ u32 get_bootmode(void); +/* start IWDG watchdog */ +int watchdog_start(void); diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index b47e74dcfbaa..78b753248418 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -118,6 +118,8 @@ void board_init_f(ulong dummy) /* enable console uart printing */ preloader_console_init(); + watchdog_start(); + ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { printf("DRAM init failed: %d\n", ret); From 6403ca7be65a9bebe46140531a8f60c84643e254 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 8 Feb 2019 16:38:23 +0100 Subject: [PATCH 066/244] configs: stm32mp15: Enable WDT flags This allows to enable WATCHDOG and WDT flags to be able to reset the watchdog and to support watchdog driver model. Change-Id: I9287e4b2b9f4fa14c7eb2d0280e03736eb57cf3f Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125148 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_optee_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 3 files changed, 6 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index e1ae9af20592..0c6d6584b4c2 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -120,5 +120,7 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index bebc823130ca..be55a601f635 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -106,5 +106,7 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index f7af5c8fcf61..95b4f982ac7b 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -105,5 +105,7 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set From a093c9007d5f1a05903217219d4021ffa87f3ae8 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 13 Feb 2019 12:51:02 +0100 Subject: [PATCH 067/244] stm32mp1: cosmetic: cleanup Alignment with upstream Change-Id: I65617d1698f7d519dddb906e85480042c0b83caf Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125699 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/Kconfig | 14 +++++++------- arch/arm/mach-stm32mp/cpu.c | 2 +- arch/arm/mach-stm32mp/spl.c | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index fbc81953d72d..58950a07427d 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -68,7 +68,7 @@ config STM32MP1_TRUSTED 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 provide ST smc to manage secure devices + TF-A monitor provides proprietary smc to manage secure devices config STM32MP1_OPTEE bool "Support trusted boot with TF-A and OPTEE" @@ -96,8 +96,6 @@ config STM32_ETZPC Say y to enable STM32 Extended TrustZone Protection Controller (ETZPC) -source "board/st/stm32mp1/Kconfig" - config CMD_STM32PROG bool "command stm32prog for STM32CudeProgrammer" default y @@ -149,6 +147,10 @@ config SYS_BOOTCOUNT_ADDR endif if DEBUG_UART + +config DEBUG_UART_BOARD_INIT + default y + # debug on UART4 by default config DEBUG_UART_BASE default 0x40010000 @@ -156,10 +158,8 @@ config DEBUG_UART_BASE # clock source is HSI on reset config DEBUG_UART_CLOCK default 64000000 - -# currently activated for debug / should be deactivated for real product -config DEBUG_UART_BOARD_INIT - default y endif +source "board/st/stm32mp1/Kconfig" + endif diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 11f32367e94a..56bb12c56d7c 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -224,7 +224,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) &&\ +#if defined(CONFIG_DEBUG_UART) && \ !defined(CONFIG_STM32MP1_TRUSTED) && \ (!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)) else diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 78b753248418..6c8744f8dc34 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -49,6 +49,7 @@ u32 spl_boot_device(void) case BOOT_FLASH_NOR_QSPI: return BOOT_DEVICE_SPI; } + return BOOT_DEVICE_MMC1; } From 48b24d63633c92149895d621fee6efd65641a061 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 15 Feb 2019 10:02:12 +0100 Subject: [PATCH 068/244] board: stm32mp1: Remove usage of temporary usb1600 property usb1600 property was temporary introduced by 'commit b2b7fd4c4b9f ("ARM: dts: stmp32: add usb1600 in usbo node for u-boot for stm32mp157a-dk1")' to be able to manage different usb initialization between EV1 and DK1/2 board. Since kernel DT is using new node stusb1600 describing the USB type-C controller for DK1/2 boards. Test this node presence in DT instead and remove the usb1600 property. Change-Id: I5ee255432773813cc2399c8606e0aef62a9f3062 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125841 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index c8bab44efa35..6347fd10f9ff 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -235,19 +235,12 @@ static struct reset_ctl usbotg_reset; /* STUSB1600_CC_CONNECTION_STATUS bitfields */ #define STUSB1600_CC_ATTACH BIT(0) -static int stusb1600_init(void) +static int stusb1600_init(ofnode node) { struct udevice *dev, *bus; - ofnode node; int ret; u32 chip_addr; - node = ofnode_by_compatible(ofnode_null(), "st,stusb1600"); - if (!ofnode_valid(node)) { - printf("stusb1600 not found\n"); - return -ENODEV; - } - ret = ofnode_read_u32(node, "reg", &chip_addr); if (ret) return -EINVAL; @@ -281,6 +274,7 @@ static int stusb1600_cable_connected(void) void board_usbotg_init(void) { + ofnode usb1600_node; int node; struct fdtdec_phandle_args args; struct udevice *dev; @@ -361,8 +355,10 @@ void board_usbotg_init(void) stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node, "g-tx-fifo-size", 0); - if (fdtdec_get_bool(blob, node, "usb1600")) { - stusb1600_init(); + /* if node stusb1600 is present, means DK1 or DK2 board */ + usb1600_node = ofnode_by_compatible(ofnode_null(), "st,stusb1600"); + if (ofnode_valid(usb1600_node)) { + stusb1600_init(usb1600_node); return; } From e7d2582fac0bdec297debcac38f325535333c6bf Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 15 Feb 2019 10:05:23 +0100 Subject: [PATCH 069/244] ARM: dts: stm32: Remove usb1600 property for stm32mp157a-dk1-u-boot This property was introduced temporary to manage different USB initialization between EV1 and DK1/2 boards. Now the presence of stusb1600 node is used. So remove the usb1600 property. Change-Id: I02f048b8614143bee9949219b62cf4649ca02a96 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125842 Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 08b198eb9275..33fe1d0713c1 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -176,7 +176,6 @@ }; &usbotg_hs { - usb1600; hnp-srp-disable; }; From 3b5b7158a76140b18d199b63dcf12bae513d3298 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 14 Feb 2019 17:09:37 +0100 Subject: [PATCH 070/244] srm32mp1: ram: add Loop and Address for some tests Add parameter for the last-added tests (come from memtester) in SPL DDR interactive mode - BlockSequential - Checkerboard - BitSpread - BitFlip - WalkingOnes - WalkingZeroes Change-Id: I32092640a765db68466474d90a9536410c7e5ce9 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125786 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/ram/stm32mp1/stm32mp1_tests.c | 292 ++++++++++++++++---------- 1 file changed, 179 insertions(+), 113 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 5f2af4ede78b..9006bac82293 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -993,24 +993,34 @@ static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr; + int i; u32 checkboard[2] = {0x55555555, 0xAAAAAAAA}; if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running test checkboard at 0x%08x length 0x%x\n", - STM32_DDR_BASE, bufsize); - - res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, - bufsize); - - checkboard[0] = ~checkboard[0]; - checkboard[1] = ~checkboard[1]; - - res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, - bufsize); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 2; i++) { + res = test_loop_size(checkboard, 2, (u32 *)addr, + bufsize); + if (res) + return res; + checkboard[0] = ~checkboard[0]; + checkboard[1] = ~checkboard[1]; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; + } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1020,23 +1030,31 @@ static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 256; i++) { - value = i | i << 8 | i << 16 | i << 24; - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 256; i++) { + value = i | i << 8 | i << 16 | i << 24; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1046,27 +1064,35 @@ static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 64; i++) { - if (i < 32) - value = 1 << i; - else - value = 1 << (63 - i); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 64; i++) { + if (i < 32) + value = 1 << i; + else + value = 1 << (63 - i); - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1076,27 +1102,35 @@ static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 64; i++) { - if (i < 32) - value = ~(1 << i); - else - value = ~(1 << (63 - i)); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 64; i++) { + if (i < 32) + value = ~(1 << i); + else + value = ~(1 << (63 - i)); - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1110,34 +1144,42 @@ static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, bitspread[4]; int i, j; - u32 bitspread[4]; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 1; i < 32; i++) { - for (j = 0; j < i; j++) { - if (i < 32) - bitspread[0] = (1 << i) | (1 << j); - else - bitspread[0] = (1 << (63 - i)) | - (1 << (63 - j)); - bitspread[1] = bitspread[0]; - bitspread[2] = ~bitspread[0]; - bitspread[3] = ~bitspread[0]; - printf("pattern = %08x", bitspread[0]); - - res = test_loop_size(bitspread, 4, - (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 1; i < 32; i++) { + for (j = 0; j < i; j++) { + if (i < 32) + bitspread[0] = (1 << i) | (1 << j); + else + bitspread[0] = (1 << (63 - i)) | + (1 << (63 - j)); + bitspread[1] = bitspread[0]; + bitspread[2] = ~bitspread[0]; + bitspread[3] = ~bitspread[0]; + printf("pattern = %08x", bitspread[0]); + + res = test_loop_size(bitspread, 4, (u32 *)addr, + bufsize); + if (res != TEST_PASSED) + return res; + } } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1147,27 +1189,37 @@ static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr; int i; u32 bitflip[4]; if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; + + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 32; i++) { + bitflip[0] = 1 << i; + bitflip[1] = bitflip[0]; + bitflip[2] = ~bitflip[0]; + bitflip[3] = bitflip[2]; + printf("pattern = %08x", bitflip[0]); - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 32; i++) { - bitflip[0] = 1 << i; - bitflip[1] = bitflip[0]; - bitflip[2] = ~bitflip[0]; - bitflip[3] = bitflip[2]; - printf("pattern = %08x", bitflip[0]); - - res = test_loop_size(bitflip, 4, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + res = test_loop_size(bitflip, 4, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1259,24 +1311,38 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, { enum test_result res = TEST_PASSED, result; int i, nb_error = 0; + u32 loop = 0, nb_loop; - /* execute all the test except the lasts which are infinite */ - for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { - printf("execute %d:%s\n", (int)i, test[i].name); - result = test[i].fct(ctl, phy, string, 0, NULL); - printf("result %d:%s = ", (int)i, test[i].name); - if (result != TEST_PASSED) { - nb_error++; - res = TEST_FAILED; - puts("Failed"); - } else { - puts("Passed"); + if (get_nb_loop(string, argc, argv, 0, &nb_loop, 1)) + return TEST_ERROR; + + while (!nb_error) { + /* execute all the test except the lasts which are infinite */ + for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { + printf("execute %d:%s\n", (int)i, test[i].name); + result = test[i].fct(ctl, phy, string, 0, NULL); + printf("result %d:%s = ", (int)i, test[i].name); + if (result != TEST_PASSED) { + nb_error++; + res = TEST_FAILED; + puts("Failed"); + } else { + puts("Passed"); + } + puts("\n\n"); } - puts("\n\n"); + printf("loop %d: %d/%d test failed\n\n\n", + loop + 1, nb_error, test_nb - NB_TEST_INFINITE); + if (test_loop_end(&loop, nb_loop, 1)) + break; + } + if (res != TEST_PASSED) { + sprintf(string, "loop %d: %d/%d test failed", loop, nb_error, + test_nb - NB_TEST_INFINITE); + } else { + sprintf(string, "loop %d: %d tests passed", loop, + test_nb - NB_TEST_INFINITE); } - sprintf(string, "%d/%d test failed", nb_error, - test_nb - NB_TEST_INFINITE); - return res; } @@ -1285,7 +1351,7 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, ****************************************************************/ const struct test_desc test[] = { - {test_all, "All", "", "Execute all tests", 0 }, + {test_all, "All", "[loop]", "Execute all tests", 1 }, {test_databus, "Simple DataBus", "[addr]", "Verifies each data line by walking 1 on fixed address", 1 @@ -1326,29 +1392,29 @@ const struct test_desc test[] = { "write & test patterns: Mostly Zero, Mostly One and F/n", 1 }, - {test_blockseq, "BlockSequential", "[size]", + {test_blockseq, "BlockSequential", "[size] [loop] [addr]", "test incremental pattern", - 1 + 3 }, - {test_checkboard, "Checkerboard", "[size]", + {test_checkboard, "Checkerboard", "[size] [loop] [addr]", "test checker pattern", - 1 + 3 }, - {test_bitspread, "BitSpread", "[size]", + {test_bitspread, "BitSpread", "[size] [loop] [addr]", "test Bit Spread pattern", - 1 + 3 }, - {test_bitflip, "BitFlip", "[size]", + {test_bitflip, "BitFlip", "[size] [loop] [addr]", "test Bit Flip pattern", - 1 + 3 }, - {test_walkbit0, "WalkingOnes", "[size]", + {test_walkbit0, "WalkingOnes", "[size] [loop] [addr]", "test Walking Ones pattern", - 1 + 3 }, - {test_walkbit1, "WalkingZeroes", "[size]", + {test_walkbit1, "WalkingZeroes", "[size] [loop] [addr]", "test Walking Zeroes pattern", - 1 + 3 }, /* need to the the 2 last one (infinite) : skipped for test all */ {test_read, "infinite read", "[addr]", From 2545f10899595b1057181d231e4524e126c95d83 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 14 Feb 2019 12:02:01 +0100 Subject: [PATCH 071/244] stm32mp1: stm32prog command: use linux reserved UUID for RAW partiton The specification request that "Binary" partition in flash layout use the the linux reserved UUID (GUID = 8DA63339-0007-60C0-C436-083AC8230908). That to avoid auto mount request in Linux. The previous used UUID data, was used for Windows FAT file system. See https://wiki.st.com/stm32mpu/index.php/STM32CubeProgrammer_flashlayout chapter GPT_partition_of_block_device-_SD_card_-2F_eMMC and https://en.wikipedia.org/wiki/Microsoft_basic_data_partition Change-Id: I2559720b86474d10551d51c2d96af687e7bfb58f Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125748 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index d263b3859405..5cc1f0ab7e10 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -46,6 +46,9 @@ EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \ 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18) +/* RAW parttion (binary / bootloader) used Linux - reserved UUID */ +#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908" + /* * unique partition guid (uuid) for partition named "rootfs" * on each MMC instance = SD Card or eMMC @@ -874,7 +877,8 @@ static int create_partitions(struct stm32prog_data *data) if (part->part_type == PART_BINARY) offset += snprintf(buf + offset, ENV_BUF_LEN - offset, - ",type=data"); + ",type=" + LINUX_RESERVED_UUID); else offset += snprintf(buf + offset, ENV_BUF_LEN - offset, From 3eee756d7a59c31e54209c56307bfbce7fc67db4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 14 Feb 2019 10:03:22 +0100 Subject: [PATCH 072/244] stm32mp: cosmetics: rename stm32mp1_helper_dbg.S Remane stm32mp1_helper_dgb.S to stm32mp1_helper_dbg.S Change-Id: Ib80d45f0a4e39c43854e5287a81314ebc00d4a4f Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125738 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/Makefile | 2 +- .../{stm32mp1_helper_dgb.S => stm32mp1_helper_dbg.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arm/mach-stm32mp/{stm32mp1_helper_dgb.S => stm32mp1_helper_dbg.S} (100%) diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index c67bccea8c8c..b09a2cade59c 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -9,7 +9,7 @@ obj-y += syscon.o ifdef CONFIG_SPL_BUILD obj-y += spl.o -obj-$(CONFIG_STM32MP1_RESET_HALT_WORKAROUND) += stm32mp1_helper_dgb.o +obj-$(CONFIG_STM32MP1_RESET_HALT_WORKAROUND) += stm32mp1_helper_dbg.o else obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S similarity index 100% rename from arch/arm/mach-stm32mp/stm32mp1_helper_dgb.S rename to arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S From 3b8056ccbcc43960547891afa395bf90fcd12426 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 14 Feb 2019 11:36:23 +0100 Subject: [PATCH 073/244] stm32mp1: reset halt workaround: no debug if sec close device If sec close device, DBGMCU can't be accessed, so we do not debug in this case. Information is stored in bit 6 of OTP0 data. Change-Id: I067b37286e7af30cab318b4cad5bddd27104816a Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125739 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S index 29f8e1f8ee17..37a1b062d16d 100644 --- a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S +++ b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S @@ -17,6 +17,9 @@ #define BIT(nr) (1 << (nr)) +#define BSEC_OTP_DATA0_ADDR 0x5C005200 +#define BSEC_OTP_DATA0_CLOSED BIT(6) + #define DBG_DSCR_ADDR 0x500D0088 #define DBG_DSCR_HDBGEN BIT(14) @@ -46,6 +49,15 @@ ENTRY(save_boot_params) * conditions closed to the initial context. */ + /* + * Check Sec Close bit in OTP (word 0 bit 6). If enabled, do not allow + * debug session and exit function. + */ + ldr r12, =BSEC_OTP_DATA0_ADDR + ldr r12, [r12] + ands r11, r12, #BSEC_OTP_DATA0_CLOSED + bne func_exit + /* Check Soc revision */ ldr r12, =RCC_DBGCFGR_ADDR ldr r11, [r12] /* read RCC_DBGCFGR (r11) */ From d412c90472732c67396e3b51168dc08762cf1486 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Feb 2019 18:48:06 +0100 Subject: [PATCH 074/244] stm32mp1: add op-tee defconfig in README Change-Id: I6ddc2b99066d9d861f0e8b8f8f6f3ea8d9fb1727 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125566 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/README | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 4ebcfb4ad7ce..c3365c675f5d 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -49,20 +49,26 @@ BootRom => FSBL in SYSRAM => SSBL in DDR => OS (Linux Kernel) with FSBL = First Stage Bootloader SSBL = Second Stage Bootloader -2 boot configurations are supported: +3 boot configurations are supported: 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 + to access to secure resources. -2) The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig) +2) The "Trusted & OP-TEE" boot chain (defconfig_file : stm32mp15_optee_defconfig) + BootRom => FSBL = Trusted Firmware-A (TF-A) => SSBL = U-Boot + TF-A performs a full initialization of Secure peripherals and installs OP-TEE + from specific partitions (teeh, teed, teex). + U-Boot is running in normal world and uses OP-TEE monitor to access. + +3) 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) + with only PSCI support (Power State Coordination Interface defined by ARM). All the STM32MP1 boards supported by U-Boot use the same generic board stm32mp1 which support all the bootable devices. @@ -108,13 +114,18 @@ the supported device trees for stm32mp157 are: for example: use one output directory for each configuration # export KBUILD_OUTPUT=stm32mp15_trusted + # export KBUILD_OUTPUT=stm32mp15_optee # export KBUILD_OUTPUT=stm32mp15_basic + you can build outside of code directory: + # export KBUILD_OUTPUT=../build/stm32mp15_trusted + 4. Configure U-Boot: # make - For trusted boot mode : "stm32mp15_trusted_defconfig" + - For trusted & optee boot mode : "stm32mp15_optee_defconfig" - For basic boot mode: "stm32mp15_basic_defconfig" 5. Configure the device-tree and build the U-Boot image: @@ -127,7 +138,12 @@ the supported device trees for stm32mp157 are: # make stm32mp15_trusted_defconfig # make DEVICE_TREE=stm32mp157c-ev1 all - b) basic boot on dk2 + b) trusted & OP-TEE boot on dk1 + # export KBUILD_OUTPUT=stm32mp15_optee + # make stm32mp15_optee_defconfig + # make DEVICE_TREE=stm32mp157a-dk1 all + + c) basic boot on dk2 # export KBUILD_OUTPUT=stm32mp15_basic # make stm32mp15_basic_defconfig # make DEVICE_TREE=stm32mp157c-dk2 all @@ -140,7 +156,7 @@ 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 + a) For Trusted boot (with or without OP-TEE) + FSBL = tf-a.stm32 (provided by TF-A compilation) + SSBL = u-boot.stm32 From 1a9a49c696a81ac05a11c6e6ed2a4d1a102b2f5e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 09:42:32 +0100 Subject: [PATCH 075/244] stm32mp1: dts: dk1: remove v3v3 node in u-boot dtsi Remove the duplicate property regulator-always-on, already present in kernel devicetree stm32mp157a-dk1.dts. Change-Id: If3628c8b6fd8867958b79c366f1d24896b673784 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125847 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 33fe1d0713c1..5c9e6b9f66e7 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -178,7 +178,3 @@ &usbotg_hs { hnp-srp-disable; }; - -&v3v3 { - regulator-always-on; -}; From 466fa08754c9dc4a5c7021ee1bf070b5805751d0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 13:05:18 +0100 Subject: [PATCH 076/244] stm32mp1: dts: remove propertie hnp-srp-disable "hnp-srp-disable" property of usbotg_hs node must be enable ONLY for HOST support but it is not activated by default, so it can be removed. Change-Id: Ic25545e8492aed0d1a0c228e8bcdba6f2aaacbdc Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125848 --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 5c9e6b9f66e7..f1a22249ffab 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -174,7 +174,3 @@ bias-pull-up; }; }; - -&usbotg_hs { - hnp-srp-disable; -}; From 702c220c6a572a3ec68bcc65638d601345445ac0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 15:36:41 +0100 Subject: [PATCH 077/244] cmd: stm32prog: delay NACK when checksum error is detected Wait few ms to be sure that all data are received in the FIFO of UART before flush it; that avoid synchronization error when NACK is sent to STM32CubeProgrammer, so the commit improves the serial programming robustness (rootfs can be updated without freeze). Change-Id: I08aa2c1555884932661639b2458ae57847549257 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/124967 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 36f9393d7610..7324d1d98806 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -729,6 +729,10 @@ static void download_command(struct stm32prog_data *data) if (rcv_xor != my_xor) { printf("checksum error on packet %d\n", packet_number); + /* wait to be sure that all data are received + * in the FIFO before flush + */ + mdelay(30); data->packet_number--; result = NACK_BYTE; goto end; @@ -951,7 +955,7 @@ bool stm32prog_serial_loop(struct stm32prog_data *data) /* wait to be sure that all data are received * in the FIFO before flush (CMD and XOR) */ - mdelay(2); + mdelay(3); stm32prog_serial_result(NACK_BYTE); } else { /*pr_debug("+ cmd %x\n", counter);*/ From 35bbb3e5619323f75182982dba141303c3a8af1d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 4 Feb 2019 11:33:19 +0100 Subject: [PATCH 078/244] cmd: stm32prog: reload watchdog in getc loop The command stm32prog need to reload the watchdog to avoid reset for some error case (when U-Boot don't received data). Change-Id: I1f5b62ca79fbc654c5fd396fdf45a3f235fdb0f6 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/124966 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 7324d1d98806..7a3481754200 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -215,8 +215,10 @@ static int stm32prog_serial_getc_err(void) do { err = ops->getc(down_serial_dev); - if (err == -EAGAIN) + if (err == -EAGAIN) { ctrlc(); + WATCHDOG_RESET(); + } } while ((err == -EAGAIN) && (!had_ctrlc())); return err; @@ -243,6 +245,7 @@ static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count) *count -= 1; } else if (err == -EAGAIN) { ctrlc(); + WATCHDOG_RESET(); } else { break; } From c8521622a35d5931486ecbec73462d19272db4d6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 18 Feb 2019 11:24:27 +0100 Subject: [PATCH 079/244] stm32mp1: cosmetics: remove duplicated line Remove duplicated define CONFIG_SYS_MAX_NAND_DEVICE Change-Id: I7cb01c3f095bc79872c3f399dd9e291e4d520c2d Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125913 Reviewed-by: CITOOLS --- include/configs/stm32mp1.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 9000495a42ad..b826d4ce27c4 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -101,9 +101,6 @@ #define CONFIG_SYS_NAND_ONFI_DETECTION #define CONFIG_SYS_MAX_NAND_DEVICE 1 -/* SPI nand */ -#define CONFIG_SYS_MAX_NAND_DEVICE 1 - /* SPI FLASH support */ #if defined(CONFIG_SPL_BUILD) #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x80000 From 3efd0a5da1e1f1f4507cebaeda7eb92c89ddabcd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 20 Feb 2019 11:30:27 +0100 Subject: [PATCH 080/244] stm32mp1: cosmetics: remove unused STM32MP_SYSCON_IWDG Associated syscon driver no more exist, so the define STM32MP_SYSCON_IWDG can be removed. Change-Id: If84857521def1f98c00acc5b866ff6755e2094a2 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126115 Reviewed-by: CIBUILD Reviewed-by: CITOOLS --- arch/arm/mach-stm32mp/include/mach/stm32.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 36b885b108aa..b52dc76c4392 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -45,7 +45,6 @@ enum { STM32MP_SYSCON_UNKNOWN, STM32MP_SYSCON_ETZPC, - STM32MP_SYSCON_IWDG, STM32MP_SYSCON_PWR, STM32MP_SYSCON_STGEN, STM32MP_SYSCON_SYSCFG, From 624506fea3804ca7f10e1fb33f76e72ae8324739 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 21 Feb 2019 19:15:05 +0100 Subject: [PATCH 081/244] stm32mp1: cosmetic: update bootcmd Respect the 80 characters limitation, as done for up-streamed version of this patch. Change-Id: Id9ee103eb5a1c4cf02eefd8317ebb7cac3cd32a8 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126281 Reviewed-by: CIBUILD Reviewed-by: CITOOLS Reviewed-by: Patrice CHOTARD --- include/configs/stm32mp1.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index b826d4ce27c4..2a936895a8b1 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -147,14 +147,17 @@ */ #define CONFIG_PREBOOT #undef CONFIG_BOOTCOMMAND -#define CONFIG_BOOTCOMMAND "echo \"Boot over ${boot_device}${boot_instance}!\";run bootcmd_stm32mp" +#define CONFIG_BOOTCOMMAND \ + "echo \"Boot over ${boot_device}${boot_instance}!\";run bootcmd_stm32mp" #define STM32MP_BOOTCMD "bootcmd_stm32mp=" \ - "if test ${boot_device} = serial || test ${boot_device} = usb; then " \ - "stm32prog ${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;" \ + "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" From 81d312946c08aa108e4f7b18633e5172ca0bb3ae Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 20 Feb 2019 11:20:31 +0100 Subject: [PATCH 082/244] ram: stm32mp1: update parameter array initialization Force alignment of the size of parameters array with the expected value by the binding. Change-Id: I9fbdcc55b1cd18866fa9d0816475184fede2a650 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/125991 Reviewed-by: CIBUILD Reviewed-by: CITOOLS Reviewed-by: Patrice CHOTARD Reviewed-by: Nicolas LE BAYON --- .../ram/st,stm32mp1-ddr.txt | 2 +- drivers/ram/stm32mp1/stm32mp1_ddr.c | 74 ++++++++++++------- drivers/ram/stm32mp1/stm32mp1_ram.c | 4 +- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt index e5b1bb5e04f5..ee708ce92c78 100644 --- a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt +++ b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt @@ -102,7 +102,7 @@ controlleur attributes: phyc attributes: ---------------- - st,phy-reg : phy values depending of the DDR type (DDR3/LPDDR2/LPDDR3) - for STM32MP15x: 10 values are requested in this order + for STM32MP15x: 11 values are requested in this order PGCR ACIOCR DXCCR diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index 7b28f6308192..b0b73c298e17 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -41,8 +41,32 @@ struct reg_desc { offsetof(struct stm32mp1_ddrphy, x),\ offsetof(struct y, x)} +#define DDR_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrctl, x),\ + INVALID_OFFSET} + +#define DDRPHY_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrphy, x),\ + INVALID_OFFSET} + +/*********************************************************** + * PARAMETERS: value get from device tree : + * size / order need to be aligned with binding + * modification NOT ALLOWED !!! + ***********************************************************/ +#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */ +#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */ +#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */ +#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */ + +#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */ +#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */ +#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */ + #define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg) -static const struct reg_desc ddr_reg[] = { +static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = { DDRCTL_REG_REG(mstr), DDRCTL_REG_REG(mrctrl0), DDRCTL_REG_REG(mrctrl1), @@ -71,7 +95,7 @@ static const struct reg_desc ddr_reg[] = { }; #define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing) -static const struct reg_desc ddr_timing[] = { +static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = { DDRCTL_REG_TIMING(rfshtmg), DDRCTL_REG_TIMING(dramtmg0), DDRCTL_REG_TIMING(dramtmg1), @@ -87,7 +111,7 @@ static const struct reg_desc ddr_timing[] = { }; #define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map) -static const struct reg_desc ddr_map[] = { +static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = { DDRCTL_REG_MAP(addrmap1), DDRCTL_REG_MAP(addrmap2), DDRCTL_REG_MAP(addrmap3), @@ -100,7 +124,7 @@ static const struct reg_desc ddr_map[] = { }; #define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf) -static const struct reg_desc ddr_perf[] = { +static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = { DDRCTL_REG_PERF(sched), DDRCTL_REG_PERF(sched1), DDRCTL_REG_PERF(perfhpr1), @@ -121,7 +145,7 @@ static const struct reg_desc ddr_perf[] = { }; #define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg) -static const struct reg_desc ddrphy_reg[] = { +static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = { DDRPHY_REG_REG(pgcr), DDRPHY_REG_REG(aciocr), DDRPHY_REG_REG(dxccr), @@ -136,7 +160,7 @@ static const struct reg_desc ddrphy_reg[] = { }; #define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing) -static const struct reg_desc ddrphy_timing[] = { +static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = { DDRPHY_REG_TIMING(ptr0), DDRPHY_REG_TIMING(ptr1), DDRPHY_REG_TIMING(ptr2), @@ -150,7 +174,7 @@ static const struct reg_desc ddrphy_timing[] = { }; #define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal) -static const struct reg_desc ddrphy_cal[] = { +static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = { DDRPHY_REG_CAL(dx0dllcr), DDRPHY_REG_CAL(dx0dqtr), DDRPHY_REG_CAL(dx0dqstr), @@ -165,11 +189,9 @@ static const struct reg_desc ddrphy_cal[] = { DDRPHY_REG_CAL(dx3dqstr), }; -#define DDR_REG_DYN(x) \ - {#x,\ - offsetof(struct stm32mp1_ddrctl, x),\ - INVALID_OFFSET} - +/************************************************************** + * DYNAMIC REGISTERS: only used for debug purpose (read/modify) + **************************************************************/ static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(stat), DDR_REG_DYN(init0), @@ -181,10 +203,7 @@ static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(pctrl_1), }; -#define DDRPHY_REG_DYN(x) \ - {#x,\ - offsetof(struct stm32mp1_ddrphy, x),\ - INVALID_OFFSET} +#define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn) static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(pir), @@ -201,6 +220,11 @@ static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(dx3gsr1), }; +#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn) + +/***************************************************************** + * REGISTERS ARRAY: used to parse device tree and interactive mode + *****************************************************************/ enum reg_type { REG_REG, REG_TIMING, @@ -234,23 +258,23 @@ struct ddr_reg_info { const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { [REG_REG] = { - "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE}, + "static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE}, [REG_TIMING] = { - "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE}, + "timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE}, [REG_PERF] = { - "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE}, + "perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE}, [REG_MAP] = { - "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE}, + "map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE}, [REGPHY_REG] = { - "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE}, + "static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE}, [REGPHY_TIMING] = { - "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE}, + "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE}, [REGPHY_CAL] = { - "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE}, + "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE}, [REG_DYN] = { - "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE}, + "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE}, [REGPHY_DYN] = { - "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE}, + "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE}, }; const char *base_name[] = { diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index 6245cb419eed..8d62c2943736 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -103,8 +103,8 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) debug("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret); if (ret) { - pr_err("%s: Cannot read %s\n", - __func__, param[idx].name); + pr_err("%s: Cannot read %s, error=%d\n", + __func__, param[idx].name, ret); return -EINVAL; } } From 790b4cd7dc541d40091bfa152aa3cbfb0d422184 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 15 Feb 2019 18:13:32 +0100 Subject: [PATCH 083/244] usb: dwc2_udc_otg: Read MAX_HW_ENDPOINT from HWCFG4 register Some DWC2 ip variant doesn't use 16 hardware endpoint as hardcoded in the driver. Bits INEps [29:26] of HWCFG4 register allows to get this information. Change-Id: Iaf1646eab749b898c2fb5c7e5a70d76ceebb2101 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125882 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/usb/gadget/dwc2_udc_otg.c | 7 ++++++- drivers/usb/gadget/dwc2_udc_otg_priv.h | 1 - drivers/usb/gadget/dwc2_udc_otg_regs.h | 17 ++++++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 6552a5b2385e..7a7c042d3bcb 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -401,6 +401,7 @@ static void reconfig_usbd(struct dwc2_udc *dev) unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); uint32_t dflt_gusbcfg; uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; + u32 max_hw_ep; debug("Reseting OTG controller\n"); @@ -486,7 +487,11 @@ static void reconfig_usbd(struct dwc2_udc *dev) writel((np_tx_fifo_sz << 16) | rx_fifo_sz, ®->gnptxfsiz); - for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++) + /* retrieve the number of TX fifo */ + max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> + GHWCFG4_NUM_IN_EPS_SHIFT; + + for (i = 1; i < max_hw_ep; i++) writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) | tx_fifo_sz << 16, ®->dieptxf[i-1]); diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h index b64e222b6d7e..a092f43ecfa4 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_priv.h +++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h @@ -24,7 +24,6 @@ #define EP_FIFO_SIZE2 1024 /* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */ #define DWC2_MAX_ENDPOINTS 4 -#define DWC2_MAX_HW_ENDPOINTS 16 #define WAIT_FOR_SETUP 0 #define DATA_STATE_XMIT 1 diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index b6852561914e..449b2088d84b 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -60,22 +60,24 @@ struct dwc2_usbotg_reg { u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ u32 grxfsiz; /* Receive FIFO Size */ u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - u8 res1[216]; + u8 res1[36]; + u32 ghwcfg4; /* User HW Config4 */ + u8 res2[176]; u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ - u8 res2[1728]; + u8 res3[1728]; /* Device Configuration */ u32 dcfg; /* Device Configuration Register */ u32 dctl; /* Device Control */ u32 dsts; /* Device Status */ - u8 res3[4]; + u8 res4[4]; u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */ u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */ u32 daint; /* Device All Endpoints Interrupt */ u32 daintmsk; /* Device All Endpoints Interrupt Mask */ - u8 res4[224]; + u8 res5[224]; struct dwc2_dev_in_endp in_endp[16]; struct dwc2_dev_out_endp out_endp[16]; - u8 res5[768]; + u8 res6[768]; struct ep_fifo ep[16]; }; @@ -273,4 +275,9 @@ struct dwc2_usbotg_reg { /* Device ALL Endpoints Interrupt Register (DAINT) */ #define DAINT_IN_EP_INT(x) (x << 0) #define DAINT_OUT_EP_INT(x) (x << 16) + +/* User HW Config4 */ +#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT 26 + #endif From 6bdb3885bf1982e48d2f93043ec6a1f2bb14ecc3 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 15 Feb 2019 18:15:23 +0100 Subject: [PATCH 084/244] usb: dwc2_udc_otg: Add tx_fifo_sz array support All TX fifo size can be different, add tx_fifo_sz_array[] into dwc2_plat_otg_data to be able to set them. tx_fifo_sz_array[] is 17 Bytes long and can contains max 16 tx fifo size (synopsys IP supports max 16 IN endpoints). First entry of tx_fifo_sz_array[] is the number of element the array contains. In case of tx_fifo_sz_array[] doesn't contains the same number of element than max hardware endpoint, display an error message. Change-Id: Iaa47c39aeab0e434a6baa6eccc1d2e509f3f12f1 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125883 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/usb/gadget/dwc2_udc_otg.c | 13 +++++++++++-- include/usb/dwc2_udc.h | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 7a7c042d3bcb..520eb65ab803 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -402,6 +402,7 @@ static void reconfig_usbd(struct dwc2_udc *dev) uint32_t dflt_gusbcfg; uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; u32 max_hw_ep; + int pdata_hw_ep; debug("Reseting OTG controller\n"); @@ -490,11 +491,19 @@ static void reconfig_usbd(struct dwc2_udc *dev) /* retrieve the number of TX fifo */ max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> GHWCFG4_NUM_IN_EPS_SHIFT; + pdata_hw_ep = dev->pdata->tx_fifo_sz_array[DWC2_SIZE_NB_OFFS]; - for (i = 1; i < max_hw_ep; i++) + if (pdata_hw_ep && max_hw_ep != pdata_hw_ep) + pr_err("Got %d hw endpoint and %d tx-fifo-size in array !!\n", + max_hw_ep, pdata_hw_ep); + + for (i = 1; i <= max_hw_ep; i++) { + if (pdata_hw_ep) + tx_fifo_sz = dev->pdata->tx_fifo_sz_array[(i - 1) + + DWC2_SIZE_OFFS]; writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) | tx_fifo_sz << 16, ®->dieptxf[i-1]); - + } /* Flush the RX FIFO */ writel(RX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & RX_FIFO_FLUSH) diff --git a/include/usb/dwc2_udc.h b/include/usb/dwc2_udc.h index 3bd05fab50be..a0f710388424 100644 --- a/include/usb/dwc2_udc.h +++ b/include/usb/dwc2_udc.h @@ -10,6 +10,10 @@ #define PHY0_SLEEP (1 << 5) +#define DWC2_MAX_HW_ENDPOINTS 16 +#define DWC2_SIZE_NB_OFFS 0 +#define DWC2_SIZE_OFFS 1 + struct dwc2_plat_otg_data { void *priv; int phy_of_node; @@ -23,6 +27,8 @@ struct dwc2_plat_otg_data { unsigned int rx_fifo_sz; unsigned int np_tx_fifo_sz; unsigned int tx_fifo_sz; + /* [0] number of element, [1..17] tx_fifo_sz (max 16 endpoints)*/ + unsigned int tx_fifo_sz_array[DWC2_MAX_HW_ENDPOINTS + 1]; }; int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata); From ba6fcdb9332f0733a4fad37628626668e5df2da2 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Sat, 16 Feb 2019 16:27:11 +0100 Subject: [PATCH 085/244] board: stm32mp1: Add tx_fifo_sz_array support Allows to use an array of tx-fifo-size defined in device tree as following: g-tx-fifo-size = <128 128 64 64 64 64 32 32>; Change-Id: Ie1386895ad28c278082b32330aec6b9132f9d5e6 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125884 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 6347fd10f9ff..f2fa1ffe5264 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -276,6 +276,7 @@ void board_usbotg_init(void) { ofnode usb1600_node; int node; + int count; struct fdtdec_phandle_args args; struct udevice *dev; const void *blob = gd->fdt_blob; @@ -352,8 +353,13 @@ void board_usbotg_init(void) "g-rx-fifo-size", 0); stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node, "g-np-tx-fifo-size", 0); - stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node, - "g-tx-fifo-size", 0); + + count = fdtdec_get_int_array_count(blob, node, "g-tx-fifo-size", + &stm32mp_otg_data.tx_fifo_sz_array[DWC2_SIZE_OFFS], + ARRAY_SIZE(stm32mp_otg_data.tx_fifo_sz_array)); + + if (count != -FDT_ERR_NOTFOUND) + stm32mp_otg_data.tx_fifo_sz_array[DWC2_SIZE_NB_OFFS] = count; /* if node stusb1600 is present, means DK1 or DK2 board */ usb1600_node = ofnode_by_compatible(ofnode_null(), "st,stusb1600"); From 61a2ad5773790fd9a4f00f167cb9a7b0d4a13cac Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 15 Feb 2019 18:15:40 +0100 Subject: [PATCH 086/244] ARM: dts: stm32: Remove g-tx-fifo-size for stm32mp157c-u-boot As dwc2_udc_otg driver has been updated and is able to manage an array of tx-fifo-size, g-tx-fifo-size doesn't need to be overload anymore. Change-Id: Ic4e23beb767275e39490db60345973eddcadc1b1 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/125885 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi index ec0881318341..86039d675aa3 100644 --- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi @@ -54,7 +54,3 @@ u-boot,dm-spl; }; }; - -&usbotg_hs { - g-tx-fifo-size = <576>; -}; From c89d12940860e6eb218b067bdd1515ca42763d99 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Mon, 18 Feb 2019 11:16:05 +0100 Subject: [PATCH 087/244] net: dwc_eth_qos: add delay for SWR operation Need more delay to have eth-ck enable when software reset operation for specific PHY (Phy without crystal) Change-Id: Ia1833a9a5c16b80a25dcadd422b0d260227c7ada Signed-off-by: Christophe Roullier Reviewed-on: https://gerrit.st.com/125912 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index dddbf1f546b6..cd1b4011fb57 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -262,6 +262,7 @@ struct eqos_desc { struct eqos_config { bool reg_access_always_ok; int mdio_wait; + int swr_wait; int config_mac; int config_mac_mdio; int (*interface)(struct udevice *); @@ -1021,7 +1022,8 @@ static int eqos_start(struct udevice *dev) eqos->reg_access_ok = true; ret = wait_for_bit_le32(&eqos->dma_regs->mode, - EQOS_DMA_MODE_SWR, false, 10, false); + EQOS_DMA_MODE_SWR, false, + eqos->config->swr_wait, false); if (ret) { pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; @@ -1823,6 +1825,7 @@ static struct eqos_ops eqos_tegra186_ops = { static const struct eqos_config eqos_tegra186_config = { .reg_access_always_ok = false, .mdio_wait = 10, + .swr_wait = 10, .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, .interface = eqos_get_interface_tegra186, @@ -1849,6 +1852,7 @@ static struct eqos_ops eqos_stm32_ops = { static const struct eqos_config eqos_stm32_config = { .reg_access_always_ok = false, .mdio_wait = 10000, + .swr_wait = 50, .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, .interface = eqos_get_interface_stm32, From c766a755dd06f2c6578e8a9544eeffc720124c3a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 27 Nov 2018 13:49:52 +0100 Subject: [PATCH 088/244] hwspinlock: cosmetic: use priv data in stm32 hardware spinlock Backport of commit 9119f547d3e9 ("hwspinlock: add stm32 hardware spinlock support")' accepted after upstream review. Change-Id: If5b132bb9ab5a2010f6c4231c509241d8122d6dc Signed-off-by: Benjamin Gaignard Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/127325 Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/hwspinlock/stm32_hwspinlock.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c index b8f3b1632f33..a32bde4906dd 100644 --- a/drivers/hwspinlock/stm32_hwspinlock.c +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include @@ -15,22 +13,26 @@ #define STM32_MUTEX_LOCK_BIT BIT(31) #define STM32_MUTEX_NUM_LOCKS 32 +struct stm32mp1_hws_priv { + fdt_addr_t base; +}; + static int stm32mp1_lock(struct udevice *dev, int index) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); u32 status; if (index >= STM32_MUTEX_NUM_LOCKS) return -EINVAL; - status = readl(*base + index * sizeof(u32)); + status = readl(priv->base + index * sizeof(u32)); if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) return -EBUSY; writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, - *base + index * sizeof(u32)); + priv->base + index * sizeof(u32)); - status = readl(*base + index * sizeof(u32)); + status = readl(priv->base + index * sizeof(u32)); if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) return -EINVAL; @@ -39,24 +41,24 @@ static int stm32mp1_lock(struct udevice *dev, int index) static int stm32mp1_unlock(struct udevice *dev, int index) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); if (index >= STM32_MUTEX_NUM_LOCKS) return -EINVAL; - writel(STM32_MUTEX_COREID, *base + index * sizeof(u32)); + writel(STM32_MUTEX_COREID, priv->base + index * sizeof(u32)); return 0; } static int stm32mp1_hwspinlock_probe(struct udevice *dev) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); struct clk clk; int ret; - *base = dev_read_addr(dev); - if (*base == FDT_ADDR_T_NONE) + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; ret = clk_get_by_index(dev, 0, &clk); @@ -86,5 +88,5 @@ U_BOOT_DRIVER(hwspinlock_stm32mp1) = { .of_match = stm32mp1_hwspinlock_ids, .ops = &stm32mp1_hwspinlock_ops, .probe = stm32mp1_hwspinlock_probe, - .priv_auto_alloc_size = sizeof(fdt_addr_t), + .priv_auto_alloc_size = sizeof(struct stm32mp1_hws_priv), }; From a1423d5ddc4e5043827cadb6eb684df42b8fb935 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 6 Mar 2019 18:26:54 +0100 Subject: [PATCH 089/244] pinctrl: stm32: cosmetic: reduce delta with upstream branch Protect configuration registers with a hardware spinlock. If a hwspinlock is defined in the device-tree node used it to be sure that none of the others processors on the SoC could change the configuration at the same time. Change-Id: I0855704157fb77fe7cf01292e8dbcbf2914c0f44 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/127326 --- drivers/pinctrl/pinctrl_stm32.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index eb7799ddfda5..66524017b817 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -211,20 +211,21 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, return 0; } + #endif int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); - int err; + int ret; + + INIT_LIST_HEAD(&priv->gpio_dev); /* hwspinlock property is optional, just log the error */ - err = hwspinlock_get_by_index(dev, 0, &priv->hws); - if (err) + ret = hwspinlock_get_by_index(dev, 0, &priv->hws); + if (ret) debug("%s: hwspinlock_get_by_index may have failed (%d)\n", - __func__, err); - - INIT_LIST_HEAD(&priv->gpio_dev); + __func__, ret); return 0; } @@ -234,7 +235,7 @@ static int stm32_gpio_config(struct gpio_desc *desc, { struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); struct stm32_gpio_regs *regs = priv->regs; - struct stm32_pinctrl_priv *pinctrl_priv; + struct stm32_pinctrl_priv *ctrl_priv; int ret; u32 index; @@ -242,9 +243,8 @@ static int stm32_gpio_config(struct gpio_desc *desc, ctl->pupd > 2 || ctl->speed > 3) return -EINVAL; - pinctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); - - ret = hwspinlock_lock_timeout(&pinctrl_priv->hws, 10); + ctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); + ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10); if (ret == -ETIME) { dev_err(desc->dev, "HWSpinlock timeout\n"); return ret; @@ -264,7 +264,7 @@ static int stm32_gpio_config(struct gpio_desc *desc, index = desc->offset; clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); - hwspinlock_unlock(&pinctrl_priv->hws); + hwspinlock_unlock(&ctrl_priv->hws); return 0; } @@ -327,8 +327,8 @@ static int stm32_pinctrl_config(int offset) int rv, len; /* - * check for "pinmux" property in each subnode of pin controller - * phandle "pinctrl-0" (e.g. pins1 and pins2 for usart1) + * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for + * usart1) of pin controller phandle "pinctrl-0" */ fdt_for_each_subnode(offset, gd->fdt_blob, offset) { struct stm32_gpio_dsc gpio_dsc; From de99afc2b0efe857317c7eadb459ec9f502e1409 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 28 Feb 2019 19:45:25 +0100 Subject: [PATCH 090/244] stm32mp1: add pattern parameter in infinite write test Change-Id: I5d1826f726a93b69905291a18a18b9f8f2cfdbf4 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126782 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/ram/stm32mp1/stm32mp1_tests.c | 31 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 9006bac82293..8f3d17079bcc 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -1243,13 +1243,18 @@ static enum test_result test_read(struct stm32mp1_ddrctl *ctl, if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern=0x%08x\n", + (u32)addr, data); + writel(data, addr); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { if (random) addr = (u32 *)(STM32_DDR_BASE + @@ -1275,20 +1280,24 @@ static enum test_result test_write(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { u32 *addr; - u32 data = 0xA5A5AA55; + u32 data; u32 loop = 0; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern 0x%08x\n", + (u32)addr, data); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { if (random) { addr = (u32 *)(STM32_DDR_BASE + @@ -1417,10 +1426,10 @@ const struct test_desc test[] = { 3 }, /* need to the the 2 last one (infinite) : skipped for test all */ - {test_read, "infinite read", "[addr]", - "basic test : infinite read access", 1}, - {test_write, "infinite write", "[addr]", - "basic test : infinite write access", 1}, + {test_read, "infinite read", "[addr] [pattern]", + "basic test : infinite read access (random: addr=0xFFFFFFFF)", 2}, + {test_write, "infinite write", "[addr] [pattern]", + "basic test : infinite write access (random: addr=0xFFFFFFFF)", 2}, }; const int test_nb = ARRAY_SIZE(test); From 2a1aa43aef7faf2f4738bc711d8fbe944ff0f60b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 28 Feb 2019 19:43:22 +0100 Subject: [PATCH 091/244] stm32mp1: update loop management in infinite test Reduce verbosity of the infinite tests to avoid CubeMX issue. test and display loop by 1024*1024 accesses: read or write. Change-Id: I43717c94bc844db371e6aa96aa45abb6266a4577 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126783 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/ram/stm32mp1/stm32mp1_tests.c | 38 ++++++++++++++++++--------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 8f3d17079bcc..4693c207ca3d 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -1238,6 +1238,7 @@ static enum test_result test_read(struct stm32mp1_ddrctl *ctl, u32 *addr; u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) @@ -1256,14 +1257,19 @@ static enum test_result test_read(struct stm32mp1_ddrctl *ctl, } while (1) { - if (random) - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = readl(addr); - if (test_loop_end(&loop, 0, 1000)) + for (i = 0; i < size; i++) { + if (random) + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = readl(addr); + } + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } @@ -1282,6 +1288,7 @@ static enum test_result test_write(struct stm32mp1_ddrctl *ctl, u32 *addr; u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) @@ -1299,16 +1306,21 @@ static enum test_result test_write(struct stm32mp1_ddrctl *ctl, } while (1) { - if (random) { - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = rand(); + for (i = 0; i < size; i++) { + if (random) { + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = rand(); + } + writel(data, addr); } - writel(data, addr); - if (test_loop_end(&loop, 0, 1000)) + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } From 3a4bf1551c4afe47272c2105c52a84a6e8a23602 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 28 Feb 2019 20:01:56 +0100 Subject: [PATCH 092/244] stm32mp1: reload watchdog during ddr test Avoid watchdog during infinite DDR test. Change-Id: I71fe0e256b52cff27fc61829863685d584b4e750 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126784 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/ram/stm32mp1/stm32mp1_tests.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 4693c207ca3d..2df6962da096 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include "stm32mp1_tests.h" @@ -154,6 +155,7 @@ static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress) return 1; } printf("loop #%d\n", *loop); + WATCHDOG_RESET(); return 0; } From de03197119ae247b72e9feb6c443587300604f2b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 26 Feb 2019 11:41:03 +0100 Subject: [PATCH 093/244] ARM: dts: stm32: Update pwr-regulators node for ED1 and DK1 To align with kernel device tree, the pwr node is reworked. pwr-supply is renamed and put under a pwr-regulators sub-node. Change-Id: I939c632ccedb073583662ac33d013a589d8e4d47 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126479 Reviewed-by: CIBUILD Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157a-dk1.dts | 4 +++- arch/arm/dts/stm32mp157c-ed1.dts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 1194e972510f..219e62b32430 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -506,7 +506,9 @@ }; &pwr { - pwr-supply = <&vdd>; + pwr-regulators { + vdd-supply = <&vdd>; + }; }; &rng1 { diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 780c992a3ad7..e7d3f3752c35 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -342,7 +342,9 @@ }; &pwr { - pwr-supply = <&vdd>; + pwr-regulators { + vdd-supply = <&vdd>; + }; }; &rng1 { From 0ea9de32aa48818127a174f02cad644dc627e6e1 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 27 Feb 2019 12:01:47 +0100 Subject: [PATCH 094/244] board: stm32mp1: Update the way vdd-supply is retrieved from DT Due to kernel DT alignment, pwr-supply is renamed to vdd-supply and is a subnode of pwr-regulators. Change-Id: I3020651a309516aa527cdd7114ec8e5da93f7f80 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126480 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index f2fa1ffe5264..c3e3b3952725 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -2,7 +2,6 @@ /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ - #include #include #include @@ -494,9 +493,12 @@ static void sysconf_init(void) if (!ret) otp = otp & BIT(13); - /* get VDD = pwr-supply */ - ret = device_get_supply_regulator(pwr_dev, "pwr-supply", - &pwr_reg); + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(stm32mp_pwr_pmic), + &dev); + + /* get VDD = vdd-supply */ + ret = device_get_supply_regulator(dev, "vdd-supply", &pwr_reg); /* check if VDD is Low Voltage */ if (!ret) { From a94c0486c1dfb7bbe9819bf5ff57a6457c4154d1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 28 Feb 2019 18:04:16 +0100 Subject: [PATCH 095/244] stm32mp1: psci: add synchronization with ROM code Use SGI0 interruption and TAMP_BACKUP_MAGIC_NUMBER to synchronize the core1 boot sequence requested by core0 in psci_cpu_on(): - a initial interruption is needed in ROM code after RCC_MP_GRSTCSETR_MPUP1RST (psci_cpu_off) - the ROM code set to 0 the 2 registers + TAMP_BACKUP_BRANCH_ADDRESS + TAMP_BACKUP_MAGIC_NUMBER when magic is not egual to BOOT_API_A7_CORE0_MAGIC_NUMBER This patch solve issue for cpu1 restart in kernel. echo 0 > /sys/devices/system/cpu/cpu1/online echo 1 > /sys/devices/system/cpu/cpu1/online Change-Id: I2928dc437dbc58e763115cdb66fe93e07a012a28 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/126762 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/psci.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index c2dff38c368c..5809298dbb45 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -47,14 +47,14 @@ static u32 __secure stm32mp_get_gicd_base_address(void) return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET; } -static void __secure stm32mp_smp_kick_all_cpus(void) +static void __secure stm32mp_raise_sgi0(int cpu) { u32 gic_dist_addr; gic_dist_addr = stm32mp_get_gicd_base_address(); - /* kick all CPUs (except this one) by writing to GICD_SGIR */ - writel(1U << 24, gic_dist_addr + GICD_SGIR); + /* ask cpu with SGI0 */ + writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR); } void __secure psci_arch_cpu_entry(void) @@ -62,6 +62,9 @@ void __secure psci_arch_cpu_entry(void) u32 cpu = psci_get_cpu_id(); psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON); + + /* reset magic in TAMP register */ + writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); } int __secure psci_features(u32 function_id, u32 psci_fid) @@ -127,6 +130,14 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON) return ARM_PSCI_RET_ALREADY_ON; + /* reset magic in TAMP register */ + if (readl(TAMP_BACKUP_MAGIC_NUMBER)) + writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); + + /* ROM code need a SGI0 after core reset is ready when magic = 0 */ + while (readl(TAMP_BACKUP_MAGIC_NUMBER)) + stm32mp_raise_sgi0(cpu); + /* store target PC and context id*/ psci_save(cpu, pc, context_id); @@ -142,7 +153,8 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, writel(BOOT_API_A7_CORE0_MAGIC_NUMBER, TAMP_BACKUP_MAGIC_NUMBER); - stm32mp_smp_kick_all_cpus(); + /* Generate an IT to start the core */ + stm32mp_raise_sgi0(cpu); return ARM_PSCI_RET_SUCCESS; } From 2a2abc60b211f49b380c3b389a2039d26dee2bd1 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 25 Feb 2019 13:49:52 +0100 Subject: [PATCH 096/244] gpio: stm32: Rename stm32f7_gpio to stm32_gpio As this driver is used on stm32f4/f7/h7 and stm32mp1 SoCs, rename it with a more generic name. Change-Id: I9b97cc4945c76d2a7bb269e7d2bf63cf6a8e6651 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126441 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/gpio/Kconfig | 4 ++-- drivers/gpio/Makefile | 2 +- drivers/gpio/{stm32f7_gpio.c => stm32_gpio.c} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename drivers/gpio/{stm32f7_gpio.c => stm32_gpio.c} (100%) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cd8b3440054..9e9cfd6557a9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -238,13 +238,13 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. -config STM32F7_GPIO +config STM32_GPIO bool "ST STM32 GPIO driver" depends on DM_GPIO && (STM32 || ARCH_STM32MP) default y help Device model driver support for STM32 GPIO controller. It should be - usable on many stm32 families like stm32f4 & stm32H7. + usable on many stm32 families like stm32f4/f7/h7 and stm32mp1. Tested on STM32F7. config MVEBU_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f18612068442..c7cab2855eda 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o obj-$(CONFIG_TCA642X) += tca642x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o -obj-$(CONFIG_STM32F7_GPIO) += stm32f7_gpio.o +obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32_gpio.c similarity index 100% rename from drivers/gpio/stm32f7_gpio.c rename to drivers/gpio/stm32_gpio.c From 04b05a110a0f7f90d61471bcf49c184783789cc6 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 25 Feb 2019 16:54:45 +0100 Subject: [PATCH 097/244] pinctrl: stm32: update .bind callback Update .bind callback in order to bind all pinctrl subnodes with "gpio-controller" property to gpio_stm32 driver. Change-Id: Iea41ff242d5e78e9c4bb904c9b5efc2d9bd4c47e Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126442 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/pinctrl/pinctrl_stm32.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 66524017b817..042425e48569 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -4,6 +4,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -363,6 +364,35 @@ static int stm32_pinctrl_config(int offset) return 0; } +static int stm32_pinctrl_bind(struct udevice *dev) +{ + ofnode node; + const char *name; + int ret; + + dev_for_each_subnode(node, dev) { + debug("%s: bind %s\n", __func__, ofnode_get_name(node)); + + ofnode_get_property(node, "gpio-controller", &ret); + if (ret < 0) + continue; + /* Get the name of each gpio node */ + name = ofnode_get_name(node); + if (!name) + return -EINVAL; + + /* Bind each gpio node */ + ret = device_bind_driver_to_node(dev, "gpio_stm32", + name, node, NULL); + if (ret) + return ret; + + debug("%s: bind %s\n", __func__, name); + } + + return 0; +} + #if CONFIG_IS_ENABLED(PINCTRL_FULL) static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config) { @@ -431,7 +461,7 @@ U_BOOT_DRIVER(pinctrl_stm32) = { .id = UCLASS_PINCTRL, .of_match = stm32_pinctrl_ids, .ops = &stm32_pinctrl_ops, - .bind = dm_scan_fdt_dev, + .bind = stm32_pinctrl_bind, .probe = stm32_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), }; From 0f1eb28985bf463baaedfe15db75806313bb1882 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 25 Feb 2019 16:59:07 +0100 Subject: [PATCH 098/244] ARM: dts: stm32: Remove useless "st,stm32-gpio" compatible string Since pinctrl_stm32 driver update, each gpio bank is now binded by pinctrl driver. The compatible string "st,stm32-gpio" becomes useless, remove it. Change-Id: I537b9ce9e3a9921324838a06adce1b384e6249b9 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126443 Reviewed-by: CIBUILD Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY --- arch/arm/dts/stm32429i-eval-u-boot.dtsi | 11 ----------- arch/arm/dts/stm32f429-disco-u-boot.dtsi | 11 ----------- arch/arm/dts/stm32f469-disco-u-boot.dtsi | 11 ----------- arch/arm/dts/stm32f746.dtsi | 11 ----------- arch/arm/dts/stm32h743-pinctrl.dtsi | 11 ----------- arch/arm/dts/stm32mp157-u-boot.dtsi | 12 ------------ 6 files changed, 67 deletions(-) diff --git a/arch/arm/dts/stm32429i-eval-u-boot.dtsi b/arch/arm/dts/stm32429i-eval-u-boot.dtsi index 6da0a636c1b5..fe437bbfe2fe 100644 --- a/arch/arm/dts/stm32429i-eval-u-boot.dtsi +++ b/arch/arm/dts/stm32429i-eval-u-boot.dtsi @@ -92,57 +92,46 @@ }; &gpioa { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiob { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioc { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiod { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioe { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiof { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiog { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioh { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioi { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioj { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiok { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32f429-disco-u-boot.dtsi b/arch/arm/dts/stm32f429-disco-u-boot.dtsi index 10e09508aa21..399d4c9ba62b 100644 --- a/arch/arm/dts/stm32f429-disco-u-boot.dtsi +++ b/arch/arm/dts/stm32f429-disco-u-boot.dtsi @@ -87,57 +87,46 @@ }; &gpioa { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiob { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioc { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiod { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioe { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiof { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiog { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioh { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioi { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioj { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiok { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32f469-disco-u-boot.dtsi b/arch/arm/dts/stm32f469-disco-u-boot.dtsi index 774f1b5e656e..d370ca700ed8 100644 --- a/arch/arm/dts/stm32f469-disco-u-boot.dtsi +++ b/arch/arm/dts/stm32f469-disco-u-boot.dtsi @@ -92,57 +92,46 @@ }; &gpioa { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiob { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioc { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiod { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioe { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiof { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiog { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioh { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioi { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioj { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiok { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index afa7832f8936..4bae1a1c35c3 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -130,7 +130,6 @@ gpioa: gpio@40020000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x0 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOA)>; st,bank-name = "GPIOA"; @@ -140,7 +139,6 @@ gpiob: gpio@40020400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x400 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOB)>; st,bank-name = "GPIOB"; @@ -151,7 +149,6 @@ gpioc: gpio@40020800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x800 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOC)>; st,bank-name = "GPIOC"; @@ -161,7 +158,6 @@ gpiod: gpio@40020c00 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0xc00 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOD)>; st,bank-name = "GPIOD"; @@ -171,7 +167,6 @@ gpioe: gpio@40021000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1000 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOE)>; st,bank-name = "GPIOE"; @@ -181,7 +176,6 @@ gpiof: gpio@40021400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1400 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOF)>; st,bank-name = "GPIOF"; @@ -191,7 +185,6 @@ gpiog: gpio@40021800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1800 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOG)>; st,bank-name = "GPIOG"; @@ -201,7 +194,6 @@ gpioh: gpio@40021c00 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1c00 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOH)>; st,bank-name = "GPIOH"; @@ -211,7 +203,6 @@ gpioi: gpio@40022000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2000 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOI)>; st,bank-name = "GPIOI"; @@ -221,7 +212,6 @@ gpioj: gpio@40022400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2400 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOJ)>; st,bank-name = "GPIOJ"; @@ -231,7 +221,6 @@ gpiok: gpio@40022800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2800 0x400>; clocks = <&rcc 0 STM32F7_AHB1_CLOCK(GPIOK)>; st,bank-name = "GPIOK"; diff --git a/arch/arm/dts/stm32h743-pinctrl.dtsi b/arch/arm/dts/stm32h743-pinctrl.dtsi index e4f4aa579bd4..65d6ca24a712 100644 --- a/arch/arm/dts/stm32h743-pinctrl.dtsi +++ b/arch/arm/dts/stm32h743-pinctrl.dtsi @@ -54,7 +54,6 @@ gpioa: gpio@58020000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x0 0x400>; clocks = <&rcc GPIOA_CK>; st,bank-name = "GPIOA"; @@ -63,7 +62,6 @@ gpiob: gpio@58020400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x400 0x400>; clocks = <&rcc GPIOB_CK>; st,bank-name = "GPIOB"; @@ -72,7 +70,6 @@ gpioc: gpio@58020800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x800 0x400>; clocks = <&rcc GPIOC_CK>; st,bank-name = "GPIOC"; @@ -81,7 +78,6 @@ gpiod: gpio@58020c00 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0xc00 0x400>; clocks = <&rcc GPIOD_CK>; st,bank-name = "GPIOD"; @@ -90,7 +86,6 @@ gpioe: gpio@58021000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1000 0x400>; clocks = <&rcc GPIOE_CK>; st,bank-name = "GPIOE"; @@ -99,7 +94,6 @@ gpiof: gpio@58021400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1400 0x400>; clocks = <&rcc GPIOF_CK>; st,bank-name = "GPIOF"; @@ -108,7 +102,6 @@ gpiog: gpio@58021800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1800 0x400>; clocks = <&rcc GPIOG_CK>; st,bank-name = "GPIOG"; @@ -117,7 +110,6 @@ gpioh: gpio@58021c00 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x1c00 0x400>; clocks = <&rcc GPIOH_CK>; st,bank-name = "GPIOH"; @@ -126,7 +118,6 @@ gpioi: gpio@58022000 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2000 0x400>; clocks = <&rcc GPIOI_CK>; st,bank-name = "GPIOI"; @@ -135,7 +126,6 @@ gpioj: gpio@58022400 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2400 0x400>; clocks = <&rcc GPIOJ_CK>; st,bank-name = "GPIOJ"; @@ -144,7 +134,6 @@ gpiok: gpio@58022800 { gpio-controller; #gpio-cells = <2>; - compatible = "st,stm32-gpio"; reg = <0x2800 0x400>; clocks = <&rcc GPIOK_CK>; st,bank-name = "GPIOK"; diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index e425932b999a..ca519e5f975f 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -77,62 +77,50 @@ }; &gpioa { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiob { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioc { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiod { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioe { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiof { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiog { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioh { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioi { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioj { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpiok { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; &gpioz { - compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; From 0794bcc845875dcdede1998d44f91368c17b8c8d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 25 Feb 2019 17:02:01 +0100 Subject: [PATCH 099/244] gpio: stm32: Remove .ofmatch callback As compatible string "st,stm32-gpio" is no more used, .ofmatch callback becomes useless, remove it. Change-Id: Ie72f86e0d9538ff380f5e3bb6d535629e97573e9 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/126444 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/gpio/stm32_gpio.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 7fff64ec15e0..104306833d80 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -200,15 +200,9 @@ static int gpio_stm32_probe(struct udevice *dev) return 0; } -static const struct udevice_id stm32_gpio_ids[] = { - { .compatible = "st,stm32-gpio" }, - { } -}; - U_BOOT_DRIVER(gpio_stm32) = { .name = "gpio_stm32", .id = UCLASS_GPIO, - .of_match = stm32_gpio_ids, .probe = gpio_stm32_probe, .ops = &gpio_stm32_ops, .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS, From bfa3dd22690491e71cc36276b2bc15312a3a5dd7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 8 Mar 2019 11:25:48 +0100 Subject: [PATCH 100/244] stm32mp1: deactivate WATCHDOG in defconfig Deactivate WATCHDOG by default in u-boot to avoid issue to boot kernel and rootfs without the needed daemon to reload it. Change-Id: I8af7eb32ce3cd09e1cec6fb2fc4107a6ea895bbb Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/127483 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- configs/stm32mp15_basic_defconfig | 2 -- configs/stm32mp15_optee_defconfig | 2 -- configs/stm32mp15_trusted_defconfig | 2 -- 3 files changed, 6 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 0c6d6584b4c2..e1ae9af20592 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -120,7 +120,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_WDT=y -CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index be55a601f635..bebc823130ca 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -106,7 +106,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_WDT=y -CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 95b4f982ac7b..f7af5c8fcf61 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -105,7 +105,5 @@ CONFIG_VIDEO_STM32=y CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 -CONFIG_WDT=y -CONFIG_WDT_STM32MP=y CONFIG_FDT_FIXUP_PARTITIONS=y # CONFIG_EFI_LOADER is not set From a897ef513f23dc6104f968260da1de4e0147059f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 11 Mar 2019 13:29:12 +0100 Subject: [PATCH 101/244] stm32mp1: dts: override the compatible for SDMMC2 If the SDMMC2 compatible changes in the U-Boot device tree located at ${fdtcontroladdr} address, this DT can't be reused for EFI boot for kernel, with the comand $> bootefi ${fdtcontroladdr} The patch only adds the needed U-Boot compatible and keeps the original compatibles of kernel device tree, as fallback. Change-Id: Idfabe57e28e6767a626ee6b06c56ab54a19f296f Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/127666 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/dts/stm32mp157-u-boot.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index ca519e5f975f..7af6cdfae656 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -150,13 +150,13 @@ }; &sdmmc1 { - compatible = "st,stm32-sdmmc2"; + compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell"; }; &sdmmc2 { - compatible = "st,stm32-sdmmc2"; + compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell"; }; &sdmmc3 { - compatible = "st,stm32-sdmmc2"; + compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell"; }; From a4ec9ce9df34cc678bb66fddf3c914fcf9867417 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Mar 2019 12:59:05 +0100 Subject: [PATCH 102/244] stm32mp1: activate UEFI defconfig Activates the UEFI configuration mandatory for the ARM Embedded Base Boot Requirements (EBBR) specification. see https://github.com/ARM-software/ebbr Adds the command bootefi. Change-Id: Ic7659fb4efb56a417062b8946498fb1a71dcd5f7 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/127734 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- configs/stm32mp15_basic_defconfig | 1 - configs/stm32mp15_optee_defconfig | 1 - configs/stm32mp15_trusted_defconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index e1ae9af20592..026367685c71 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -121,4 +121,3 @@ CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 CONFIG_FDT_FIXUP_PARTITIONS=y -# CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index bebc823130ca..0db864d84898 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -107,4 +107,3 @@ CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 CONFIG_FDT_FIXUP_PARTITIONS=y -# CONFIG_EFI_LOADER is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index f7af5c8fcf61..d19d244918a9 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -106,4 +106,3 @@ CONFIG_VIDEO_STM32_DSI=y CONFIG_VIDEO_STM32_MAX_XRES=1280 CONFIG_VIDEO_STM32_MAX_YRES=800 CONFIG_FDT_FIXUP_PARTITIONS=y -# CONFIG_EFI_LOADER is not set From 459a0c45b838680284f810bc91ef0b5a83a1f055 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 28 Feb 2019 15:19:32 +0100 Subject: [PATCH 103/244] clk: stm32mp1: Add SPI1 clock entry Change-Id: I8f294872c92efc5a3f0b18961c667bc29d949a2d Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/127800 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/clk/clk_stm32mp1.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 96595504150c..d55a3f135b30 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -94,6 +94,7 @@ DECLARE_GLOBAL_DATA_PTR; #define RCC_PLL4CSGR 0x8A4 #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 +#define RCC_SPI2S1CKSELR 0x8D8 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 #define RCC_UART35CKSELR 0x8EC @@ -302,6 +303,7 @@ enum stm32mp1_parent_sel { _STGEN_SEL, _DSI_SEL, _ADC12_SEL, + _SPI1_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -539,6 +541,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), @@ -609,6 +612,8 @@ static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48}; static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER}; static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; +static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, + _PLL3_R}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), @@ -633,6 +638,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), + STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT @@ -747,6 +753,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_STGEN_SEL] = "STGEN", [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", + [_SPI1_SEL] = "SPI1", }; static const struct stm32mp1_clk_data stm32mp1_data = { From bc858f63146d303102426b052be8e16ff2d18e4f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 12 Mar 2019 10:49:56 +0100 Subject: [PATCH 104/244] spi: stm32: Add Serial Peripheral Interface driver for STM32MP Add SPI driver support for STM32MP SoCs family. Change-Id: I70967cfddfc81ef0164ef6837772837c360a640e Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/127801 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/stm32_spi.c | 615 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 624 insertions(+) create mode 100644 drivers/spi/stm32_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index da967542647c..62d624563849 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -197,6 +197,14 @@ config STM32_QSPI used to access the SPI NOR flash chips on platforms embedding this ST IP core. +config STM32_SPI + bool "STM32 SPI driver" + depends on ARCH_STM32MP + help + Enable the STM32 Serial Peripheral Interface (SPI) driver for STM32MP + SoCs. This uses driver model and requires a device tree binding to + operate. + config SUN4I_SPI bool "Allwinner A10 SoCs SPI controller" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7242ea7e4045..2f984d9b1b82 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o obj-$(CONFIG_SH_SPI) += sh_spi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o +obj-$(CONFIG_STM32_SPI) += stm32_spi.o obj-$(CONFIG_SUN4I_SPI) += sun4i_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c new file mode 100644 index 000000000000..34b217584dd1 --- /dev/null +++ b/drivers/spi/stm32_spi.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Serial peripheral interface (SPI) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* STM32 SPI registers */ +#define STM32_SPI_CR1 0x00 +#define STM32_SPI_CR2 0x04 +#define STM32_SPI_CFG1 0x08 +#define STM32_SPI_CFG2 0x0C +#define STM32_SPI_SR 0x14 +#define STM32_SPI_IFCR 0x18 +#define STM32_SPI_TXDR 0x20 +#define STM32_SPI_RXDR 0x30 +#define STM32_SPI_I2SCFGR 0x50 + +/* STM32_SPI_CR1 bit fields */ +#define SPI_CR1_SPE BIT(0) +#define SPI_CR1_MASRX BIT(8) +#define SPI_CR1_CSTART BIT(9) +#define SPI_CR1_CSUSP BIT(10) +#define SPI_CR1_HDDIR BIT(11) +#define SPI_CR1_SSI BIT(12) + +/* STM32_SPI_CR2 bit fields */ +#define SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32_SPI_CFG1 bit fields */ +#define SPI_CFG1_DSIZE GENMASK(4, 0) +#define SPI_CFG1_DSIZE_MIN 3 +#define SPI_CFG1_FTHLV_SHIFT 5 +#define SPI_CFG1_FTHLV GENMASK(8, 5) +#define SPI_CFG1_MBR_SHIFT 28 +#define SPI_CFG1_MBR GENMASK(30, 28) +#define SPI_CFG1_MBR_MIN 0 +#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) + +/* STM32_SPI_CFG2 bit fields */ +#define SPI_CFG2_COMM_SHIFT 17 +#define SPI_CFG2_COMM GENMASK(18, 17) +#define SPI_CFG2_MASTER BIT(22) +#define SPI_CFG2_LSBFRST BIT(23) +#define SPI_CFG2_CPHA BIT(24) +#define SPI_CFG2_CPOL BIT(25) +#define SPI_CFG2_SSM BIT(26) +#define SPI_CFG2_AFCNTR BIT(31) + +/* STM32_SPI_SR bit fields */ +#define SPI_SR_RXP BIT(0) +#define SPI_SR_TXP BIT(1) +#define SPI_SR_EOT BIT(3) +#define SPI_SR_TXTF BIT(4) +#define SPI_SR_OVR BIT(6) +#define SPI_SR_SUSP BIT(11) +#define SPI_SR_RXPLVL_SHIFT 13 +#define SPI_SR_RXPLVL GENMASK(14, 13) +#define SPI_SR_RXWNE BIT(15) + +/* STM32_SPI_IFCR bit fields */ +#define SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32_SPI_I2SCFGR bit fields */ +#define SPI_I2SCFGR_I2SMOD BIT(0) + +#define MAX_CS_COUNT 4 + +/* SPI Master Baud Rate min/max divisor */ +#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) +#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) + +#define STM32_SPI_TIMEOUT_US 100000 + +/* SPI Communication mode */ +#define SPI_FULL_DUPLEX 0 +#define SPI_SIMPLEX_TX 1 +#define SPI_SIMPLEX_RX 2 +#define SPI_HALF_DUPLEX 3 + +struct stm32_spi_priv { + void __iomem *base; + struct clk clk; + struct reset_ctl rst_ctl; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; + ulong bus_clk_rate; + unsigned int fifo_size; + unsigned int cur_bpw; + unsigned int cur_hz; + unsigned int cur_xferlen; /* current transfer length in bytes */ + int tx_len; /* number of data to be written in bytes */ + int rx_len; /* number of data to be read in bytes */ + const void *tx_buf; /* data to be written, or NULL */ + void *rx_buf; /* data to be read, or NULL */ + u32 cur_mode; + bool cs_high; +}; + +static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +{ + while ((priv->tx_len > 0) && + (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + u32 offs = priv->cur_xferlen - priv->tx_len; + + if (priv->tx_len >= sizeof(u32) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { + const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); + + writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u32); + } else if (priv->tx_len >= sizeof(u16) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { + const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); + + writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); + + writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u8); + } + } + + debug("%s: %d bytes left\n", __func__, priv->tx_len); +} + +static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +{ + u32 sr = readl(priv->base + STM32_SPI_SR); + u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + + while ((priv->rx_len > 0) && + ((sr & SPI_SR_RXP) || + ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = priv->cur_xferlen - priv->rx_len; + + if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) && + (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { + u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); + + *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u32); + } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && + (priv->rx_len >= sizeof(u16) || + (!(sr & SPI_SR_RXWNE) && + (rxplvl >= 2 || priv->cur_bpw > 8)))) { + u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); + + *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); + + *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u8); + } + + sr = readl(priv->base + STM32_SPI_SR); + rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + } + + debug("%s: %d bytes left\n", __func__, priv->rx_len); +} + +static int stm32_spi_enable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_disable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_claim_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + return stm32_spi_enable(priv); +} + +static int stm32_spi_release_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + return stm32_spi_disable(priv); +} + +static void stm32_spi_stopxfer(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 cr1, sr; + int ret; + + debug("%s\n", __func__); + + cr1 = readl(priv->base + STM32_SPI_CR1); + + if (!(cr1 & SPI_CR1_SPE)) + return; + + /* Wait on EOT or suspend the flow */ + ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + !(sr & SPI_SR_EOT), 100000); + if (ret < 0) { + if (cr1 & SPI_CR1_CSTART) { + writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); + if (readl_poll_timeout(priv->base + STM32_SPI_SR, + sr, !(sr & SPI_SR_SUSP), + 100000) < 0) + dev_err(dev, "Suspend request timeout\n"); + } + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); +} + +static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + + debug("%s: cs=%d enable=%d\n", __func__, cs, enable); + + if (cs >= MAX_CS_COUNT) + return -ENODEV; + + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return -EINVAL; + + if (priv->cs_high) + enable = !enable; + + return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0); +} + +static int stm32_spi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 cfg2_clrb = 0, cfg2_setb = 0; + + debug("%s: mode=%d\n", __func__, mode); + + if (mode & SPI_CPOL) + cfg2_setb |= SPI_CFG2_CPOL; + else + cfg2_clrb |= SPI_CFG2_CPOL; + + if (mode & SPI_CPHA) + cfg2_setb |= SPI_CFG2_CPHA; + else + cfg2_clrb |= SPI_CFG2_CPHA; + + if (mode & SPI_LSB_FIRST) + cfg2_setb |= SPI_CFG2_LSBFRST; + else + cfg2_clrb |= SPI_CFG2_LSBFRST; + + if (cfg2_clrb || cfg2_setb) + clrsetbits_le32(priv->base + STM32_SPI_CFG2, + cfg2_clrb, cfg2_setb); + + if (mode & SPI_CS_HIGH) + priv->cs_high = true; + else + priv->cs_high = false; + return 0; +} + +static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 fthlv, half_fifo; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (priv->fifo_size / 2); + + /* data_packet should not exceed transfer length */ + fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo; + + /* align packet size with data registers access */ + fthlv -= (fthlv % 4); + + if (!fthlv) + fthlv = 1; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); + + return 0; +} + +static int stm32_spi_set_speed(struct udevice *bus, uint hz) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 div, mbrdiv; + + debug("%s: hz=%d\n", __func__, hz); + + if (priv->cur_hz == hz) + return 0; + + div = DIV_ROUND_UP(priv->bus_clk_rate, hz); + + if (div < STM32_MBR_DIV_MIN || + div > STM32_MBR_DIV_MAX) + return -EINVAL; + + /* Determine the first power of 2 greater than or equal to div */ + if (div & (div - 1)) + mbrdiv = fls(div); + else + mbrdiv = fls(div) - 1; + + if ((mbrdiv - 1) < 0) + return -EINVAL; + + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); + + priv->cur_hz = hz; + + return 0; +} + +static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(slave); + struct dm_spi_slave_platdata *slave_plat; + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 sr; + u32 ifcr = 0; + u32 xferlen; + u32 mode; + int xfer_status = 0; + + xferlen = bitlen / 8; + + if (xferlen <= SPI_CR2_TSIZE) + writel(xferlen, priv->base + STM32_SPI_CR2); + else + return -EMSGSIZE; + + priv->tx_buf = dout; + priv->rx_buf = din; + priv->tx_len = priv->tx_buf ? bitlen / 8 : 0; + priv->rx_len = priv->rx_buf ? bitlen / 8 : 0; + + mode = SPI_FULL_DUPLEX; + if (!priv->tx_buf) + mode = SPI_SIMPLEX_RX; + else if (!priv->rx_buf) + mode = SPI_SIMPLEX_TX; + + if (priv->cur_xferlen != xferlen || priv->cur_mode != mode) { + priv->cur_mode = mode; + priv->cur_xferlen = xferlen; + + /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ + stm32_spi_disable(priv); + + clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + mode << SPI_CFG2_COMM_SHIFT); + + stm32_spi_set_fthlv(bus, xferlen); + + /* Enable the SPI hardware */ + stm32_spi_enable(priv); + } + + debug("%s: priv->tx_len=%d priv->rx_len=%d\n", __func__, + priv->tx_len, priv->rx_len); + + slave_plat = dev_get_parent_platdata(slave); + if (flags & SPI_XFER_BEGIN) + stm32_spi_set_cs(bus, slave_plat->cs, false); + + /* Be sure to have data in fifo before starting data transfer */ + if (priv->tx_buf) + stm32_spi_write_txfifo(priv); + + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + + while (1) { + sr = readl(priv->base + STM32_SPI_SR); + + if (sr & SPI_SR_OVR) { + dev_err(bus, "Overrun: RX data lost\n"); + xfer_status = -EIO; + break; + } + + if (sr & SPI_SR_SUSP) { + dev_warn(bus, "System too slow is limiting data throughput\n"); + + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + ifcr |= SPI_SR_SUSP; + } + + if (sr & SPI_SR_TXTF) + ifcr |= SPI_SR_TXTF; + + if (sr & SPI_SR_TXP) + if (priv->tx_buf && priv->tx_len > 0) + stm32_spi_write_txfifo(priv); + + if (sr & SPI_SR_RXP) + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + if (sr & SPI_SR_EOT) { + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + break; + } + + writel(ifcr, priv->base + STM32_SPI_IFCR); + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + stm32_spi_stopxfer(bus); + + if (flags & SPI_XFER_END) + stm32_spi_set_cs(bus, slave_plat->cs, true); + + return xfer_status; +} + +static int stm32_spi_get_fifo_size(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 count = 0; + + stm32_spi_enable(priv); + + while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, priv->base + STM32_SPI_TXDR); + + stm32_spi_disable(priv); + + debug("%s %d x 8-bit fifo size\n", __func__, count); + + return count; +} + +static int stm32_spi_probe(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + unsigned long clk_rate; + int ret; + int i; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + /* enable clock */ + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret < 0) + return ret; + + clk_rate = clk_get_rate(&priv->clk); + if (!clk_rate) { + ret = -EINVAL; + goto clk_err; + } + + priv->bus_clk_rate = clk_rate; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &priv->rst_ctl); + if (ret < 0) + goto clk_err; + + reset_assert(&priv->rst_ctl); + udelay(2); + reset_deassert(&priv->rst_ctl); + + ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios, + ARRAY_SIZE(priv->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s cs gpios: %d", dev->name, ret); + goto reset_err; + } + + priv->fifo_size = stm32_spi_get_fifo_size(dev); + + priv->cur_mode = SPI_FULL_DUPLEX; + priv->cur_xferlen = 0; + priv->cur_bpw = SPI_DEFAULT_WORDLEN; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { + if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + continue; + + dm_gpio_set_dir_flags(&priv->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + + /* Ensure I2SMOD bit is kept cleared */ + clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - automatic communication suspend when RX-Fifo is full + */ + setbits_le32(priv->base + STM32_SPI_CR1, + SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); + + /* + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + * - keep control of all associated GPIOs + */ + setbits_le32(priv->base + STM32_SPI_CFG2, + SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); + + return 0; + +reset_err: + reset_free(&priv->rst_ctl); + +clk_err: + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return ret; +}; + +static int stm32_spi_remove(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + int ret; + + stm32_spi_stopxfer(dev); + stm32_spi_disable(priv); + + ret = reset_assert(&priv->rst_ctl); + if (ret < 0) + return ret; + + reset_free(&priv->rst_ctl); + + ret = clk_disable(&priv->clk); + if (ret < 0) + return ret; + + clk_free(&priv->clk); + + return ret; +}; + +static const struct dm_spi_ops stm32_spi_ops = { + .claim_bus = stm32_spi_claim_bus, + .release_bus = stm32_spi_release_bus, + .set_mode = stm32_spi_set_mode, + .set_speed = stm32_spi_set_speed, + .xfer = stm32_spi_xfer, +}; + +static const struct udevice_id stm32_spi_ids[] = { + { .compatible = "st,stm32h7-spi", }, + { } +}; + +U_BOOT_DRIVER(stm32_spi) = { + .name = "stm32_spi", + .id = UCLASS_SPI, + .of_match = stm32_spi_ids, + .ops = &stm32_spi_ops, + .priv_auto_alloc_size = sizeof(struct stm32_spi_priv), + .probe = stm32_spi_probe, + .remove = stm32_spi_remove, +}; From 30db435de3f751c06a1c09605bc5ebeb0bde3c1c Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 26 Feb 2019 17:34:07 +0100 Subject: [PATCH 105/244] configs: stm32mp15: Enable STM32_SPI and CMD_SPI flag This enables the SPI support for STM32MP15. Change-Id: I0443c434613dd69e05af3884569a2686ef8de5a0 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/127798 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_optee_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 3 files changed, 6 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 026367685c71..69372e2cf8e7 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -32,6 +32,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_BMP=y @@ -102,6 +103,7 @@ CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 0db864d84898..f284c3d7956b 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -23,6 +23,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_BMP=y @@ -88,6 +89,7 @@ CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index d19d244918a9..b18debe9a473 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_BMP=y @@ -87,6 +88,7 @@ CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y From 68be2f8e4f6ec58c6d6038f0c1dc13629aee6e5d Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 15 Mar 2019 15:14:43 +0100 Subject: [PATCH 106/244] spi: spi-mem: Allow use of spi_mem_exec_op for all SPI modes SPI controllers support all types of SPI modes including dual/quad bus widths. Therefore remove constraint wrt SPI mode from spi-mem layer. Change-Id: I781cc2fa299a6ca4d62ddd5b270f86034fd2aa03 Signed-off-by: Vignesh R Tested-by: Simon Goldschmidt Tested-by: Stefan Roese Tested-by: Horatiu Vultur Reviewed-by: Jagan Teki Tested-by: Jagan Teki #zynq-microzed Reviewed-on: https://gerrit.st.com/128083 Reviewed-by: CITOOLS Reviewed-by: Christophe KERELLO Tested-by: Christophe KERELLO Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/spi-mem.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index af9aef009a73..1da20b8de5c4 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -323,15 +323,6 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) return -EIO; #else - /* U-Boot does not support parallel SPI data lanes */ - if ((op->cmd.buswidth != 1) || - (op->addr.nbytes && op->addr.buswidth != 1) || - (op->dummy.nbytes && op->dummy.buswidth != 1) || - (op->data.nbytes && op->data.buswidth != 1)) { - printf("Dual/Quad raw SPI transfers not supported\n"); - return -ENOTSUPP; - } - if (op->data.nbytes) { if (op->data.dir == SPI_MEM_DATA_IN) rx_buf = op->data.buf.in; From 36cec76b091c90797e36baea487184164eefae42 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 15 Mar 2019 15:14:55 +0100 Subject: [PATCH 107/244] spi: spi-mem: Extend spi_mem_adjust_op_size() to honor max xfer size Extend spi_mem_adjust_op_size() to take spi->max_write_size and spi->max_read_size into account. Change-Id: Iddabffb420608ae39c5c79cc53baa55c3810e25c Signed-off-by: Vignesh R Tested-by: Simon Goldschmidt Tested-by: Stefan Roese Tested-by: Horatiu Vultur Reviewed-by: Jagan Teki Tested-by: Jagan Teki #zynq-microzed Reviewed-on: https://gerrit.st.com/128084 Reviewed-by: CITOOLS Reviewed-by: Christophe KERELLO Tested-by: Christophe KERELLO Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/spi-mem.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 1da20b8de5c4..334af682dc65 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -412,6 +412,25 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) if (ops->mem_ops && ops->mem_ops->adjust_op_size) return ops->mem_ops->adjust_op_size(slave, op); + if (!ops->mem_ops || !ops->mem_ops->exec_op) { + unsigned int len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + + op->dummy.nbytes; + if (slave->max_write_size && len > slave->max_write_size) + return -EINVAL; + + if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_read_size); + else if (slave->max_write_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_write_size - len); + + if (!op->data.nbytes) + return -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); From 966e7ed9afd182061eac582c80b86c9442b68236 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 15 Mar 2019 15:15:07 +0100 Subject: [PATCH 108/244] spi: spi-mem: Claim SPI bus before spi mem access It is necessary to call spi_claim_bus() before starting any SPI transactions and this restriction would also apply when calling spi-mem operations. Therefore claim and release bus before requesting transfer via exec_op. Change-Id: I2ec36bfe8645520016ca61f9a5869e8dcf065fe6 Signed-off-by: Vignesh R Tested-by: Simon Goldschmidt Tested-by: Stefan Roese Tested-by: Horatiu Vultur Reviewed-by: Jagan Teki Tested-by: Jagan Teki #zynq-microzed Reviewed-on: https://gerrit.st.com/128085 Reviewed-by: CITOOLS Reviewed-by: Christophe KERELLO Tested-by: Christophe KERELLO Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/spi-mem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 334af682dc65..1bb0987edb72 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -210,6 +210,10 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) if (!spi_mem_supports_op(slave, op)) return -ENOTSUPP; + ret = spi_claim_bus(slave); + if (ret < 0) + return ret; + if (ops->mem_ops) { #ifndef __UBOOT__ /* @@ -232,6 +236,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) mutex_lock(&ctlr->io_mutex); #endif ret = ops->mem_ops->exec_op(slave, op); + #ifndef __UBOOT__ mutex_unlock(&ctlr->io_mutex); mutex_unlock(&ctlr->bus_lock_mutex); @@ -245,8 +250,10 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) * read path) and expect the core to use the regular SPI * interface in other cases. */ - if (!ret || ret != -ENOTSUPP) + if (!ret || ret != -ENOTSUPP) { + spi_release_bus(slave); return ret; + } } #ifndef __UBOOT__ @@ -333,10 +340,6 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; op_buf = calloc(1, op_len); - ret = spi_claim_bus(slave); - if (ret < 0) - return ret; - op_buf[pos++] = op->cmd.opcode; if (op->addr.nbytes) { From ea6fec0b6f9690036b7e8e021770cac4ed7ec54e Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Thu, 28 Feb 2019 11:16:40 +0100 Subject: [PATCH 109/244] spi: stm32_qspi: set fsize to max address This patch set the fsize to max address. It not necessary to know the flash size. Change-Id: Icc00c818a44780e147690a2ae6db618d81f707f9 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128086 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 3b92254a5ce1..54f14ba3c1ae 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -205,15 +205,6 @@ static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) ; } -static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size) -{ - u32 fsize = fls(size) - 1; - - clrsetbits_le32(&priv->regs->dcr, - STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT, - fsize << STM32_QSPI_DCR_FSIZE_SHIFT); -} - static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs) { clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, @@ -501,6 +492,10 @@ static int stm32_qspi_probe(struct udevice *bus) setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); + /* Set dcr fsize to max address */ + setbits_le32(&priv->regs->dcr, + STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT); + return 0; } @@ -513,12 +508,10 @@ 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; 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) @@ -526,8 +519,6 @@ static int stm32_qspi_claim_bus(struct udevice *dev) _stm32_qspi_set_cs(priv, slave_plat->cs); - _stm32_qspi_set_flash_size(priv, flash->size); - _stm32_qspi_enable(priv); return 0; From df7e29293ba3add24fc4d885adef869c0190110d Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Thu, 28 Feb 2019 11:55:12 +0100 Subject: [PATCH 110/244] spi: stm32_qspi: remove useless functions and local variables Change-Id: Ie0b1a15735e76a71e4c6def439adf630672069c3 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128087 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 52 +++++++++------------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 54f14ba3c1ae..17e4524069f7 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -177,16 +177,6 @@ struct stm32_qspi_priv { #define CMD_HAS_DATA BIT(26) }; -static void _stm32_qspi_disable(struct stm32_qspi_priv *priv) -{ - clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} - -static void _stm32_qspi_enable(struct stm32_qspi_priv *priv) -{ - setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} - static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) { while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) @@ -205,12 +195,6 @@ static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) ; } -static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs) -{ - clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, - cs ? STM32_QSPI_CR_FSEL : 0); -} - static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) { unsigned int ccr_reg = 0; @@ -446,13 +430,11 @@ 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 dm_spi_bus *dm_spi_bus = bus->uclass_priv; struct clk clk; struct reset_ctl reset_ctl; int ret; - dm_spi_bus = bus->uclass_priv; - dm_spi_bus->max_hz = plat->max_hz; priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; @@ -506,33 +488,26 @@ static int stm32_qspi_remove(struct udevice *bus) static int stm32_qspi_claim_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct dm_spi_slave_platdata *slave_plat; - - bus = dev->parent; - priv = dev_get_priv(bus); - slave_plat = dev_get_parent_platdata(dev); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); if (slave_plat->cs >= STM32_MAX_NORCHIP) return -ENODEV; - _stm32_qspi_set_cs(priv, slave_plat->cs); + /* Set chip select */ + clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, + slave_plat->cs ? STM32_QSPI_CR_FSEL : 0); - _stm32_qspi_enable(priv); + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); return 0; } static int stm32_qspi_release_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - - bus = dev->parent; - priv = dev_get_priv(bus); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); - _stm32_qspi_disable(priv); + clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); return 0; } @@ -540,13 +515,8 @@ static int stm32_qspi_release_bus(struct udevice *dev) static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct spi_flash *flash; - - bus = dev->parent; - priv = dev_get_priv(bus); - flash = dev_get_uclass_priv(dev); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); + struct spi_flash *flash = dev_get_uclass_priv(dev); return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout, (u8 *)din, flags); From a2ddf2bacf61f5f23ecf52f15ac5157f51411a21 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Mon, 18 Mar 2019 11:50:26 +0100 Subject: [PATCH 111/244] spi: stm32_qspi: manage different flashes There is 2 chip select. Each chip select can manage different flashes that have different configurations (frequency, mode). The controller has to be properly configured for each flash. Set_speed and set_mode functions are not systematically called before the bus is claimed. To avoid any issues, the flash configuration is saved the first time claim_bus function is called, and then is systematically restored each time we move from a different chip select. Change-Id: I9e94d4ade934eba6760a90f28ccdbfd4fd771705 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128088 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 41 ++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 17e4524069f7..8813507d04ad 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -155,7 +155,7 @@ enum STM32_QSPI_CCR_FMODE { /* default SCK frequency, unit: HZ */ #define STM32_QSPI_DEFAULT_SCK_FREQ 108000000 -#define STM32_MAX_NORCHIP 2 +#define STM32_QSPI_MAX_CHIP 2 struct stm32_qspi_platdata { u32 base; @@ -163,11 +163,20 @@ struct stm32_qspi_platdata { u32 max_hz; }; +struct stm32_qspi_flash { + u32 cr; + u32 dcr; + u32 mode; + bool initialized; +}; + struct stm32_qspi_priv { struct stm32_qspi_regs *regs; + struct stm32_qspi_flash flash[STM32_QSPI_MAX_CHIP]; ulong clock_rate; u32 max_hz; u32 mode; + int cs_used; u32 command; u32 address; @@ -438,7 +447,7 @@ static int stm32_qspi_probe(struct udevice *bus) dm_spi_bus->max_hz = plat->max_hz; priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; - + priv->cs_used = -1; priv->max_hz = plat->max_hz; ret = clk_get_by_index(bus, 0, &clk); @@ -491,12 +500,32 @@ static int stm32_qspi_claim_bus(struct udevice *dev) struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - if (slave_plat->cs >= STM32_MAX_NORCHIP) + if (slave_plat->cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; - /* Set chip select */ - clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, - slave_plat->cs ? STM32_QSPI_CR_FSEL : 0); + if (priv->cs_used != slave_plat->cs) { + struct stm32_qspi_flash *flash = &priv->flash[slave_plat->cs]; + + priv->cs_used = slave_plat->cs; + + if (flash->initialized) { + /* Set the configuration: speed + mode + cs */ + writel(flash->cr, &priv->regs->cr); + writel(flash->dcr, &priv->regs->dcr); + priv->mode = flash->mode; + } else { + /* Set chip select */ + clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, + priv->cs_used ? STM32_QSPI_CR_FSEL : 0); + + /* Save the configuration: speed + mode + cs */ + flash->cr = readl(&priv->regs->cr); + flash->dcr = readl(&priv->regs->dcr); + flash->mode = priv->mode; + + flash->initialized = true; + } + } setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); From 0c82ca32d85483806ac2ed9f91282791d3fc1291 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Mon, 18 Mar 2019 11:53:36 +0100 Subject: [PATCH 112/244] spi: stm32_qspi: rework read/write data function This patch prepares the add of exec_op function used by spi-mem framework. stm32_qspi_tx_poll function will be called in exec_op function. Change-Id: I8cd1e4c128e71e6720a3adaa46f3ad03ce13f3a3 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128089 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 79 +++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 8813507d04ad..aa7520c58839 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -18,6 +18,7 @@ #include #include #include +#include struct stm32_qspi_regs { u32 cr; /* 0x00 */ @@ -157,6 +158,8 @@ enum STM32_QSPI_CCR_FMODE { #define STM32_QSPI_MAX_CHIP 2 +#define STM32_QSPI_FIFO_TIMEOUT_US 30000 + struct stm32_qspi_platdata { u32 base; u32 memory_map; @@ -198,12 +201,6 @@ static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) ; } -static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) -{ - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF)) - ; -} - static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) { unsigned int ccr_reg = 0; @@ -287,13 +284,55 @@ static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) writel(priv->address, &priv->regs->ar); } +static void _stm32_qspi_read_fifo(u8 *val, void __iomem *addr) +{ + *val = readb(addr); +} + +static void _stm32_qspi_write_fifo(u8 *val, void __iomem *addr) +{ + writeb(*val, addr); +} + +static int _stm32_qspi_poll(struct stm32_qspi_priv *priv, + const u8 *dout, u8 *din, u32 len) +{ + void (*fifo)(u8 *val, void __iomem *addr); + u32 sr; + u8 *buf; + int ret; + + if (din) { + fifo = _stm32_qspi_read_fifo; + buf = din; + + } else { + fifo = _stm32_qspi_write_fifo; + buf = (u8 *)dout; + } + + 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; + } + + fifo(buf++, &priv->regs->dr); + } + + return 0; +} + 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) { unsigned int words = bitlen / 8; u32 ccr_reg; - int i; + int ret; if (flags & SPI_XFER_MMAP) { _stm32_qspi_enable_mmap(priv, flash); @@ -359,17 +398,9 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, __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); - - i = 0; - while (words > i) { - writeb(dout[i], &priv->regs->dr); - debug("%02x ", dout[i]); - i++; - } - debug("\n"); + ret = _stm32_qspi_poll(priv, dout, NULL, words); + if (ret) + return ret; _stm32_qspi_wait_for_complete(priv); } else { @@ -388,15 +419,11 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, priv->regs->ccr, priv->regs->ar, priv->regs->dlr); - debug("%s: data:", __func__); + ret = _stm32_qspi_poll(priv, NULL, din, words); + if (ret) + return ret; - i = 0; - while (words > i) { - din[i] = readb(&priv->regs->dr); - debug("%02x ", din[i]); - i++; - } - debug("\n"); + _stm32_qspi_wait_for_complete(priv); } return 0; From 924fb0070de20753938192300d62a54850789eb3 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Mon, 18 Mar 2019 11:58:41 +0100 Subject: [PATCH 113/244] spi: stm32_qspi: rework end of transfer This patch prepares the add of exec_op function used by spi-mem framework. stm32_qspi_wait_cmd function will be called in exec_op function. Change-Id: I79236beefde7ea1056b47ec74c1cf21f98227404 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128090 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 51 ++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index aa7520c58839..7a3eb7884253 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -159,6 +159,7 @@ enum STM32_QSPI_CCR_FMODE { #define STM32_QSPI_MAX_CHIP 2 #define STM32_QSPI_FIFO_TIMEOUT_US 30000 +#define STM32_QSPI_CMD_TIMEOUT_US 1000000 struct stm32_qspi_platdata { u32 base; @@ -195,12 +196,6 @@ static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) ; } -static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) -{ - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF)) - ; -} - static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) { unsigned int ccr_reg = 0; @@ -284,6 +279,32 @@ static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) writel(priv->address, &priv->regs->ar); } +static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, bool wait_nobusy) +{ + u32 sr; + int ret; + + if (wait_nobusy) { + _stm32_qspi_wait_for_not_busy(priv); + return 0; + } + + 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; + } + + /* clear flags */ + writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + + return ret; +} + static void _stm32_qspi_read_fifo(u8 *val, void __iomem *addr) { *val = readb(addr); @@ -384,12 +405,14 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, } if (flags & SPI_XFER_END) { + bool cmd_has_data = priv->command & CMD_HAS_DATA; + 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) + if (cmd_has_data) _stm32_qspi_set_xfer_length(priv, words); _stm32_qspi_start_xfer(priv, ccr_reg); @@ -397,15 +420,15 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, debug("%s: write: ccr:0x%08x adr:0x%08x\n", __func__, priv->regs->ccr, priv->regs->ar); - if (priv->command & CMD_HAS_DATA) { + if (cmd_has_data) { ret = _stm32_qspi_poll(priv, dout, NULL, words); if (ret) return ret; - - _stm32_qspi_wait_for_complete(priv); - } else { - _stm32_qspi_wait_for_not_busy(priv); } + + ret = _stm32_qspi_wait_cmd(priv, !cmd_has_data); + if (ret) + return ret; } } else if (din) { ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ); @@ -423,7 +446,9 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, if (ret) return ret; - _stm32_qspi_wait_for_complete(priv); + ret = _stm32_qspi_wait_cmd(priv, false); + if (ret) + return ret; } return 0; From a62067f8ff034ede30c4824d8f2ee09f42714d36 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 5 Mar 2019 14:55:02 +0100 Subject: [PATCH 114/244] spi: stm32_qspi: use readl_poll_timeout to avoid infinite loop Change-Id: I0bd7787747f8a266a87198b10b2b77bac0406280 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128091 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 7a3eb7884253..efbb6e3a0be3 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -160,6 +160,7 @@ enum STM32_QSPI_CCR_FMODE { #define STM32_QSPI_FIFO_TIMEOUT_US 30000 #define STM32_QSPI_CMD_TIMEOUT_US 1000000 +#define STM32_BUSY_TIMEOUT_US 100000 struct stm32_qspi_platdata { u32 base; @@ -190,10 +191,18 @@ struct stm32_qspi_priv { #define CMD_HAS_DATA BIT(26) }; -static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) +static int _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) { - while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) - ; + u32 sr; + int ret; + + 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); + + return ret; } static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) @@ -284,10 +293,8 @@ static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, bool wait_nobusy) u32 sr; int ret; - if (wait_nobusy) { - _stm32_qspi_wait_for_not_busy(priv); - return 0; - } + if (wait_nobusy) + return _stm32_qspi_wait_for_not_busy(priv); ret = readl_poll_timeout(&priv->regs->sr, sr, sr & STM32_QSPI_SR_TCF, @@ -410,7 +417,9 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_WRITE); - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; if (cmd_has_data) _stm32_qspi_set_xfer_length(priv, words); @@ -433,7 +442,9 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, } else if (din) { ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ); - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; _stm32_qspi_set_xfer_length(priv, words); @@ -610,6 +621,7 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) u32 qspi_clk = priv->clock_rate; u32 prescaler = 255; u32 csht; + int ret; if (speed > plat->max_hz) speed = plat->max_hz; @@ -625,7 +637,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 << @@ -645,8 +659,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); From fe4a37e98548f943aa95a66f7e14e3c26ac1505d Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Mon, 18 Mar 2019 11:58:07 +0100 Subject: [PATCH 115/244] spi: stm32_qspi: add exec_op support This patch adds exec_op support used in SPI-MEM framework. Thanks to exec_op support, spi nand framework can currently be used with QSPI IP. Change-Id: I951744082c61a7e88e73ce870a329d8bc19fbdea Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128092 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index efbb6e3a0be3..ccc7ce9dda0a 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -161,6 +162,7 @@ enum STM32_QSPI_CCR_FMODE { #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_platdata { u32 base; @@ -465,6 +467,100 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, return 0; } +static int _stm32_qspi_tx(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op) +{ + if (!op->data.nbytes) + return 0; + + if (op->data.dir == SPI_MEM_DATA_IN) + return _stm32_qspi_poll(priv, NULL, op->data.buf.in, + op->data.nbytes); + + return _stm32_qspi_poll(priv, op->data.buf.out, NULL, op->data.nbytes); +} + +static int _stm32_qspi_get_mode(u8 buswidth) +{ + if (buswidth == 4) + return 3; + + return buswidth; +} + +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; + 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; + + ccr = (STM32_QSPI_CCR_IND_WRITE << STM32_QSPI_CCR_FMODE_SHIFT); + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) + ccr = (STM32_QSPI_CCR_IND_READ << STM32_QSPI_CCR_FMODE_SHIFT); + + if (op->data.nbytes) + _stm32_qspi_set_xfer_length(priv, op->data.nbytes); + + ccr |= op->cmd.opcode; + ccr |= (_stm32_qspi_get_mode(op->cmd.buswidth) + << STM32_QSPI_CCR_IMODE_SHIFT); + + 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); + } + + if (op->dummy.buswidth && op->dummy.nbytes) + ccr |= (op->dummy.nbytes * 8 / op->dummy.buswidth + << STM32_QSPI_CCR_DCYC_SHIFT); + + if (op->data.nbytes) + ccr |= (_stm32_qspi_get_mode(op->data.buswidth) + << STM32_QSPI_CCR_DMODE_SHIFT); + + writel(ccr, &priv->regs->ccr); + + if (op->addr.nbytes) + writel(op->addr.val, &priv->regs->ar); + + ret = _stm32_qspi_tx(priv, op); + if (ret) + goto abort; + + /* wait end of tx in indirect mode */ + ret = _stm32_qspi_wait_cmd(priv, !op->data.nbytes); + if (ret) + goto abort; + + return 0; + +abort: + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); + + /* wait clear of abort bit by hw */ + timeout = readl_poll_timeout(&priv->regs->cr, cr, + !(cr & STM32_QSPI_CR_ABORT), + STM32_ABT_TIMEOUT_US); + + writel(STM32_QSPI_FCR_CTCF, &priv->regs->fcr); + + if (ret || timeout) + debug("%s ret:%d abort timeout:%d\n", __func__, ret, timeout); + + return ret; +} + static int stm32_qspi_ofdata_to_platdata(struct udevice *bus) { struct resource res_regs, res_mem; @@ -708,12 +804,17 @@ 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[] = { From 208786420dd8635468f4b065b3feed0d63523a6c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 10 Apr 2019 12:47:36 +0200 Subject: [PATCH 116/244] board: stm32mp1: rework board_mtdparts_default This patch prepares the support of the spi nand device. Change-Id: I043065b3c27d583be550a353078c92f9c2b15428 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128093 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY Reviewed-by: CIBUILD --- board/st/stm32mp1/stm32mp1.c | 75 ++++++++++++++++++++++++------------ include/configs/stm32mp1.h | 2 +- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index c3e3b3952725..7e38780edb1b 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -906,6 +906,7 @@ void board_quiesce_devices(void) #ifdef CONFIG_SYS_MTDPARTS_RUNTIME #define MTDPARTS_LEN 256 +#define MTDIDS_LEN 128 /** * The mtdparts_nand0 and mtdparts_nor0 variable tends to be long. @@ -915,7 +916,7 @@ void board_quiesce_devices(void) * @param buf temporary buffer pointer MTDPARTS_LEN long * @return mtdparts variable string, NULL if not found */ -static const char *env_get_mtdparts(char *str, char *buf) +static const char *env_get_mtdparts(const char *str, char *buf) { if (gd->flags & GD_FLG_ENV_READY) return env_get(str); @@ -924,40 +925,64 @@ static const char *env_get_mtdparts(char *str, char *buf) return NULL; } +/** + * update the variables "mtdids" and "mtdparts" with content of mtdparts_ + */ +static void board_get_mtdparts(const char *dev, + char *mtdids, + char *mtdparts) +{ + char env_name[32] = "mtdparts_"; + char tmp_mtdparts[MTDPARTS_LEN]; + const char *tmp; + + /* name of env variable to read = mtdparts_ */ + strcat(env_name, dev); + tmp = env_get_mtdparts(env_name, tmp_mtdparts); + if (tmp) { + /* mtdids: "=, ...." */ + if (mtdids[0] != '\0') + strcat(mtdids, ","); + strcat(mtdids, dev); + strcat(mtdids, "="); + strcat(mtdids, dev); + + /* mtdparts: "mtdparts=:>;..." */ + if (mtdparts[0] != '\0') + strncat(mtdparts, ";", MTDPARTS_LEN); + else + strcat(mtdparts, "mtdparts="); + strncat(mtdparts, dev, MTDPARTS_LEN); + strncat(mtdparts, ":", MTDPARTS_LEN); + strncat(mtdparts, tmp, MTDPARTS_LEN); + } +} + void board_mtdparts_default(const char **mtdids, const char **mtdparts) { struct udevice *dev; - char s_nand0[128] = {0}, s_nor0[128] = {0}; - char mtdparts_buf[MTDPARTS_LEN]; - const char *temp; - static char parts[256]; - static char ids[22]; + static char parts[2 * MTDPARTS_LEN + 1]; + static char ids[MTDIDS_LEN + 1]; + static bool mtd_initialized; + + if (mtd_initialized) { + *mtdids = ids; + *mtdparts = parts; + return; + } + + memset(parts, 0, sizeof(parts)); + memset(ids, 0, sizeof(ids)); if (!uclass_get_device(UCLASS_MTD, 0, &dev)) { - temp = env_get_mtdparts("mtdparts_nand0", mtdparts_buf); - if (temp) - snprintf(s_nand0, sizeof(s_nand0), temp); + board_get_mtdparts("nand0", ids, parts); } if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) { - temp = env_get_mtdparts("mtdparts_nor0", mtdparts_buf); - if (temp) - snprintf(s_nor0, sizeof(s_nor0), temp); + board_get_mtdparts("nor0", ids, parts); } - strcpy(ids, ""); - strcpy(parts, ""); - if (strlen(s_nand0) && strlen(s_nor0)) { - snprintf(ids, sizeof(ids), "nor0=nor0,nand0=nand0"); - snprintf(parts, sizeof(parts), - "mtdparts=nor0:%s;nand0:%s", s_nor0, s_nand0); - } else if (strlen(s_nand0)) { - snprintf(ids, sizeof(ids), "nand0=nand0"); - snprintf(parts, sizeof(parts), "mtdparts=nand0:%s", s_nand0); - } else if (strlen(s_nor0)) { - snprintf(ids, sizeof(ids), "nor0=nor0"); - snprintf(parts, sizeof(parts), "mtdparts=nor0:%s", s_nor0); - } + mtd_initialized = true; *mtdids = ids; *mtdparts = parts; debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts); diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 2a936895a8b1..c08b194ea0a4 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -168,7 +168,7 @@ /* with OPTEE: define specific MTD partitions = teeh, teed, teex */ #define STM32MP_MTDPARTS \ "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ - "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI);\0" + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" #else /* CONFIG_STM32MP1_OPTEE */ From 3d48f24256061cd497e4d98f945a6a03cf9503f8 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 10 Apr 2019 12:43:33 +0200 Subject: [PATCH 117/244] board: stm32mp1: add spi nand support This patch adds the support of the spi nand device in mtdparts command. Change-Id: Id708e0e9584d8460e90637f0db18f1804f3e1283 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/128094 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY Reviewed-by: CIBUILD # Conflicts: # include/configs/stm32mp1.h --- board/st/stm32mp1/stm32mp1.c | 21 +++++++++++++++++++-- include/configs/stm32mp1.h | 6 ++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 7e38780edb1b..2e0888bb7fc5 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -960,8 +961,9 @@ static void board_get_mtdparts(const char *dev, void board_mtdparts_default(const char **mtdids, const char **mtdparts) { + struct mtd_info *mtd; struct udevice *dev; - static char parts[2 * MTDPARTS_LEN + 1]; + static char parts[3 * MTDPARTS_LEN + 1]; static char ids[MTDIDS_LEN + 1]; static bool mtd_initialized; @@ -974,8 +976,23 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts) memset(parts, 0, sizeof(parts)); memset(ids, 0, sizeof(ids)); - if (!uclass_get_device(UCLASS_MTD, 0, &dev)) { + /* probe all MTD devices */ + for (uclass_first_device(UCLASS_MTD, &dev); + dev; + uclass_next_device(&dev)) { + pr_debug("mtd device = %s\n", dev->name); + } + + mtd = get_mtd_device_nm("nand0"); + if (!IS_ERR_OR_NULL(mtd)) { board_get_mtdparts("nand0", ids, parts); + put_mtd_device(mtd); + } + + mtd = get_mtd_device_nm("spi-nand0"); + if (!IS_ERR_OR_NULL(mtd)) { + board_get_mtdparts("spi-nand0", ids, parts); + put_mtd_device(mtd); } if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) { diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index c08b194ea0a4..e9801b08f86a 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -168,13 +168,15 @@ /* with OPTEE: define specific MTD partitions = teeh, teed, teex */ #define STM32MP_MTDPARTS \ "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ - "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" \ + "mtdparts_spi-nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" \ #else /* CONFIG_STM32MP1_OPTEE */ #define STM32MP_MTDPARTS \ "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),-(nor_user)\0" \ - "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" \ + "mtdparts_spi-nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" #endif /* CONFIG_STM32MP1_OPTEE */ From 66793a538dad47bd1334e171d5f9846fb4619de0 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 20 Mar 2019 17:16:06 +0100 Subject: [PATCH 118/244] board: stm32mp1: Update power supply check via USB TYPE-C Add 2 new checks: - detect when USB TYPE-C cable is not plugged correctly. In this case, GND and VBUS pins are connected but not CC1 and CC2 pins. - detect is an USB Type-C charger supplies more than 3 Amps which is not compliant with the USB Type-C specification In these 2 situations, stop the boot process and let red led blinks forever. V cc1 | V cc2 | power supply | red led | console message range (Volts) |range (Volts)| (Amps) | blinks | --------------|-------------|--------------|---------|----------------------------------- > 2.15 | < 0.2 | > 3 | for ever| USB TYPE-C charger not compliant with specification [2.15 - 1.23[ | < 0.2 | 3 | NO | NO [1.23 - 0.66[ | < 0.2 | 1.5 | 3 times | WARNING 1.5A power supply detected [0.66 - 0] | < 0.2 | 0.5 | 2 times | WARNING 500mA power supply detected < 0.2 | < 0.2 | | for ever| ERROR USB TYPE-C connection in unattached mode > 0.2 | > 0.2 | | for ever| ERROR USB TYPE-C connection in unattached mode Change-Id: I803e791c4a996ecedd41a7bb8b6855d11f45d38d Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/127540 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 69 +++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 2e0888bb7fc5..2e966d01c9fe 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -68,9 +68,10 @@ */ DECLARE_GLOBAL_DATA_PTR; +#define USB_LOW_THRESHOLD_UV 200000 #define USB_WARNING_LOW_THRESHOLD_UV 660000 #define USB_START_LOW_THRESHOLD_UV 1230000 -#define USB_START_HIGH_THRESHOLD_UV 2100000 +#define USB_START_HIGH_THRESHOLD_UV 2150000 int checkboard(void) { @@ -643,9 +644,10 @@ static int board_check_usb_power(void) ofnode node; unsigned int raw; int max_uV = 0; + int min_uV = USB_START_HIGH_THRESHOLD_UV; int ret, uV, adc_count; - u8 i, nb_blink; - + u32 nb_blink; + u8 i; node = ofnode_path("/config"); if (!ofnode_valid(node)) { debug("%s: no /config node?\n", __func__); @@ -697,6 +699,8 @@ static int board_check_usb_power(void) if (!adc_raw_to_uV(adc, raw, &uV)) { if (uV > max_uV) max_uV = uV; + if (uV < min_uV) + min_uV = uV; pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__, adc->name, adc_args.args[0], raw, uV); } else { @@ -711,27 +715,66 @@ static int board_check_usb_power(void) * continue. */ if (max_uV > USB_START_LOW_THRESHOLD_UV && - max_uV < USB_START_HIGH_THRESHOLD_UV) + max_uV <= USB_START_HIGH_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) return 0; - /* Stop boot process and make u-boot,error-led blinking */ - pr_err("\n*******************************************\n"); + pr_err("****************************************************\n"); + + /* + * If highest and lowest value are either both below + * USB_LOW_THRESHOLD_UV or both above USB_LOW_THRESHOLD_UV, that + * means USB TYPE-C is in unattached mode, this is an issue, make + * u-boot,error-led blinking and stop boot process. + */ + if ((max_uV > USB_LOW_THRESHOLD_UV && + min_uV > USB_LOW_THRESHOLD_UV) || + (max_uV <= USB_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV)) { + pr_err("* ERROR USB TYPE-C connection in unattached mode *\n"); + pr_err("* Check that USB TYPE-C cable is correctly plugged *\n"); + /* with 125ms interval, led will blink for 17.02 years ....*/ + nb_blink = U32_MAX; + } - if (max_uV < USB_WARNING_LOW_THRESHOLD_UV) { - pr_err("* WARNING 500mA power supply detected *\n"); + if (max_uV > USB_LOW_THRESHOLD_UV && + max_uV <= USB_WARNING_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) { + pr_err("* WARNING 500mA power supply detected *\n"); nb_blink = 2; - } else { - pr_err("* WARNING 1.5A power supply detected *\n"); + } + + if (max_uV > USB_WARNING_LOW_THRESHOLD_UV && + max_uV <= USB_START_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) { + pr_err("* WARNING 1.5mA power supply detected *\n"); nb_blink = 3; } - pr_err("* Current too low, use a 3A power supply! *\n"); - pr_err("*******************************************\n\n"); + /* + * If highest value is above 2.15 Volts that means that the USB TypeC + * supplies more than 3 Amp, this is not compliant with TypeC specification + */ + if (max_uV > USB_START_HIGH_THRESHOLD_UV) { + pr_err("* USB TYPE-C charger not compliant with *\n"); + pr_err("* specification *\n"); + pr_err("****************************************************\n\n"); + /* with 125ms interval, led will blink for 17.02 years ....*/ + nb_blink = U32_MAX; + } else { + 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) + if (ret) { + /* in unattached case, the boot process must be stopped */ + if (nb_blink == U32_MAX) + hang(); return ret; + } + /* make u-boot,error-led blinking */ for (i = 0; i < nb_blink * 2; i++) { led_set_state(led, LEDST_TOGGLE); mdelay(125); From f4bc35b197e74ca46f42ecaaf291a3a7e3231c97 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 26 Mar 2019 15:13:21 +0100 Subject: [PATCH 119/244] stm32mp1: increase CONFIG_ENV_SIZE To allows to save current environment in SDCARD, which already larger than 4KB. Environment size: 4106/4091 bytes we need to increase the value of CONFIG_ENV_SIZE to 8KB. Change-Id: Iec6b3e825770236f6a8d04b8d2b160cf2f345286 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/128947 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- include/configs/stm32mp1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index e9801b08f86a..04ed16054db9 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -48,7 +48,7 @@ /* * Env parameters */ -#define CONFIG_ENV_SIZE SZ_4K +#define CONFIG_ENV_SIZE SZ_8K #if defined(CONFIG_ENV_IS_IN_UBI) #define CONFIG_ENV_UBI_PART "UBI" From bf89e5e46380bd86947e4642841fdc61ebe8012a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 26 Mar 2019 14:51:31 +0100 Subject: [PATCH 120/244] stm32mp1: Manage all RGMII interfaces for eth Board codes for stm32mp1, manage all rgmii interfaces (rgmii, rgmii-id, rgmii-rxid, rgmii-txid) Change-Id: Iae63224c3508a34f13257c6c2c73117c7730a31b Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/128948 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe ROULLIER --- board/st/stm32mp1/stm32mp1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 2e966d01c9fe..08b55629215c 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -577,6 +577,9 @@ int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__); break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: if (eth_clk_sel_reg) value = SYSCFG_PMCSETR_ETH_SEL_RGMII | SYSCFG_PMCSETR_ETH_CLK_SEL; From 92b1335d5fb3ba877d59ed4ce2c1715177c71e6a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 26 Mar 2019 14:50:18 +0100 Subject: [PATCH 121/244] ARM: dts: stm32: alignment with v4.19-stm32mp-r1.2 Change-Id: Ic9b3df51ca2c8d6d8879aa0aa07528c3661f6c33 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/128949 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 16 ++++++++-------- arch/arm/dts/stm32mp157a-dk1.dts | 7 +++---- arch/arm/dts/stm32mp157c-dk2.dts | 1 + arch/arm/dts/stm32mp157c-ed1.dts | 4 ++-- arch/arm/dts/stm32mp157c-ev1.dts | 2 +- arch/arm/dts/stm32mp157c.dtsi | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 970a4105b170..3813f98023c7 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -248,7 +248,7 @@ pinmux = ; /* DFSDM_CKOUT */ bias-disable; drive-push-pull; - slew-rate = <1>; + slew-rate = <0>; }; }; @@ -1418,13 +1418,6 @@ }; }; - stusb1600_pins_a: stusb1600-0 { - pins { - pinmux = ; - bias-pull-up; - }; - }; - spi5_sleep_pins_a: spi5-sleep-0 { pins { pinmux = , /* SPI5_SCK */ @@ -1433,6 +1426,13 @@ }; }; + stusb1600_pins_a: stusb1600-0 { + pins { + pinmux = ; + bias-pull-up; + }; + }; + uart4_pins_a: uart4-0 { pins1 { pinmux = ; /* UART4_TX */ diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 219e62b32430..be5497316ff4 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -73,8 +73,8 @@ no-map; }; - gpu_reserved: gpu@dc000000 { - reg = <0xdc000000 0x4000000>; + gpu_reserved: gpu@d4000000 { + reg = <0xd4000000 0x4000000>; no-map; }; }; @@ -180,7 +180,7 @@ pinctrl-0 = <ðernet0_rgmii_pins_a>; pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; pinctrl-names = "default", "sleep"; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; max-speed = <1000>; phy-handle = <&phy0>; @@ -296,7 +296,6 @@ interrupt-parent = <&gpioi>; pinctrl-names = "default"; pinctrl-0 = <&stusb1600_pins_a>; - status = "okay"; typec_con: connector { diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts index 20a86f1b9abc..f41c3a900b45 100644 --- a/arch/arm/dts/stm32mp157c-dk2.dts +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -51,6 +51,7 @@ compatible = "orisetech,otm8009a"; reg = <0>; reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; + power-supply = <&v3v3>; status = "okay"; port { diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index e7d3f3752c35..12c46f225018 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -64,8 +64,8 @@ no-map; }; - gpu_reserved: gpu@f8000000 { - reg = <0xf8000000 0x8000000>; + gpu_reserved: gpu@e8000000 { + reg = <0xe8000000 0x8000000>; no-map; }; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 9f0ee3d16388..63ebabdbeb8e 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -347,7 +347,7 @@ pinctrl-0 = <ðernet0_rgmii_pins_a>; pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; pinctrl-names = "default", "sleep"; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; max-speed = <1000>; phy-handle = <&phy0>; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 6d3642d13095..c969d9b9a766 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -1273,7 +1273,7 @@ resets = <&rcc CAMITF_R>; clocks = <&rcc DCMI>; clock-names = "mclk"; - dmas = <&dmamux1 75 0x400 0xd>; + dmas = <&dmamux1 75 0x400 0x1d>; dma-names = "tx"; status = "disabled"; }; From 7157fa1d0e06c6e3f272dbeaf7fec295431078cf Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Mar 2019 18:06:49 +0100 Subject: [PATCH 122/244] test/py: Mark some pinmux tests as sandbox-centric trini update of upstreamed patch: Mark some tests as sandbox-centric Change-Id: I72d43417dccb64e3ee8be5e0144db08eba473ade Signed-off-by: Tom Rini Reviewed-on: https://gerrit.st.com/129397 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- test/py/tests/test_pinmux.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py index f04a2796ee92..25394f1fafa5 100644 --- a/test/py/tests/test_pinmux.py +++ b/test/py/tests/test_pinmux.py @@ -18,6 +18,7 @@ def test_pinmux_usage_2(u_boot_console): assert 'Usage:' in output @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_status_all(u_boot_console): """Test that 'pinmux status -a' displays pin's muxing.""" output = u_boot_console.run_command('pinmux status -a') @@ -28,6 +29,7 @@ def test_pinmux_status_all(u_boot_console): assert ('W1 : 1-wire gpio' in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_list(u_boot_console): """Test that 'pinmux list' returns the pin-controller list.""" output = u_boot_console.run_command('pinmux list') @@ -43,6 +45,7 @@ def test_pinmux_dev_bad(u_boot_console): assert (expected_output in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_dev(u_boot_console): """Test that 'pinmux dev' select the wanted pin controller.""" pincontroller = 'pinctrl' @@ -51,6 +54,7 @@ def test_pinmux_dev(u_boot_console): assert (expected_output in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_status(u_boot_console): """Test that 'pinmux status' displays selected pincontroller's pin muxing descriptions.""" From bcad06b2fffd90e8d9698c21a412999dd85d6a34 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 09:30:12 +0100 Subject: [PATCH 123/244] efi: add protection for block_dev Check the value of block_dev before to use this pointer. This patch solves problem for the command "load" when ubifs is previously mounted; in this case the function blk_get_device_part_str("ubi 0") don't return error but return block_dev = NULL and then data abort. Change-Id: I2a1e2bf1c8023fc2f463ce107949d0dc6f3bf0ea Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/129399 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- cmd/bootefi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 4d68d807480a..3a6bcc0dcee1 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -625,7 +625,7 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); - if (part < 0) + if (part < 0 || !desc) return; bootefi_device_path = efi_dp_from_part(desc, part); From e0fcd22cd6e6d1148875dc45591f40099ed650a1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 27 Mar 2019 14:22:22 +0100 Subject: [PATCH 124/244] video: OTM8009A: remove trace during probe Change dev_err to dev_dbg for regulator trace. Add dev_err when erro is detected. Change-Id: I938adb51d9d5cbd3448dbb9845bcf7f6172a9524 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/129124 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Philippe CORNU Reviewed-by: Yannick FERTRE --- drivers/video/orisetech_otm8009a.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c index ad1d6f0fd4ac..41c4bef6349a 100644 --- a/drivers/video/orisetech_otm8009a.c +++ b/drivers/video/orisetech_otm8009a.c @@ -302,10 +302,13 @@ static int otm8009a_panel_probe(struct udevice *dev) int ret; if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { - dev_err(dev, "enable regulator '%s'\n", priv->reg->name); + dev_dbg(dev, "enable regulator '%s'\n", priv->reg->name); ret = regulator_set_enable(priv->reg, true); - if (ret) + if (ret) { + dev_err(dev, "Regulator : '%s' - can't enable\n", + priv->reg->name); return ret; + } } /* reset panel */ From 9ee3938bca68fb3ca302780d0cbd06cb728ddbae Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 2 Apr 2019 10:13:06 +0200 Subject: [PATCH 125/244] mmc: stm32_sdmmc2: reload watchdog This patch solves a watchdog reset issue during mmc erase command. Change-Id: I0caaea396a9a9aa0280660751590f0945b090186 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/129888 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/mmc/stm32_sdmmc2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index ed31ca126e93..34503c72a7a2 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -14,6 +14,7 @@ #include #include #include +#include struct stm32_sdmmc2_plat { struct mmc_config cfg; @@ -432,6 +433,8 @@ static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0; int ret, retry = 3; + WATCHDOG_RESET(); + retry_cmd: ctx.data_length = 0; ctx.dpsm_abort = false; From 891268d7751c8d704f442f62490e1b5581fba5d3 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 2 Apr 2019 14:40:41 +0200 Subject: [PATCH 126/244] mtd: rawnand: stm32_fmc2: fix oob free offset This patch set the correct size and offset of the oob free region. Change-Id: Ib1c5ae9b06eff55549bdd87576ef3c9cdf1d199b Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/129889 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 6f6f5e6ae9f9..49922bb88b16 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1049,7 +1049,7 @@ static int stm32_fmc2_probe(struct udevice *dev) oob_index = FMC2_BBM_LEN; for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) ecclayout->eccpos[i] = oob_index; - ecclayout->oobfree->offset = oob_index + 1; + ecclayout->oobfree->offset = oob_index; ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; chip->ecc.layout = ecclayout; From 7dc89bab59b724a61e590bf131e7e62aa540c2b9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 2 Apr 2019 19:15:54 +0200 Subject: [PATCH 127/244] stm32mp1: dfu: reset pointer at the end of the stm32prog command Reset data pointer stm32prog_data to avoid data abort when "dfu" command is used after "stm32prog command" Change-Id: Id23adcb3bc156a40fc65fef4df8a134de1dec2f9 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/129938 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c index c7dd678c669b..f795a9c91b00 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c @@ -254,6 +254,7 @@ static const char product[] = bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) { int ret; + bool result; stm32prog_data = data; g_dnl_set_product(product); @@ -267,8 +268,14 @@ bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) /* found next selected partition */ stm32prog_next_phase(data); } - return (run_usb_dnl_gadget(dev, "usb_dnl_dfu") || - (stm32prog_data->phase == PHASE_DO_RESET)); + + ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu") ; + + result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET); + + stm32prog_data = NULL; + + return result; } int g_dnl_get_board_bcd_device_number(int gcnum) From 038753164d6a7708e50d3083a2cce6b1da726a84 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 1 Apr 2019 18:21:09 +0200 Subject: [PATCH 128/244] stm32mp1: migrate BOOTCOMMAND in defconfig Migration needed after commit b6251db8c3f0 ("Kconfig: Introduce USE_BOOTCOMMAND and migrate BOOTCOMMAND") Change-Id: I183e04ae8606a07f1f9f637ef9018e3c19f919b2 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/129736 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + include/configs/stm32mp1.h | 4 +--- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 69372e2cf8e7..134e901cc139 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -9,6 +9,7 @@ CONFIG_SPL_SPI_SUPPORT=y # CONFIG_ARMV7_VIRT is not set 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 CONFIG_SPL_I2C_SUPPORT=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index f284c3d7956b..826a959ca2c7 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -5,6 +5,7 @@ CONFIG_TARGET_STM32MP1=y CONFIG_STM32MP1_OPTEE=y CONFIG_DISTRO_DEFAULTS=y CONFIG_FIT=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/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index b18debe9a473..c240eb427ef0 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -4,6 +4,7 @@ CONFIG_SYS_MALLOC_F_LEN=0x3000 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 # CONFIG_CMD_ELF is not set diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 04ed16054db9..02f32984fe02 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -146,11 +146,9 @@ * for nor boot, use the default order */ #define CONFIG_PREBOOT -#undef CONFIG_BOOTCOMMAND -#define CONFIG_BOOTCOMMAND \ - "echo \"Boot over ${boot_device}${boot_instance}!\";run bootcmd_stm32mp" #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 " \ From 539d60142ffc5c728491fc6c61f8e32304299c4b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 11 Apr 2019 17:38:35 +0200 Subject: [PATCH 129/244] serial: stm32: add Framing error support Add management of Bit 1 of USART_ISR = FE: Framing error This bit is set by hardware when a de-synchronization, excessive noise or a break character is detected. It is cleared by software, writing 1 to the FECF bit in the USART_ICR register (for stm32 after f4). Change-Id: I31b1d3ab476d95e4265c8b509e9e8406769c6875 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/130864 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Fabrice GASNIER --- drivers/serial/serial_stm32.c | 5 +++-- drivers/serial/serial_stm32.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index d806057c607d..fcfd02c14745 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -114,10 +114,11 @@ static int stm32_serial_getc(struct udevice *dev) if ((isr & USART_ISR_RXNE) == 0) return -EAGAIN; - if (isr & (USART_ISR_PE | USART_ISR_ORE)) { + if (isr & (USART_ISR_PE | USART_ISR_ORE | USART_ISR_FE)) { if (!stm32f4) setbits_le32(base + ICR_OFFSET, - USART_ICR_PCECF | USART_ICR_ORECF); + USART_ICR_PCECF | USART_ICR_ORECF | + USART_ICR_FECF); else readl(base + RDR_OFFSET(stm32f4)); return -EIO; diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h index 5549f8c5368a..7b0c53145e8b 100644 --- a/drivers/serial/serial_stm32.h +++ b/drivers/serial/serial_stm32.h @@ -67,6 +67,7 @@ struct stm32x7_serial_platdata { #define USART_ISR_TXE BIT(7) #define USART_ISR_RXNE BIT(5) #define USART_ISR_ORE BIT(3) +#define USART_ISR_FE BIT(1) #define USART_ISR_PE BIT(0) #define USART_BRR_F_MASK GENMASK(7, 0) @@ -74,6 +75,7 @@ struct stm32x7_serial_platdata { #define USART_BRR_M_MASK GENMASK(15, 4) #define USART_ICR_ORECF BIT(3) +#define USART_ICR_FECF BIT(1) #define USART_ICR_PCECF BIT(0) #endif From 51da0de92cd5733255730ed2fb5443b2d310ad5a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 15 Apr 2019 11:04:37 +0200 Subject: [PATCH 130/244] Change FDT memory type from runtime data to boot services data Following Ard's suggestion: Runtime data sections are intended for data that is used by the runtime services implementation. Let's change the type to EFI_BOOT_SERVICES_DATA This also fixes booting of armv7 using efi and fdtcontroladdr Suggested-by: Ard Biesheuvel Signed-off-by: Ilias Apalodimas Acked-by: Ard Biesheuvel Reviewed-by: Heinrich Schuchardt [backport of http://patchwork.ozlabs.org/patch/1084888/] Change-Id: Ibf8d4e611f4e42d026c0924fc140cd7b8116cb69 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/130999 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- cmd/bootefi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 3a6bcc0dcee1..595dbddd4a8d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -190,13 +190,13 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) /* Safe fdt location is at 127MB */ new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, + EFI_BOOT_SERVICES_DATA, fdt_pages, &new_fdt_addr); if (ret != EFI_SUCCESS) { /* If we can't put it there, put it somewhere */ new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size); ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, + EFI_BOOT_SERVICES_DATA, fdt_pages, &new_fdt_addr); if (ret != EFI_SUCCESS) { printf("ERROR: Failed to reserve space for FDT\n"); From 4701adfa82b71f1116abd3179450d7688573c0b1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 15 Apr 2019 13:01:20 +0200 Subject: [PATCH 131/244] stm32mp1: add check for presence of environment in boot device For boot from flash, check presence of default environment to force save env. Change-Id: I06d288a1f0de94cc2618ed5ee81183018d1fcc6d Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131127 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- include/configs/stm32mp1.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 02f32984fe02..1e3738ea11ac 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -152,6 +152,7 @@ "if test ${boot_device} = serial || test ${boot_device} = usb;" \ "then stm32prog ${boot_device} ${boot_instance}; " \ "else " \ + "run env_check;" \ "if test ${boot_device} = mmc;" \ "then env set boot_targets \"mmc${boot_instance}\"; fi;" \ "if test ${boot_device} = nand;" \ @@ -199,6 +200,9 @@ "bootlimit=0\0" \ "altbootcmd=run bootcmd\0" \ "usb_pgood_delay=2000\0" \ + "env_default=1\0" \ + "env_check=if test $env_default -eq 1;"\ + " then env set env_default 0;env save;fi\0" \ STM32MP_BOOTCMD \ STM32MP_MTDPARTS \ BOOTENV \ From c3217b04cd2d53c0e6d9da359363171d3045300e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 16 Apr 2019 09:34:46 +0200 Subject: [PATCH 132/244] fs: ext4: do not write on filesystem with metadata_csum feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit U-Boot doesn't support metadata_csum feature. Writing to filesystem with metadata_csum feature makes the filesystem corrupted and unbootable by Linux: [ 2.527495] EXT4-fs (mmcblk0p2): ext4_check_descriptors: Checksum for group 0 failed (52188!=0) [ 2.537421] EXT4-fs (mmcblk0p2): ext4_check_descriptors: Checksum for group 1 failed (5262!=0) ... [ 2.653308] EXT4-fs (mmcblk0p2): ext4_check_descriptors: Checksum for group 14 failed (42611!=0) [ 2.662179] EXT4-fs (mmcblk0p2): ext4_check_descriptors: Checksum for group 15 failed (21527!=0) [ 2.687920] JBD2: journal checksum error [ 2.691982] EXT4-fs (mmcblk0p2): error loading journal [ 2.698292] VFS: Cannot open root device "mmcblk0p2" or unknown-block(179,2): error -74 Don't write to filesystem with meatadata_csum feature to not corrupt the filesystem. Signed-off-by: Sébastien Szymanski [backport of 2e7365518acdb8fb6e9be332c8a6c57b457188d9] Change-Id: Icac8b1841bb574bdbcbc0522bb50973aaf7a10eb Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131128 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- fs/ext4/ext4_write.c | 6 ++++++ include/ext4fs.h | 1 + 2 files changed, 7 insertions(+) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index a7f543f7df7d..4eb77c327ef3 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -864,6 +864,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer, printf("error in File System init\n"); return -1; } + + if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { + printf("Unsupported feature metadata_csum found, not writing.\n"); + return -1; + } + inodes_per_block = fs->blksz / fs->inodesz; parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); if (parent_inodeno == -1) diff --git a/include/ext4fs.h b/include/ext4fs.h index bb5563910725..24210113411a 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -32,6 +32,7 @@ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_EXT_MAGIC 0xf30a #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 #define EXT4_INDIRECT_BLOCKS 12 From ccc895942f4ef3522580bae1e24a4c108b878ec4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 17 Apr 2019 13:11:22 +0200 Subject: [PATCH 133/244] serial: stm32: remove watchog reset in debug putc For STM32MP, the watchdog is based on DM and the function watchod_reset call the function uclass_get_device(UCLASS_WDT) to found the driver associated IWDG2. As this reset is not mandatory in debug putc (the uart fifo will be empty after some us), we can simplify the code by removing this call. And this patch avoid issue when putc is called before initialization of DM core, before the parsing of the device tree parsing and each node bound to driver; that also avoid memory leak. Change-Id: I182687e29342c3dfdb1c3d501506fb01811a3909 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131239 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/serial/serial_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index fcfd02c14745..b57db1d2ccb4 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -284,7 +284,7 @@ static inline void _debug_uart_putc(int c) struct stm32_uart_info *uart_info = _debug_uart_info(); while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN) - WATCHDOG_RESET(); + ; } DEBUG_UART_FUNCS From 9cfd3376f775690a9e5157546028751d08f2d855 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 17 Apr 2019 19:24:57 +0200 Subject: [PATCH 134/244] dm: adc: uclass: get reference regulator once device_get_supply_regulator() only needs to be called once. But each time there's call to adc_vxx_value() for instance, it calls adc_vxx_platdata_update() -> device_get_supply_regulator(). So, move device_get_supply_regulator() to pre_probe() routine. This also allows vdd_supply/vss_supply to be provided directly from uc_pdata, e.g dt-binding variant like stm32-adc provide its own 'vref-supply'. Change-Id: I7141e575e3648ee35e6a95a44e71bbdf3f1b031a Signed-off-by: Fabrice Gasnier Reviewed-by: Simon Glass [reapply a4a87f7b7435a4ee47247e69500b8e800c6b2a21] Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/131297 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/adc/adc-uclass.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index 27b2654e3e48..0a492eba5437 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -277,13 +277,8 @@ static int adc_vdd_platdata_update(struct udevice *dev) * will bind before its supply regulator device, then the below 'get' * will return an error. */ - if (!uc_pdata->vdd_supply) { - /* Only get vdd_supply once */ - ret = device_get_supply_regulator(dev, "vdd-supply", - &uc_pdata->vdd_supply); - if (ret) - return ret; - } + if (!uc_pdata->vdd_supply) + return 0; ret = regulator_get_value(uc_pdata->vdd_supply); if (ret < 0) @@ -299,12 +294,8 @@ static int adc_vss_platdata_update(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); int ret; - if (!uc_pdata->vss_supply) { - ret = device_get_supply_regulator(dev, "vss-supply", - &uc_pdata->vss_supply); - if (ret) - return ret; - } + if (!uc_pdata->vss_supply) + return 0; ret = regulator_get_value(uc_pdata->vss_supply); if (ret < 0) From f2e7a5b262c08579dba7a4703d5dc53e164a74ee Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Thu, 9 May 2019 18:11:19 +0200 Subject: [PATCH 135/244] mtd: rawnand: stm32_fmc2: avoid warnings when building with W=1 option This patch solves warnings detected by setting W=1 when building. Warnings type detected: - [-Wsign-compare] - [-Wtype-limits] Change-Id: I25ceb25341ffdb655607d6010f637650fad1d15e Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/132878 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 93 +++++++++----------------- 1 file changed, 31 insertions(+), 62 deletions(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 49922bb88b16..a54af9434a21 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -627,21 +627,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *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; + unsigned long timing, tar, tclr, thiz, twait; + unsigned long tset_mem, tset_att, thold_mem, thold_att; + + tar = max_t(unsigned long, hclkp, sdrt->tAR_min); + timing = DIV_ROUND_UP(tar, hclkp) - 1; + tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); + + tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min); + timing = DIV_ROUND_UP(tclr, hclkp) - 1; + tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); tims->thiz = FMC2_THIZ; thiz = (tims->thiz + 1) * hclkp; @@ -651,18 +646,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * 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; + twait = max_t(unsigned long, hclkp, sdrt->tRP_min); + twait = max_t(unsigned long, twait, sdrt->tWP_min); + twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO); + timing = DIV_ROUND_UP(twait, hclkp); + tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_MEM > tCS - tWAIT @@ -677,20 +665,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, 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; + timing = DIV_ROUND_UP(tset_mem, hclkp); + tims->tset_mem = clamp_val(timing, 1, 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; + thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min); if (sdrt->tREH_min > tset_mem && (thold_mem < sdrt->tREH_min - tset_mem)) thold_mem = sdrt->tREH_min - tset_mem; @@ -700,11 +683,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, 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; + timing = DIV_ROUND_UP(thold_mem, hclkp); + tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_ATT > tCS - tWAIT @@ -726,11 +706,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, 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; + timing = DIV_ROUND_UP(tset_att, hclkp); + tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tHOLD_ATT > tALH @@ -745,17 +722,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * 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; + thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min); + thold_att = max_t(unsigned long, 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; @@ -774,11 +745,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, 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; + timing = DIV_ROUND_UP(thold_att, hclkp); + tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); } static int stm32_fmc2_setup_interface(struct mtd_info *mtd, int chipnr, @@ -932,7 +900,8 @@ static int stm32_fmc2_probe(struct udevice *dev) struct nand_ecclayout *ecclayout; struct resource resource; struct reset_ctl reset; - int oob_index, chip_cs, mem_region, ret, i; + int oob_index, chip_cs, mem_region, ret; + unsigned int i; spin_lock_init(&fmc2->controller.lock); init_waitqueue_head(&fmc2->controller.wq); From 639d358acf84519ea0ad6f7d9d9e9b1131b011aa Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 7 May 2019 15:29:30 +0200 Subject: [PATCH 136/244] mmc: stm32_sdmmc2: avoid warnings when building with W=1 option This patch solves warnings detected by setting W=1 when building. Warnings type detected: - [-Wmissing-prototypes] - [-Wimplicit-fallthrough=] Change-Id: I212f1c9723b88cda533b27464e32ac949f69a264 Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/132879 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/mmc/stm32_sdmmc2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 34503c72a7a2..e7058cbe0822 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -672,6 +672,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev) switch (dev_read_u32_default(dev, "bus-width", 1)) { case 8: cfg->host_caps |= MMC_MODE_8BIT; + /* fall through */ case 4: cfg->host_caps |= MMC_MODE_4BIT; break; @@ -695,7 +696,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev) return ret; } -int stm32_sdmmc_bind(struct udevice *dev) +static int stm32_sdmmc_bind(struct udevice *dev) { struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); From 97c4504a0ec99fc8c3a0f4052cbeb489639b8ba2 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Tue, 7 May 2019 15:30:40 +0200 Subject: [PATCH 137/244] spi: stm32_qspi: avoid warnings when building with W=1 option This patch solves warnings detected by setting W=1 when building. Warnings type detected: - [-Wtype-limits] - [-Wsign-compare] Change-Id: I345f990ea09b2be01e7db5dc3397a22593eae09a Signed-off-by: Christophe Kerello Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/132880 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index ccc7ce9dda0a..fd7fea40469b 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -621,9 +621,9 @@ static int stm32_qspi_probe(struct udevice *bus) } priv->clock_rate = clk_get_rate(&clk); - if (priv->clock_rate < 0) { + if (!priv->clock_rate) { clk_disable(&clk); - return priv->clock_rate; + return -EINVAL; } ret = reset_get_by_index(bus, 0, &reset_ctl); @@ -658,14 +658,15 @@ static int stm32_qspi_claim_bus(struct udevice *dev) { struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + int slave_cs = slave_plat->cs; - if (slave_plat->cs >= STM32_QSPI_MAX_CHIP) + if (slave_cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; - if (priv->cs_used != slave_plat->cs) { - struct stm32_qspi_flash *flash = &priv->flash[slave_plat->cs]; + if (priv->cs_used != slave_cs) { + struct stm32_qspi_flash *flash = &priv->flash[slave_cs]; - priv->cs_used = slave_plat->cs; + priv->cs_used = slave_cs; if (flash->initialized) { /* Set the configuration: speed + mode + cs */ @@ -723,11 +724,12 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) speed = plat->max_hz; if (speed > 0) { - prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; - if (prescaler > 255) - prescaler = 255; - else if (prescaler < 0) - prescaler = 0; + prescaler = 0; + if (qspi_clk) { + prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; + if (prescaler > 255) + prescaler = 255; + } } csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); From e11d95c3cedc0d55a2fabf28bf37f73acc59bf5a Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 17:28:51 +0200 Subject: [PATCH 138/244] stm32mp1: Fix warnings when compiling with W=1 This patch solves the following warnings: arch/arm/mach-stm32mp/cpu.c:386:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (instance > ARRAY_SIZE(serial_addr)) ^ Change-Id: I4a724828b579fbfbc3c26e27904867393eb87948 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133248 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-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 56bb12c56d7c..2c058f57e24e 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -374,7 +374,7 @@ static void setup_boot_mode(void) 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; + unsigned int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1; u32 forced_mode = (boot_ctx & TAMP_BOOT_FORCED_MASK); struct udevice *dev; int alias; From d08a553a8e8e5ab565aa0adecc99266826c7bf07 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 18:24:13 +0200 Subject: [PATCH 139/244] board: stm32mp1: Fix warnings when compiling with W=1 This patch solves the following warnings: board/st/stm32mp1/stm32mp1.c:164:6: warning: no previous prototype for 'board_is_dk2' [-Wmissing-prototypes] bool board_is_dk2(void) ^~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:193:5: warning: no previous prototype for 'board_mmc_init' [-Wmissing-prototypes] int board_mmc_init(void) ^~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:200:6: warning: no previous prototype for 'board_qspi_init' [-Wmissing-prototypes] void board_qspi_init(void) ^~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:276:6: warning: no previous prototype for 'board_usbotg_init' [-Wmissing-prototypes] void board_usbotg_init(void) ^~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:416:5: warning: no previous prototype for 'g_dnl_board_usb_cable_connected' [-Wmissing-prototypes] int g_dnl_board_usb_cable_connected(void) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:426:5: warning: no previous prototype for 'g_dnl_bind_fixup' [-Wmissing-prototypes] int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) ^~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:546:5: warning: no previous prototype for 'board_interface_eth_init' [-Wmissing-prototypes] int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, ^~~~~~~~~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:849:19: warning: no previous prototype for 'env_get_location' [-Wmissing-prototypes] enum env_location env_get_location(enum env_operation op, int prio) ^~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:876:13: warning: no previous prototype for 'env_ext4_get_intf' [-Wmissing-prototypes] const char *env_ext4_get_intf(void) ^~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:889:13: warning: no previous prototype for 'env_ext4_get_dev_part' [-Wmissing-prototypes] const char *env_ext4_get_dev_part(void) ^~~~~~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:946:6: warning: no previous prototype for 'board_quiesce_devices' [-Wmissing-prototypes] void board_quiesce_devices(void) ^~~~~~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:1008:6: warning: no previous prototype for 'board_mtdparts_default' [-Wmissing-prototypes] void board_mtdparts_default(const char **mtdids, const char **mtdparts) ^~~~~~~~~~~~~~~~~~~~~~ board/st/stm32mp1/stm32mp1.c:1093:6: warning: no previous prototype for 'board_stm32copro_image_process' [-Wmissing-prototypes] void board_stm32copro_image_process(ulong fw_image, size_t fw_size) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change-Id: I74605129d464688965da49d731c72431aa1313e8 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133249 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 13 ++++++++----- include/environment.h | 9 +++++++++ include/linux/mtd/mtd.h | 1 + include/netdev.h | 2 ++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 08b55629215c..7a739ac68030 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -5,17 +5,20 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -161,7 +164,7 @@ static void board_key_check(void) #endif } -bool board_is_dk2(void) +static __maybe_unused bool board_is_dk2(void) { if (of_machine_is_compatible("st,stm32mp157c-dk2")) return true; @@ -190,14 +193,14 @@ int board_late_init(void) #ifdef CONFIG_STM32_SDMMC2 /* this is a weak define that we are overriding */ -int board_mmc_init(void) +static int board_mmc_init(void) { return 0; } #endif #ifdef CONFIG_STM32_QSPI -void board_qspi_init(void) +static void board_qspi_init(void) { } #endif /* CONFIG_STM32_QSPI */ @@ -273,7 +276,7 @@ static int stusb1600_cable_connected(void) return status & STUSB1600_CC_ATTACH; } -void board_usbotg_init(void) +static void board_usbotg_init(void) { ofnode usb1600_node; int node; @@ -1090,7 +1093,7 @@ int ft_board_setup(void *blob, bd_t *bd) } #endif -void board_stm32copro_image_process(ulong fw_image, size_t fw_size) +static void board_stm32copro_image_process(ulong fw_image, size_t fw_size) { int ret, id = 0; /* Copro id fixed to 0 as only one coproc on mp1 */ unsigned int rsc_size; diff --git a/include/environment.h b/include/environment.h index 5e90f157e8d0..e5d48112987e 100644 --- a/include/environment.h +++ b/include/environment.h @@ -268,9 +268,18 @@ extern struct hsearch_data env_htab; /* Function that updates CRC of the enironment */ void env_crc_update(void); +/* allows to set ext4 interface */ +const char *env_ext4_get_intf(void); + +/* allows to set ext4 device and partition */ +const char *env_ext4_get_dev_part(void); + /* Look up the variable from the default environment */ char *env_get_default(const char *name); +/* Returns the best env location for a board */ +enum env_location env_get_location(enum env_operation op, int prio); + /* [re]set to the default environment */ void set_default_env(const char *s, int flags); diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 68e591532492..9cb0e438d8d3 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -586,5 +586,6 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset, int mtd_search_alternate_name(const char *mtdname, char *altname, unsigned int max_len); +void board_mtdparts_default(const char **mtdids, const char **mtdparts); #endif #endif /* __MTD_MTD_H__ */ diff --git a/include/netdev.h b/include/netdev.h index 55001625fb92..2b1028c54645 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -21,6 +21,8 @@ */ int board_eth_init(bd_t *bis); +int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, + bool eth_ref_clk_sel_reg); int cpu_eth_init(bd_t *bis); /* Driver initialization prototypes */ From d42837075db0a8c9432a64b33a01f97b6056fe53 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 18:25:17 +0200 Subject: [PATCH 140/244] net: dwc_eth_qos: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/net/dwc_eth_qos.c:624:6: warning: no previous prototype for 'eqos_stop_clks_tegra186' [-Wmissing-prototypes] void eqos_stop_clks_tegra186(struct udevice *dev) ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/dwc_eth_qos.c:639:6: warning: no previous prototype for 'eqos_stop_clks_stm32' [-Wmissing-prototypes] void eqos_stop_clks_stm32(struct udevice *dev) ^~~~~~~~~~~~~~~~~~~~ drivers/net/dwc_eth_qos.c:1293:6: warning: no previous prototype for 'eqos_stop' [-Wmissing-prototypes] void eqos_stop(struct udevice *dev) ^~~~~~~~~ drivers/net/dwc_eth_qos.c:1347:5: warning: no previous prototype for 'eqos_send' [-Wmissing-prototypes] int eqos_send(struct udevice *dev, void *packet, int length) ^~~~~~~~~ drivers/net/dwc_eth_qos.c:1388:5: warning: no previous prototype for 'eqos_recv' [-Wmissing-prototypes] int eqos_recv(struct udevice *dev, int flags, uchar **packetp) ^~~~~~~~~ drivers/net/dwc_eth_qos.c:1412:5: warning: no previous prototype for 'eqos_free_pkt' [-Wmissing-prototypes] int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) ^~~~~~~~~~~~~ Change-Id: I59dd686cee8f53b091cc875e12f9ee2ad2fc3271 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133250 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index cd1b4011fb57..5b933fb0d326 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -621,7 +621,7 @@ static int eqos_start_clks_stm32(struct udevice *dev) return ret; } -void eqos_stop_clks_tegra186(struct udevice *dev) +static void eqos_stop_clks_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -636,7 +636,7 @@ void eqos_stop_clks_tegra186(struct udevice *dev) debug("%s: OK\n", __func__); } -void eqos_stop_clks_stm32(struct udevice *dev) +static void eqos_stop_clks_stm32(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1290,7 +1290,7 @@ static int eqos_start(struct udevice *dev) return ret; } -void eqos_stop(struct udevice *dev) +static void eqos_stop(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); int i; @@ -1344,7 +1344,7 @@ void eqos_stop(struct udevice *dev) debug("%s: OK\n", __func__); } -int eqos_send(struct udevice *dev, void *packet, int length) +static int eqos_send(struct udevice *dev, void *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *tx_desc; @@ -1385,7 +1385,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) return -ETIMEDOUT; } -int eqos_recv(struct udevice *dev, int flags, uchar **packetp) +static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *rx_desc; @@ -1409,7 +1409,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) return length; } -int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) +static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); uchar *packet_expected; From 78bcf76da2d51b554ccdac06d39c6f5b8e889117 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 18:28:12 +0200 Subject: [PATCH 141/244] board: stm32mp1: cmd_stboard: Fix warnings when compiling with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch solves the following warnings: board/st/stm32mp1/cmd_stboard.c:24:16: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare] for (i = 0; i < ARRAY_SIZE(st_board_id); i++) ^ Change-Id: Ie93d7229fcae4ec951e3d4ddc83b8b2a74f17a08 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133251 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/cmd_stboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/st/stm32mp1/cmd_stboard.c b/board/st/stm32mp1/cmd_stboard.c index 38b1c1be1e02..03d4b521e5d7 100644 --- a/board/st/stm32mp1/cmd_stboard.c +++ b/board/st/stm32mp1/cmd_stboard.c @@ -11,7 +11,7 @@ static bool check_stboard(u16 board) { - int i; + unsigned int i; const u16 st_board_id[] = { 0x1272, 0x1263, From 649aba2badd793bcc8f385e19cb24d65861254a7 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 18:43:07 +0200 Subject: [PATCH 142/244] stm32mp1: cmd_stm32prog: Fix warnings when compiling with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch solves the following warnings: arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: In function ‘stm32prog_header_check’: arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:122:16: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare] for (i = 0; i < (sizeof(raw_header->padding) / 4); i++) { ^ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: In function ‘parse_ip’: u-boot/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:286:17: warning: comparison of integer expressions of different signedness: ‘__kernel_size_t’ {aka ‘unsigned int’} and ‘int’ [-Wsign-compare] if (strlen(p) != len + 1) { ^~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: In function 'treat_partition_list': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:818:30: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (data->dev[j].dev_type == -1) { ^~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: In function 'create_partitions': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:895:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (mmc_id < ARRAY_SIZE(uuid_mmc)) { ^ CC cmd/version.o arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: At top level: arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:1524:6: warning: no previous prototype for 'stm32prog_devices_init' [-Wmissing-prototypes] void stm32prog_devices_init(struct stm32prog_data *data) ^~~~~~~~~~~~~~~~~~~~~~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c: In function 'parse_flash_layout': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:428:7: warning: this statement may fall through [-Wimplicit-fallthrough=] if (column == 0 && p == col) { ^ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c:439:3: note: here default: ^~~~~~~ Change-Id: I3acefb406bfc8091ae5f908cfff1f6f31429603a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133252 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index 5cc1f0ab7e10..8325b565c529 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -49,12 +49,14 @@ /* RAW parttion (binary / bootloader) used Linux - reserved UUID */ #define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908" +#define DFU_DEV_UNDEFINED 0xFFFF + /* * unique partition guid (uuid) for partition named "rootfs" * on each MMC instance = SD Card or eMMC * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..." */ -const static efi_guid_t uuid_mmc[3] = { +static const efi_guid_t uuid_mmc[3] = { ROOTFS_MMC0_UUID, ROOTFS_MMC1_UUID, ROOTFS_MMC2_UUID @@ -92,7 +94,7 @@ char *stm32prog_get_error(struct stm32prog_data *data) u8 stm32prog_header_check(struct raw_header_s *raw_header, struct image_header_s *header) { - int i; + unsigned int i; header->present = 0; header->image_checksum = 0x0; @@ -264,7 +266,7 @@ static int parse_ip(struct stm32prog_data *data, char *p, struct stm32prog_part_t *part) { int result = 0; - int len = 0; + unsigned int len = 0; part->dev_id = 0; if (!strcmp(p, "none")) { @@ -434,7 +436,7 @@ static int parse_flash_layout(struct stm32prog_data *data, eof = true; continue; } - /* no break */ + /* fall through */ /* by default continue with the next character */ default: p++; @@ -772,7 +774,7 @@ static int treat_partition_list(struct stm32prog_data *data) struct stm32prog_part_t *part; for (j = 0; j < STM32PROG_MAX_DEV; j++) { - data->dev[j].dev_type = -1; + data->dev[j].dev_type = DFU_DEV_UNDEFINED; INIT_LIST_HEAD(&data->dev[j].part_list); } @@ -815,7 +817,7 @@ static int treat_partition_list(struct stm32prog_data *data) } } for (j = 0; j < STM32PROG_MAX_DEV; j++) { - if (data->dev[j].dev_type == -1) { + if (data->dev[j].dev_type == DFU_DEV_UNDEFINED) { /* new device found */ data->dev[j].dev_type = part->dev_type; data->dev[j].dev_id = part->dev_id; @@ -844,7 +846,8 @@ static int create_partitions(struct stm32prog_data *data) char buf[ENV_BUF_LEN]; char uuid[UUID_STR_LEN + 1]; unsigned char *uuid_bin; - int i, mmc_id; + unsigned int mmc_id; + int i; bool rootfs_found; struct stm32prog_part_t *part; @@ -1521,7 +1524,7 @@ static int part_delete(struct stm32prog_data *data, return ret; } -void stm32prog_devices_init(struct stm32prog_data *data) +static void stm32prog_devices_init(struct stm32prog_data *data) { int i; int ret; From edf333448f711fbd6c897a80dbb395d18d25b21a Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 16:06:35 +0200 Subject: [PATCH 143/244] cmd: pinmux: Fix warnings when compiling with W=1 This patch solves the following warnings: cmd/pinmux.c: In function 'do_dev': cmd/pinmux.c:26:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (ret) { ^ cmd/pinmux.c:30:2: note: here case 1: ^~~~ Change-Id: I5535cd16093a910caaf48055330b4a0f555f7bf4 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133253 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- cmd/pinmux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/pinmux.c b/cmd/pinmux.c index 6c8ec5164d3c..de909a163d8d 100644 --- a/cmd/pinmux.c +++ b/cmd/pinmux.c @@ -27,6 +27,7 @@ static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Can't get the pin-controller: %s!\n", name); return CMD_RET_FAILURE; } + /* fall through */ case 1: if (!currdev) { printf("Pin-controller device is not set!\n"); From 4aeb1151930849494142ee8eec02c5c078b12e53 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 16:16:05 +0200 Subject: [PATCH 144/244] gpio: stm32_gpio: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/gpio/stm32_gpio.c: In function 'stm32_offset_to_index': drivers/gpio/stm32_gpio.c:34:12: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (idx == offset) ^~ Change-Id: I7accf005d5493957e5e476f4404aaf4ea339bf20 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133254 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/gpio/stm32_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 104306833d80..4eea8aed770e 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -26,7 +26,7 @@ int stm32_offset_to_index(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); - int idx = 0; + unsigned int idx = 0; int i; for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { From 6977610cd4fb124f3bce71693e62eebf122cc91e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 17:05:36 +0200 Subject: [PATCH 145/244] i2c: stm32f7_i2c: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/i2c/stm32f7_i2c.c: In function 'stm32_i2c_compute_solutions': drivers/i2c/stm32f7_i2c.c:524:15: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (scldel < scldel_min) ^ drivers/i2c/stm32f7_i2c.c:530:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (((sdadel >= sdadel_min) && ^~ drivers/i2c/stm32f7_i2c.c:531:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] (sdadel <= sdadel_max)) && ^~ drivers/i2c/stm32f7_i2c.c: In function 'stm32_i2c_choose_solution': drivers/i2c/stm32f7_i2c.c:621:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (clk_error < clk_error_prev) { ^ Change-Id: I41b51a9fbf3cc7a0efb63d5c5b8f20acfe29c2f1 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133255 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/i2c/stm32f7_i2c.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 50c4fd0de23a..2b18735fea6b 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -519,13 +519,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, /* Compute possible values for PRESC, SCLDEL and SDADEL */ for (p = 0; p < STM32_PRESC_MAX; p++) { for (l = 0; l < STM32_SCLDEL_MAX; l++) { - u32 scldel = (l + 1) * (p + 1) * i2cclk; + int scldel = (l + 1) * (p + 1) * i2cclk; if (scldel < scldel_min) continue; for (a = 0; a < STM32_SDADEL_MAX; a++) { - u32 sdadel = (a * (p + 1) + 1) * i2cclk; + int sdadel = (a * (p + 1) + 1) * i2cclk; if (((sdadel >= sdadel_min) && (sdadel <= sdadel_max)) && @@ -613,10 +613,12 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= i2c_specs[setup->speed].h_min) && (i2cclk < tscl_h)) { - int clk_error = tscl - i2cbus; + u32 clk_error; - if (clk_error < 0) - clk_error = -clk_error; + if (tscl > i2cbus) + clk_error = tscl - i2cbus; + else + clk_error = i2cbus - tscl; if (clk_error < clk_error_prev) { clk_error_prev = clk_error; From 2c9ef7bba986c09cbb0d8c3b5cf6d309ac461033 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 17:07:04 +0200 Subject: [PATCH 146/244] cmd: stm32key: Fix warnings when compiling with W=1 This patch solves the following warnings: arch/arm/mach-stm32mp/cmd_stm32key.c:69:5: warning: no previous prototype for 'do_stm32key' [-Wmissing-prototypes] int do_stm32key(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ^~~~~~~~~~~ Change-Id: I7577ac44f3d833c3f91d8dbd204471b99a662966 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133256 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/cmd_stm32key.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32key.c b/arch/arm/mach-stm32mp/cmd_stm32key.c index 4245e6f4b1e9..6b1e4db7a85d 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32key.c +++ b/arch/arm/mach-stm32mp/cmd_stm32key.c @@ -66,7 +66,8 @@ static int confirm_prog(void) return 0; } -int do_stm32key(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_stm32key(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { u32 addr; const char *op = argc >= 2 ? argv[1] : NULL; From 7cde650ff7d44112fac4b970d8cb34dea2505679 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 17:20:08 +0200 Subject: [PATCH 147/244] adc: stm32-adc: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/adc/stm32-adc.c: In function 'stm32_adc_chan_of_init': drivers/adc/stm32-adc.c:176:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (num_channels > adc->cfg->max_channels) { ^ Change-Id: I4a240f32a090f9f59fa40cced146e52796f2edee Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133257 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/adc/stm32-adc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index e108062f2fee..029338e4af60 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -163,15 +163,16 @@ static int stm32_adc_chan_of_init(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); struct stm32_adc *adc = dev_get_priv(dev); u32 chans[STM32_ADC_CH_MAX]; - int i, num_channels, ret; + unsigned int i, num_channels; + int ret; /* Retrieve single ended channels listed in device tree */ - num_channels = dev_read_size(dev, "st,adc-channels"); - if (num_channels < 0) { - dev_err(dev, "can't get st,adc-channels: %d\n", num_channels); - return num_channels; + ret = dev_read_size(dev, "st,adc-channels"); + if (ret < 0) { + dev_err(dev, "can't get st,adc-channels: %d\n", ret); + return ret; } - num_channels /= sizeof(u32); + num_channels = ret / sizeof(u32); if (num_channels > adc->cfg->max_channels) { dev_err(dev, "too many st,adc-channels: %d\n", num_channels); From b4b56a70f9c45e74cbdf9be7c347df64085b665b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 17:38:42 +0200 Subject: [PATCH 148/244] stm32mp1: bsec: Fix warnings when compiling with W=1 This patch solves the following warnings: arch/arm/mach-stm32mp/bsec.c: In function 'stm32mp_bsec_read': arch/arm/mach-stm32mp/bsec.c:363:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (offset >= STM32_BSEC_OTP_OFFSET) { ^~ arch/arm/mach-stm32mp/bsec.c: In function 'stm32mp_bsec_write': arch/arm/mach-stm32mp/bsec.c:398:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (offset >= STM32_BSEC_OTP_OFFSET) { ^~ Change-Id: I89a4a52294a76c6e6262cdfcae7fdc66d879497a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133258 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/bsec.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 913dbef41ad5..452229786fee 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -359,12 +359,13 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset, bool shadow = true; int nb_otp = size / sizeof(u32); int otp; + unsigned int offs = offset; - if (offset >= STM32_BSEC_OTP_OFFSET) { - offset -= STM32_BSEC_OTP_OFFSET; + if (offs >= STM32_BSEC_OTP_OFFSET) { + offs -= STM32_BSEC_OTP_OFFSET; shadow = false; } - otp = offset / sizeof(u32); + otp = offs / sizeof(u32); if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { dev_err(dev, "wrong value for otp, max value : %i\n", @@ -394,12 +395,13 @@ static int stm32mp_bsec_write(struct udevice *dev, int offset, bool shadow = true; int nb_otp = size / sizeof(u32); int otp; + unsigned int offs = offset; - if (offset >= STM32_BSEC_OTP_OFFSET) { - offset -= STM32_BSEC_OTP_OFFSET; + if (offs >= STM32_BSEC_OTP_OFFSET) { + offs -= STM32_BSEC_OTP_OFFSET; shadow = false; } - otp = offset / sizeof(u32); + otp = offs / sizeof(u32); if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { dev_err(dev, "wrong value for otp, max value : %d\n", From 04ba3e7d9bfa31d315c501870e256ce7df5fc71f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 10 May 2019 17:42:14 +0200 Subject: [PATCH 149/244] adc: stm32: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/adc/stm32-adc-core.c: In function 'stm32h7_adc_clk_sel': drivers/adc/stm32-adc-core.c:87:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { ^ drivers/adc/stm32-adc-core.c:107:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { ^ Change-Id: I48fd8f027af85f1fe40f7ba603e8efe967106a81 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133259 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/adc/stm32-adc-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index a9aa143bfe7b..04b6a8a2f5b5 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -60,7 +60,8 @@ static int stm32h7_adc_clk_sel(struct udevice *dev, { u32 ckmode, presc; unsigned long rate; - int i, div; + unsigned int i; + int div; /* stm32h7 bus clock is common for all ADC instances (mandatory) */ if (!clk_valid(&common->bclk)) { From bbd9fa6e3f2e8fe5b226d4c2dc72a4054250aefa Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 09:39:37 +0200 Subject: [PATCH 150/244] stm32mp: stm32prog_serial: Fix warnings when compiling with W=1 This patch solves the following warnings: arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:32:20: warning: no previous prototype for 'stm32prog_get_entity' [-Wmissing-prototypes] struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) ^~~~~~~~~~~~~~~~~~~~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c: In function 'stm32prog_read': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:131:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (ret < buffer_size) { ^ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c: In function 'stm32prog_start': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:341:15: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (address != data->phase) { ^~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:348:44: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (address == DEFAULT_ADDRESS || address == data->phase) { ^~ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c: In function 'download_command': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:795:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (i = size; i < codesize; i++) ^ arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c: In function 'read_partition_command': arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c:888:12: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (; i < codesize; i++) ^ Change-Id: Iea77151b99f453551054679831f56dbc6482a56b Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133260 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- .../mach-stm32mp/cmd_stm32prog/stm32prog.h | 2 +- .../cmd_stm32prog/stm32prog_serial.c | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h index 51541bc79e9c..08d6e5e4c682 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h @@ -139,7 +139,7 @@ struct stm32prog_data { int full_update; /* command internal information */ - int phase; + unsigned int phase; u32 offset; char error[255]; struct stm32prog_part_t *cur_part; diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 7a3481754200..f9dee73a0060 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -29,7 +29,7 @@ const u8 cmd_id[] = { #define NB_CMD sizeof(cmd_id) /* DFU support for serial *********************************************/ -struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) +static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) { int alt_id; @@ -76,6 +76,7 @@ static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset, u8 *buffer, u32 buffer_size) { struct dfu_entity *dfu_entity; + u32 size; int ret; /* pr_debug("%s entry\n", __func__); */ @@ -128,12 +129,15 @@ static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset, ret, phase, offset); return ret; } - if (ret < buffer_size) { + + size = ret; + + if (size < buffer_size) { data->offset = 0; data->read_phase = PHASE_END; - memset(buffer + ret, 0, buffer_size - ret); + memset(buffer + size, 0, buffer_size - size); } else { - data->offset += ret; + data->offset += size; } /*pr_debug("%s exit ret=%d\n", __func__, ret);*/ return ret; @@ -629,7 +633,7 @@ static void download_command(struct stm32prog_data *data) u32 packet_number; u32 result = ACK_BYTE; u8 ret; - int i; + unsigned int i; bool error; int rcv; @@ -792,7 +796,7 @@ static void download_command(struct stm32prog_data *data) if (data->cursor <= BL_HEADER_SIZE) goto end; /* compute checksum on payload */ - for (i = size; i < codesize; i++) + for (i = (unsigned long)size; i < codesize; i++) data->checksum += data->buffer[i]; if (data->cursor > @@ -829,10 +833,10 @@ static void download_command(struct stm32prog_data *data) */ static void read_partition_command(struct stm32prog_data *data) { - u32 part_id, codesize, offset = 0, rcv_data; + u32 i, part_id, codesize, offset = 0, rcv_data; long size; u8 tmp_xor; - int i, res; + int res; u8 buffer[256]; part_id = stm32prog_serial_getc(); @@ -861,28 +865,29 @@ static void read_partition_command(struct stm32prog_data *data) } pr_debug("%s : %x\n", __func__, part_id); + rcv_data = 0; switch (part_id) { case PHASE_OTP: - res = 0; size = codesize; if (!stm32prog_otp_read(data, offset, buffer, &size)) - res = size; + rcv_data = size; break; case PHASE_PMIC: - res = 0; size = codesize; if (!stm32prog_pmic_read(data, offset, buffer, &size)) - res = size; + rcv_data = size; break; default: res = stm32prog_read(data, part_id, offset, buffer, codesize); + if (res > 0) + rcv_data = res; break; } - if (res > 0) { + if (rcv_data > 0) { stm32prog_serial_putc(ACK_BYTE); /*----------- Send data to the host -----------*/ - for (i = 0; i < res; i++) + for (i = 0; i < rcv_data; i++) stm32prog_serial_putc(buffer[i]); /*----------- Send filler to the host -----------*/ for (; i < codesize; i++) From 1d928b90e396ed887e04bdd233e5ae4dd58607fe Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 09:51:30 +0200 Subject: [PATCH 151/244] stm32mp: stm32prog_usb: Fix warnings when compiling with W=1 This patch solves the following warnings: arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c:166:6: warning: no previous prototype for 'dfu_initiated_callback' [-Wmissing-prototypes] void dfu_initiated_callback(struct dfu_entity *dfu) ^~~~~~~~~~~~~~~~~~~~~~ Change-Id: Id335a931cf24d1640fed50c32c266739113b3e3d Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133261 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- include/dfu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dfu.h b/include/dfu.h index 36304c7ffc70..64fdba3ec466 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -167,6 +167,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu); unsigned char *dfu_free_buf(void); unsigned long dfu_get_buf_size(void); bool dfu_usb_get_reset(void); +void dfu_initiated_callback(struct dfu_entity *dfu); int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num); int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num); From 79650e2b79002bd92b5c7ffd98c0f099135fd6cd Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 09:56:33 +0200 Subject: [PATCH 152/244] clk: clk_stm32mp1: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/clk/clk_stm32mp1.c: In function 'stm32mp1_clk_get_parent': drivers/clk/clk_stm32mp1.c:826:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (i = 0; i < ARRAY_SIZE(stm32mp1_clks); i++) ^ Change-Id: Ic6f34caa42db5674d6539bb314cbdabd5e0888ae Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133262 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/clk/clk_stm32mp1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index d55a3f135b30..4b4e00713e35 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -822,10 +822,11 @@ static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, const struct stm32mp1_clk_sel *sel = priv->data->sel; int i; int s, p; + unsigned int idx; - for (i = 0; i < ARRAY_SIZE(stm32mp1_clks); i++) - if (stm32mp1_clks[i][0] == id) - return stm32mp1_clks[i][1]; + for (idx = 0; idx < ARRAY_SIZE(stm32mp1_clks); idx++) + if (stm32mp1_clks[idx][0] == id) + return stm32mp1_clks[idx][1]; i = stm32mp1_clk_get_id(priv, id); if (i < 0) From 2a350181f0ffb0d358dcd2c183a234eb56ddef4c Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 11:34:50 +0200 Subject: [PATCH 153/244] serial: stm32: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/serial/serial_stm32.c: In function 'stm32_serial_probe': drivers/serial/serial_stm32.c:207:23: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if (plat->clock_rate < 0) { ^ Change-Id: I849299bd045f34dc1670008ca42ada2a220a38e5 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133263 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/serial/serial_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index b57db1d2ccb4..0bde839ca6f5 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -204,9 +204,9 @@ static int stm32_serial_probe(struct udevice *dev) } plat->clock_rate = clk_get_rate(&clk); - if (plat->clock_rate < 0) { + if (!plat->clock_rate) { clk_disable(&clk); - return plat->clock_rate; + return -EINVAL; }; _stm32_serial_init(plat->base, plat->uart_info); From 274fb39006bf0be90dd6700db4c0c6642cd8f61e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 11:42:02 +0200 Subject: [PATCH 154/244] spi: stm32: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/spi/stm32_spi.c: In function 'stm32_spi_write_txfifo': drivers/spi/stm32_spi.c:116:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (priv->tx_len >= sizeof(u32) && ^~ drivers/spi/stm32_spi.c:122:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] } else if (priv->tx_len >= sizeof(u16) && ^~ drivers/spi/stm32_spi.c: In function 'stm32_spi_read_rxfifo': drivers/spi/stm32_spi.c:150:21: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { ^~ drivers/spi/stm32_spi.c:156:21: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] (priv->rx_len >= sizeof(u16) || ^~ drivers/core/simple-bus.c:15:12: warning: no previous prototype for 'simple_bus_translate' [-Wmissing-prototypes] fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr) ^~~~~~~~~~~~~~~~~~~~ drivers/spi/stm32_spi.c: In function 'stm32_spi_set_speed': drivers/spi/stm32_spi.c:335:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] div > STM32_MBR_DIV_MAX) ^ drivers/spi/stm32_spi.c:344:19: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if ((mbrdiv - 1) < 0) ^ drivers/spi/stm32_spi.c: In function 'stm32_spi_probe': drivers/spi/stm32_spi.c:531:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { ^ Change-Id: Icbf0ea5e01fa4ff3b4aad4ce8534a4f714c0e741 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133264 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_spi.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index 34b217584dd1..75b6006b4540 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -99,8 +99,8 @@ struct stm32_spi_priv { unsigned int cur_bpw; unsigned int cur_hz; unsigned int cur_xferlen; /* current transfer length in bytes */ - int tx_len; /* number of data to be written in bytes */ - int rx_len; /* number of data to be read in bytes */ + unsigned int tx_len; /* number of data to be written in bytes */ + unsigned int rx_len; /* number of data to be read in bytes */ const void *tx_buf; /* data to be written, or NULL */ void *rx_buf; /* data to be read, or NULL */ u32 cur_mode; @@ -322,7 +322,8 @@ static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) static int stm32_spi_set_speed(struct udevice *bus, uint hz) { struct stm32_spi_priv *priv = dev_get_priv(bus); - u32 div, mbrdiv; + u32 mbrdiv; + long div; debug("%s: hz=%d\n", __func__, hz); @@ -341,7 +342,7 @@ static int stm32_spi_set_speed(struct udevice *bus, uint hz) else mbrdiv = fls(div) - 1; - if ((mbrdiv - 1) < 0) + if (!mbrdiv) return -EINVAL; clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, @@ -481,7 +482,7 @@ static int stm32_spi_probe(struct udevice *dev) struct stm32_spi_priv *priv = dev_get_priv(dev); unsigned long clk_rate; int ret; - int i; + unsigned int i; priv->base = dev_remap_addr(dev); if (!priv->base) From 497f679861bbdf75c92e7a4065fbfaaa4c1a2e68 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 11:48:25 +0200 Subject: [PATCH 155/244] power: regulator: stm32: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/power/regulator/stm32-vrefbuf.c: In function 'stm32_vrefbuf_set_value': drivers/power/regulator/stm32-vrefbuf.c:80:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (uV == stm32_vrefbuf_voltages[i]) { ^~ Change-Id: Icfa1d7dfa5ba391019b6b93db9084079243b6d95 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133265 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/power/regulator/stm32-vrefbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c index 0ad6833ed041..645528e84e86 100644 --- a/drivers/power/regulator/stm32-vrefbuf.c +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -30,7 +30,7 @@ struct stm32_vrefbuf { struct udevice *vdda_supply; }; -static const unsigned int stm32_vrefbuf_voltages[] = { +static const int stm32_vrefbuf_voltages[] = { /* Matches resp. VRS = 000b, 001b, 010b, 011b */ 2500000, 2048000, 1800000, 1500000, }; From 422680882f51c1d14d22901a793ff01640025482 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 11:57:36 +0200 Subject: [PATCH 156/244] mailbox: stm32-ipcc: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/mailbox/stm32-ipcc.c: In function 'stm32_ipcc_probe': drivers/mailbox/stm32-ipcc.c:130:42: warning: pointer targets in passing argument 3 of 'dev_read_prop' differ in signedness [-Wpointer-sign] cell = dev_read_prop(dev, "st,proc_id", &len); ^ Change-Id: I0e63720a32f401506269b33dc0928d4554e9704a Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133266 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/mailbox/stm32-ipcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index dfcea9153800..4ebec150b50e 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -127,7 +127,7 @@ static int stm32_ipcc_probe(struct udevice *dev) /* proc_id */ cell = dev_read_prop(dev, "st,proc_id", &len); - if (len < sizeof(fdt32_t)) { + if (sizeof(fdt32_t) - len > 0) { dev_dbg(dev, "Missing st,proc_id\n"); return -EINVAL; } From 790af47bcafaca16886e05953dabb491be0c30b9 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 12:00:17 +0200 Subject: [PATCH 157/244] misc: stm32_fuse: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/misc/stm32mp_fuse.c:20:5: warning: no previous prototype for 'fuse_read' [-Wmissing-prototypes] int fuse_read(u32 bank, u32 word, u32 *val) ^~~~~~~~~ CC cmd/sf.o drivers/misc/stm32mp_fuse.c:52:5: warning: no previous prototype for 'fuse_prog' [-Wmissing-prototypes] int fuse_prog(u32 bank, u32 word, u32 val) ^~~~~~~~~ drivers/misc/stm32mp_fuse.c:83:5: warning: no previous prototype for 'fuse_sense' [-Wmissing-prototypes] int fuse_sense(u32 bank, u32 word, u32 *val) ^~~~~~~~~~ drivers/misc/stm32mp_fuse.c:114:5: warning: no previous prototype for 'fuse_override' [-Wmissing-prototypes] int fuse_override(u32 bank, u32 word, u32 val) ^~~~~~~~~~~~~ Change-Id: Ife3950c72e40dfeb6ab541676c73a4a82814945e Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133267 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/misc/stm32mp_fuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 842871fb033e..e199abee2201 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include From e18553fc1a42bb41d4a7026aea59afda4e2c7bd7 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 13:35:59 +0200 Subject: [PATCH 158/244] phy: phy-stm32-usbphyc: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/phy/phy-stm32-usbphyc.c:63:6: warning: no previous prototype for 'stm32_usbphyc_get_pll_params' [-Wmissing-prototypes] void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change-Id: I7ad629180f5dcff3faa6d5926bb7b3d076465e65 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133268 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/phy/phy-stm32-usbphyc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 22937d89860d..b6d3144e412c 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -60,7 +60,8 @@ struct stm32_usbphyc { } phys[MAX_PHYS]; }; -void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) +static void stm32_usbphyc_get_pll_params(u32 clk_rate, + struct pll_params *pll_params) { unsigned long long fvco, ndiv, frac; From 59db4e04f3d39bf7498c649c287620f0964a9760 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 13:37:56 +0200 Subject: [PATCH 159/244] ram: stm32mp1_ddr: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/ram/stm32mp1/stm32mp1_ddr.c:642:6: warning: no previous prototype for 'mode_register_write' [-Wmissing-prototypes] void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) ^~~~~~~~~~~~~~~~~~~ Change-Id: I41c70b685514b783fdbf56fd9d464c5fab7b374c Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133269 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index b0b73c298e17..8cde44028615 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -639,7 +639,7 @@ static void wait_operating_mode(struct ddr_info *priv, int mode) } /* Mode Register Writes (MRW or MRS) */ -void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) +static void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) { u32 mrctrl0; From 86305e1d6041817cf76ce4da6e2ae7406e2cfb62 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 13:40:36 +0200 Subject: [PATCH 160/244] ram: stm32mp1_ram: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/ram/stm32mp1/stm32mp1_ram.c: In function 'stm32mp1_ddr_clk_enable': drivers/ram/stm32mp1/stm32mp1_ram.c:33:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) { ^ drivers/ram/stm32mp1/stm32mp1_ram.c: In function 'stm32mp1_ddr_setup': drivers/ram/stm32mp1/stm32mp1_ram.c:98:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (idx = 0; idx < ARRAY_SIZE(param); idx++) { ^ Change-Id: I4cebe75cf58c9f460ebfc42f4fe5124164de23d5 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133270 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/ram/stm32mp1/stm32mp1_ram.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index 8d62c2943736..e0ab47575dfc 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -28,7 +28,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) unsigned long ddr_clk; struct clk clk; int ret; - int idx; + unsigned int idx; for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) { ret = clk_get_by_name(priv->dev, clkname[idx], &clk); @@ -60,7 +60,8 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) { struct ddr_info *priv = dev_get_priv(dev); - int ret, idx; + int ret; + unsigned int idx; struct clk axidcg; struct stm32mp1_ddr_config config; From cf4c209e781f488f516eb54b77695df8bf370e1d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 13:45:39 +0200 Subject: [PATCH 161/244] pinctrl: pinctrl_stm32: Fix warnings when compiling with W=1 drivers/pinctrl/pinctrl_stm32.c:139:13: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if (*idx < 0) ^ drivers/pinctrl/pinctrl_stm32.c: At top level: drivers/pinctrl/pinctrl_stm32.c:218:5: warning: no previous prototype for 'stm32_pinctrl_probe' [-Wmissing-prototypes] int stm32_pinctrl_probe(struct udevice *dev) ^~~~~~~~~~~~~~~~~~~ This patch solves the following warnings: Change-Id: Ibd0c9a5e680377bbb065dea706c2ff4daa1d01cf Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133271 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrice CHOTARD --- drivers/pinctrl/pinctrl_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 042425e48569..e74139e65c03 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -136,7 +136,7 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, */ *idx = stm32_offset_to_index(gpio_bank->gpio_dev, selector - pin_count); - if (*idx < 0) + if (IS_ERR_VALUE(*idx)) return NULL; return gpio_bank->gpio_dev; @@ -215,7 +215,7 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, #endif -int stm32_pinctrl_probe(struct udevice *dev) +static int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); int ret; From 3e098b9cbab314b73e1c3471d21cf668e613fd7d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 13:48:59 +0200 Subject: [PATCH 162/244] remoteproc: stm32_copro: Fix warnings when compiling with W=1 This patch solves the following warnings: drivers/remoteproc/stm32_copro.c: In function 'st_of_to_priv': drivers/remoteproc/stm32_copro.c:60:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (len < 3 * sizeof(fdt32_t)) { ^ drivers/remoteproc/stm32_copro.c:77:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if (len < 3 * sizeof(fdt32_t)) { ^ drivers/remoteproc/stm32_copro.c: In function 'stm32_copro_da_to_pa': drivers/remoteproc/stm32_copro.c:156:9: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] if (da >= 0 && da < STM32_RETRAM_SIZE) ^~ Change-Id: I7ab177325f121fdf59efdf4979ec7c4eb2e78dcb Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133272 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/remoteproc/stm32_copro.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 44230ff4a6bc..0a8b90017a78 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -57,7 +57,7 @@ static int st_of_to_priv(struct udevice *dev, priv->hold_boot_regmap = regmap; cell = dev_read_prop(dev, "st,syscfg-holdboot", &len); - if (len < 3 * sizeof(fdt32_t)) { + if ((3 * sizeof(fdt32_t) - len) > 0) { dev_dbg(dev, "holdboot offset and mask not available\n"); return -EINVAL; } @@ -74,7 +74,7 @@ static int st_of_to_priv(struct udevice *dev, } cell = dev_read_prop(dev, "st,syscfg-tz", &len); - if (len < 3 * sizeof(fdt32_t)) { + if (3 * sizeof(fdt32_t) - len > 0) { dev_dbg(dev, "tz offset and mask not available\n"); return -EINVAL; } @@ -153,7 +153,7 @@ static ulong stm32_copro_da_to_pa(struct udevice *dev, ulong da) /* to update with address translate by DT range */ /* CM4 boot at address 0x0 = RETRAM alias, not available for CA7 load */ - if (da >= 0 && da < STM32_RETRAM_SIZE) + if (da < STM32_RETRAM_SIZE) return (da + STM32_RETRAM_BASE); return da; From 996b3080a6055f55f1017a2f609d7e7e73b4b9d8 Mon Sep 17 00:00:00 2001 From: Nicolas Le Bayon Date: Mon, 20 May 2019 18:11:33 +0200 Subject: [PATCH 163/244] ARM: dts: stm32mp1: DDR config v1.45 Update DDR configuration with the latest update: - Change DQSGE to 1 for DDR3, to cure missing DQS preamble. Change-Id: Ibf609264ca2d1ab93c7f5bd5f949b4eb352fae94 Signed-off-by: Nicolas Le Bayon Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133883 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi | 4 ++-- arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 4 ++-- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi | 4 ++-- arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi index e22b3fea67fa..43edbfe30c70 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binF.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.44" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 1x4Gb 533MHz v1.45" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 @@ -89,7 +89,7 @@ #define DDR_PTR2 0x042DA068 #define DDR_ACIOCR 0x10400812 #define DDR_DXCCR 0x00000C40 -#define DDR_DSGCR 0xF200001F +#define DDR_DSGCR 0xF200011F #define DDR_DCR 0x0000000B #define DDR_DTPR0 0x36D477D0 #define DDR_DTPR1 0x098B00D8 diff --git a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi index dc30360b0a41..11e8f2bef69f 100644 --- a/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.44" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.45" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 @@ -89,7 +89,7 @@ #define DDR_PTR2 0x042DA068 #define DDR_ACIOCR 0x10400812 #define DDR_DXCCR 0x00000C40 -#define DDR_DSGCR 0xF200001F +#define DDR_DSGCR 0xF200011F #define DDR_DCR 0x0000000B #define DDR_DTPR0 0x38D488D0 #define DDR_DTPR1 0x098B00D8 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi index 99dbc6e2bd85..e0644a39e2e3 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binF.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.44" +#define DDR_MEM_NAME "DDR3-1066/777 bin F 2x4Gb 533MHz v1.45" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 @@ -89,7 +89,7 @@ #define DDR_PTR2 0x042DA068 #define DDR_ACIOCR 0x10400812 #define DDR_DXCCR 0x00000C40 -#define DDR_DSGCR 0xF200001F +#define DDR_DSGCR 0xF200011F #define DDR_DCR 0x0000000B #define DDR_DTPR0 0x36D477D0 #define DDR_DTPR1 0x098B00D8 diff --git a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi index 772ef7d03a9c..4b70b605541b 100644 --- a/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +++ b/arch/arm/dts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -16,7 +16,7 @@ * address mapping : RBC * Tc > + 85C : N */ -#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.44" +#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.45" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 @@ -89,7 +89,7 @@ #define DDR_PTR2 0x042DA068 #define DDR_ACIOCR 0x10400812 #define DDR_DXCCR 0x00000C40 -#define DDR_DSGCR 0xF200001F +#define DDR_DSGCR 0xF200011F #define DDR_DCR 0x0000000B #define DDR_DTPR0 0x38D488D0 #define DDR_DTPR1 0x098B00D8 From 2b1399e98c331c0d7c556b23a63a0b62998a1d5e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 21 May 2019 10:39:57 +0200 Subject: [PATCH 164/244] stm32mp1: support of error led on ed1/ev1 board Create a function led_error_blink and add node in device tree. Signed-off-by: Patrick Delaunay Change-Id: I282911f43d565511221106198bde5101b4ec659b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133929 --- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 8 +++++ board/st/stm32mp1/stm32mp1.c | 46 ++++++++++++++++-------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 546129efd5a3..517de819169a 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -16,11 +16,19 @@ config { u-boot,boot-led = "heartbeat"; + u-boot,error-led = "error"; st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; }; led { + red { + label = "error"; + gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + status = "okay"; + }; + blue { default-state = "on"; }; diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 7a739ac68030..270543128d04 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -641,12 +642,40 @@ static int setup_led(enum led_state_t cmd) } #endif /* CONFIG_LED */ +static void __maybe_unused led_error_blink(u32 nb_blink) +{ +#ifdef CONFIG_LED + int ret; + struct udevice *led; + u32 i; +#endif + + if (!nb_blink) + return; + +#ifdef CONFIG_LED + ret = get_led(&led, "u-boot,error-led"); + if (!ret) { + /* make u-boot,error-led blinking */ + /* if U32_MAX and 125ms interval, for 17.02 years */ + for (i = 0; i < 2 * nb_blink; i++) { + led_set_state(led, LEDST_TOGGLE); + mdelay(125); + WATCHDOG_RESET(); + } + } +#endif + + /* infinite: the boot process must be stopped */ + if (nb_blink == U32_MAX) + hang(); +} + #ifdef CONFIG_ADC 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; @@ -772,20 +801,7 @@ static int board_check_usb_power(void) pr_err("****************************************************\n\n"); } - ret = get_led(&led, "u-boot,error-led"); - if (ret) { - /* in unattached case, the boot process must be stopped */ - if (nb_blink == U32_MAX) - hang(); - return ret; - } - - /* make u-boot,error-led blinking */ - for (i = 0; i < nb_blink * 2; i++) { - led_set_state(led, LEDST_TOGGLE); - mdelay(125); - } - led_set_state(led, LEDST_ON); + led_error_blink(nb_blink); return 0; } From 2294b26f4af6c3821c708ba94fc59a182fe3efac Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 22 May 2019 09:37:26 +0200 Subject: [PATCH 165/244] stm32mp1: use gd to store frequency information Use existing gd structure to store frequency information which can be used in drivers or arch without new request. Change-Id: Ibe32fe00b89f2ad5b345a46d4bd80d41c1c0cf02 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134026 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/clk/clk_stm32mp1.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 4b4e00713e35..eb7068c05cbe 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -2066,22 +2066,22 @@ static int stm32mp1_clk_probe(struct udevice *dev) stm32mp1_clk_dump(priv); #endif + gd->cpu_clk = stm32mp1_clk_get(priv, _CK_MPU); + gd->bus_clk = stm32mp1_clk_get(priv, _ACLK); + /* DDRPHYC father */ + gd->mem_clk = stm32mp1_clk_get(priv, _PLL2_R); #if defined(CONFIG_DISPLAY_CPUINFO) if (gd->flags & GD_FLG_RELOC) { char buf[32]; printf("Clocks:\n"); - printf("- MPU : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _CK_MPU))); + printf("- MPU : %s MHz\n", strmhz(buf, gd->cpu_clk)); printf("- MCU : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_MCU))); - printf("- AXI : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _ACLK))); + printf("- AXI : %s MHz\n", strmhz(buf, gd->bus_clk)); printf("- PER : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_PER))); - /* DDRPHYC father */ - printf("- DDR : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _PLL2_R))); + printf("- DDR : %s MHz\n", strmhz(buf, gd->mem_clk)); } #endif /* CONFIG_DISPLAY_CPUINFO */ #endif From d4e92b29a4d0a429e4815b349e3eef271fd8498f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 22 May 2019 13:58:07 +0200 Subject: [PATCH 166/244] stm32mp1: check the boot-source to disable bootdelay Allows to avoid to wait 2 second in U-Boot before to start STM32CubeProgrammer command. Signed-off-by: Patrick Delaunay Change-Id: I5bec02eb9f688cb5a2dc9025d024be01e09a02f5 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134063 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/stm32mp1.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 270543128d04..9b3517519f37 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -175,6 +175,7 @@ static __maybe_unused bool board_is_dk2(void) int board_late_init(void) { + char *boot_device; #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG const void *fdt_compat; int fdt_compat_len; @@ -188,6 +189,10 @@ int board_late_init(void) env_set("board_name", fdt_compat + 3); } #endif + /* Check the boot-source to disable bootdelay */ + boot_device = env_get("boot_device"); + if (!strcmp(boot_device, "serial") || !strcmp(boot_device, "usb")) + env_set("bootdelay", "0"); return 0; } From 5abed36ebdc8c99da5292800120992e5bb2b63c0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 24 May 2019 17:46:41 +0200 Subject: [PATCH 167/244] cli: deactivate some feature for SPL Signed-off-by: Patrick Delaunay Change-Id: I31e7667c70e7f238976b867cfa7fb620623f357e Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134443 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- common/cli_readline.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/cli_readline.c b/common/cli_readline.c index 99b631720e17..a6dc79b701ac 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -13,6 +13,12 @@ #include #include +#ifdef CONFIG_SPL_BUILD +#undef CONFIG_CMDLINE_EDITING +#undef CONFIG_AUTO_COMPLETE +#undef CONFIG_SHOW_ACTIVITY +#endif + DECLARE_GLOBAL_DATA_PTR; static const char erase_seq[] = "\b \b"; /* erase sequence */ From 34e08a48c5cad94eb4ffd26a94cfe754e8df6790 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 5 Jun 2019 09:51:28 +0200 Subject: [PATCH 168/244] stm32mp: cosmetic: cleanup arch Alignment with up-stream. Signed-off-by: Patrick Delaunay Change-Id: I6eaa767c31c8c8125a9593e4cbb154520a4a16d6 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135092 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/Kconfig | 8 +++----- arch/arm/mach-stm32mp/Makefile | 4 ++-- arch/arm/mach-stm32mp/bsec.c | 2 +- arch/arm/mach-stm32mp/cmd_poweroff.c | 2 +- arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h | 2 +- arch/arm/mach-stm32mp/psci.c | 5 ++++- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 58950a07427d..9545b69bbd82 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -43,12 +43,12 @@ config TARGET_STM32MP1 imply SYSRESET_SYSCON if !STM32MP1_TRUSTED help target STMicroelectronics SOC STM32MP1 family - STM32MP153 or STM32MP151 + STM32MP157, STM32MP153 or STM32MP151 STMicroelectronics MPU with core ARMv7 - dual core A7 for STM32MP153, monocore for STM32MP151 + dual core A7 for STM32MP157/3, monocore for STM32MP151 config STM32MP1_RESET_HALT_WORKAROUND - bool "workaround for reset halt deubg on stm32mp15x" + bool "workaround for reset halt debug on stm32mp15x" depends on TARGET_STM32MP1 default y help @@ -59,7 +59,6 @@ config STM32MP1_RESET_HALT_WORKAROUND it can be removed when using the Soc revision that fixes the limitation. - config STM32MP1_TRUSTED bool "Support trusted boot with TF-A" default y if !SPL @@ -136,7 +135,6 @@ config NR_DRAM_BANKS config BOOTSTAGE_STASH_ADDR default 0xC3000000 - if BOOTCOUNT_LIMIT config SYS_BOOTCOUNT_SINGLEWORD default y diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index b09a2cade59c..11109ccc10a2 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -14,9 +14,9 @@ else obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o -obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-y += bsec.o -obj-y += cmd_poweroff.o +obj-$(CONFIG_SYSRESET) += cmd_poweroff.o +obj-$(CONFIG_ARMV7_PSCI) += psci.o endif obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 452229786fee..52563780e07e 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ diff --git a/arch/arm/mach-stm32mp/cmd_poweroff.c b/arch/arm/mach-stm32mp/cmd_poweroff.c index a6fdc79c79f9..f54dd1daf230 100644 --- a/arch/arm/mach-stm32mp/cmd_poweroff.c +++ b/arch/arm/mach-stm32mp/cmd_poweroff.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include diff --git a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h index 538958f6864d..9ee7fb711450 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32mp1_smc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #ifndef __STM32MP1_SMC_H__ diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 5809298dbb45..708a699f65c5 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -134,7 +134,10 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, if (readl(TAMP_BACKUP_MAGIC_NUMBER)) writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); - /* ROM code need a SGI0 after core reset is ready when magic = 0 */ + /* + * ROM code need a first SGI0 after core reset + * core is ready when magic is set to 0 in ROM code + */ while (readl(TAMP_BACKUP_MAGIC_NUMBER)) stm32mp_raise_sgi0(cpu); From b01e1d633a73de0e19b72a04f5f46f038e7063da Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 5 Jun 2019 09:59:25 +0200 Subject: [PATCH 169/244] arm: stm32mp1: deploy spl in root folder Deploy u-boot-spl.stm32 binary in u-boot root folder like the rest of the boards. This makes it more streamlined when building in Yocto, Buildroot etc.. - continue to generate all SPL files in spl sub-directory - copy in root folder the needed file for user (YOCTO, buildroot): u-boot-spl.stm32 [backport of 1b35c90836e5660a37ed33581f06ebb0b36b01ad] [backport of 29e1a64c06da729418629ca1df8ed11bb34f71b9] Signed-off-by: Sean Nyekjaer Signed-off-by: Patrick Delaunay Change-Id: I76533a6287e38f0d91f92c368e656894ce7fea4e Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135093 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/config.mk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/config.mk b/arch/arm/mach-stm32mp/config.mk index bd8944a6c798..d9d39fd7a08d 100644 --- a/arch/arm/mach-stm32mp/config.mk +++ b/arch/arm/mach-stm32mp/config.mk @@ -7,7 +7,7 @@ ifndef CONFIG_SPL ALL-y += u-boot.stm32 else ifdef CONFIG_SPL_BUILD -ALL-y += spl/u-boot-spl.stm32 +ALL-y += u-boot-spl.stm32 endif endif @@ -25,3 +25,6 @@ spl/u-boot-spl.stm32: MKIMAGEOUTPUT = spl/u-boot-spl.stm32.log spl/u-boot-spl.stm32: spl/u-boot-spl.bin FORCE $(call if_changed,mkimage) + +u-boot-spl.stm32 : spl/u-boot-spl.stm32 + $(call if_changed,copy) From e3da87025c5f2295113ddb34009db4d470b5f784 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 5 Jun 2019 10:08:09 +0200 Subject: [PATCH 170/244] stm32mp1: cosmetic: cleanup board Alignment with up-stream. Signed-off-by: Patrick Delaunay Change-Id: Iad9168589683bfb40ca356b5a744fcedc9701baf Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135094 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/MAINTAINERS | 5 +- board/st/stm32mp1/README | 23 ++- board/st/stm32mp1/board.c | 4 +- board/st/stm32mp1/stm32mp1.c | 301 ++++++++++++++++------------------ 4 files changed, 155 insertions(+), 178 deletions(-) diff --git a/board/st/stm32mp1/MAINTAINERS b/board/st/stm32mp1/MAINTAINERS index 6c9710a1cf22..3bf4c21b602a 100644 --- a/board/st/stm32mp1/MAINTAINERS +++ b/board/st/stm32mp1/MAINTAINERS @@ -1,11 +1,10 @@ STM32MP1 BOARD M: Patrick Delaunay -M: Christophe Kerello L: uboot-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers) S: Maintained F: arch/arm/dts/stm32mp157* F: board/st/stm32mp1 -F: configs/stm32mp15_trusted_defconfig -F: configs/stm32mp15_optee_defconfig F: configs/stm32mp15_basic_defconfig +F: configs/stm32mp15_optee_defconfig +F: configs/stm32mp15_trusted_defconfig F: include/configs/stm32mp1.h diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index c3365c675f5d..b710602634d1 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -176,7 +176,6 @@ You can select the boot mode, ----------------------------------- 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 @@ -209,14 +208,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 | - ----- ------- -------- ---------------- - | 1 | fsbl1 | 256 KiB | TF-A or SPL | - | 2 | fsbl2 | 256 KiB | TF-A or SPL | - | 3 | ssbl | enought | U-Boot | - | * | - | - | Boot/Rootfs | - ----- ------- --------- --------------- + ----- ------- --------- -------------- + | 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 | + ----- ------- --------- -------------- (*) add bootable partition for extlinux.conf following Generic Distribution @@ -240,7 +239,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 @@ -255,7 +254,7 @@ for example: with gpt table with 128 entries # 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. +To boot from SDCard, select BootPinMode = 1 0 1 and reset. 8. Prepare eMMC =============== @@ -264,7 +263,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 : diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index b6e528878e79..c3d832f58489 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -47,7 +47,7 @@ int board_ddr_power_init(enum ddr_type ddr_type) ret = uclass_get_device_by_driver(UCLASS_PMIC, DM_GET_DRIVER(pmic_stpmic1), &dev); if (ret) - /* No PMIC on power discrete board */ + /* No PMIC on board */ return 0; switch (ddr_type) { @@ -149,7 +149,7 @@ int board_ddr_power_init(enum ddr_type ddr_type) mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - /* Enable VDD_DDR22 =BUCK2 */ + /* Enable VDD_DDR2 =BUCK2 */ ret = pmic_clrsetbits(dev, STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA); diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 9b3517519f37..d3b2ea6eb048 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -165,52 +165,6 @@ static void board_key_check(void) #endif } -static __maybe_unused bool board_is_dk2(void) -{ - if (of_machine_is_compatible("st,stm32mp157c-dk2")) - return true; - - return false; -} - -int board_late_init(void) -{ - char *boot_device; -#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 - /* Check the boot-source to disable bootdelay */ - boot_device = env_get("boot_device"); - if (!strcmp(boot_device, "serial") || !strcmp(boot_device, "usb")) - env_set("bootdelay", "0"); - - return 0; -} - -#ifdef CONFIG_STM32_SDMMC2 -/* this is a weak define that we are overriding */ -static int board_mmc_init(void) -{ - return 0; -} -#endif - -#ifdef CONFIG_STM32_QSPI -static void board_qspi_init(void) -{ -} -#endif /* CONFIG_STM32_QSPI */ - #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) /* @@ -443,113 +397,6 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) } #endif /* CONFIG_USB_GADGET */ -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); - debug("SYSCFG: init @0x%p\n", 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); - debug("[0x%x] SYSCFG.icnr = 0x%08x (LTDC and GPU)\n", - (u32)syscfg + SYSCFG_ICNR, readl(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); - debug("[0x%x] SYSCFG.bootr = 0x%08x\n", - (u32)syscfg + SYSCFG_BOOTR, readl(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); - - ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(stm32mp_pwr_pmic), - &dev); - - /* get VDD = vdd-supply */ - ret = device_get_supply_regulator(dev, "vdd-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 - debug("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n", - (u32)syscfg + SYSCFG_IOCTRLSETR, - readl(syscfg + SYSCFG_IOCTRLSETR)); - - /* 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); - - debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n", - (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR)); -#endif -} - /* board interface eth init */ /* this is a weak define that we are overriding */ int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, @@ -812,6 +659,112 @@ static int board_check_usb_power(void) } #endif /* CONFIG_ADC */ +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); + debug("SYSCFG: init @0x%p\n", 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); + debug("[0x%x] SYSCFG.icnr = 0x%08x (LTDC and GPU)\n", + (u32)syscfg + SYSCFG_ICNR, readl(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); + debug("[0x%x] SYSCFG.bootr = 0x%08x\n", + (u32)syscfg + SYSCFG_BOOTR, readl(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); + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(stm32mp_pwr_pmic), + &dev); + + /* get VDD = vdd-supply */ + ret = device_get_supply_regulator(dev, "vdd-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 + debug("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n", + (u32)syscfg + SYSCFG_IOCTRLSETR, + readl(syscfg + SYSCFG_IOCTRLSETR)); + + /* 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); + + debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n", + (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR)); +#endif +} + #ifdef CONFIG_DM_REGULATOR /* Fix to make I2C1 usable on DK2 for touchscreen usage in kernel */ static int dk2_i2c1_fix(void) @@ -919,6 +872,14 @@ const char *env_ext4_get_dev_part(void) } #endif +static __maybe_unused bool board_is_dk2(void) +{ + if (of_machine_is_compatible("st,stm32mp157c-dk2")) + return true; + + return false; +} + /* board dependent setup after realloc */ int board_init(void) { @@ -952,14 +913,6 @@ int board_init(void) sysconf_init(); -#ifdef CONFIG_STM32_SDMMC2 - board_mmc_init(); -#endif /* CONFIG_STM32_SDMMC2 */ - -#ifdef CONFIG_STM32_QSPI - board_qspi_init(); -#endif /* CONFIG_STM32_QSPI */ - #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) board_usbotg_init(); #endif @@ -967,6 +920,32 @@ int board_init(void) return 0; } +int board_late_init(void) +{ + + char *boot_device; +#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 + + /* Check the boot-source to disable bootdelay */ + boot_device = env_get("boot_device"); + if (!strcmp(boot_device, "serial") || !strcmp(boot_device, "usb")) + env_set("bootdelay", "0"); + + return 0; +} + void board_quiesce_devices(void) { #ifdef CONFIG_LED From 6dccaf25ab01e8fb6c51f8604169031d3b85d2f7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 5 Jun 2019 11:38:34 +0200 Subject: [PATCH 171/244] ram: stm32mp1: cleanup driver Alignment with upstream: - remove pwr (not used) - introduce CONFIG_STM32MP1_DDR_TESTS - remove stm32mp1_tuning.h for prototypes only used in tuning.c - move many tuning buffers in stack to reduce memory footprint Signed-off-by: Patrick Delaunay Change-Id: Ief77856ca65e83d9946b07ff012a709fb99c8629 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135095 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/Kconfig | 10 +- drivers/ram/stm32mp1/Makefile | 3 +- drivers/ram/stm32mp1/stm32mp1_ddr.c | 71 ++--- drivers/ram/stm32mp1/stm32mp1_ddr.h | 2 - drivers/ram/stm32mp1/stm32mp1_interactive.c | 12 +- drivers/ram/stm32mp1/stm32mp1_ram.c | 9 +- drivers/ram/stm32mp1/stm32mp1_tuning.c | 276 +++++++++++--------- drivers/ram/stm32mp1/stm32mp1_tuning.h | 54 ---- 8 files changed, 221 insertions(+), 216 deletions(-) delete mode 100644 drivers/ram/stm32mp1/stm32mp1_tuning.h diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig index 761de09af56c..2fd8c7b7e3b8 100644 --- a/drivers/ram/stm32mp1/Kconfig +++ b/drivers/ram/stm32mp1/Kconfig @@ -30,9 +30,17 @@ config STM32MP1_DDR_INTERACTIVE_FORCE useful when SPL is loaded in sysram directly by programmer +config STM32MP1_DDR_TESTS + bool "STM32MP1 DDR driver : tests support" + depends on STM32MP1_DDR_INTERACTIVE + default y + help + activate test support for interactive support in + STM32MP1 DDR controller driver: command test + config STM32MP1_DDR_TUNING bool "STM32MP1 DDR driver : support of tuning" - depends on SPL && STM32MP1_DDR_INTERACTIVE + depends on STM32MP1_DDR_INTERACTIVE default y help activate tuning command in STM32MP1 DDR interactive mode diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile index bc292d16d1d4..e1e9135603a0 100644 --- a/drivers/ram/stm32mp1/Makefile +++ b/drivers/ram/stm32mp1/Makefile @@ -6,7 +6,8 @@ obj-y += stm32mp1_ram.o obj-y += stm32mp1_ddr.o -obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o stm32mp1_tests.o +obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o +obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o ifneq ($(DDR_INTERACTIVE),) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index 8cde44028615..f6484da5ce20 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -192,6 +192,7 @@ static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = { /************************************************************** * DYNAMIC REGISTERS: only used for debug purpose (read/modify) **************************************************************/ +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(stat), DDR_REG_DYN(init0), @@ -222,6 +223,8 @@ static const struct reg_desc ddrphy_dyn[] = { #define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn) +#endif + /***************************************************************** * REGISTERS ARRAY: used to parse device tree and interactive mode *****************************************************************/ @@ -233,11 +236,13 @@ enum reg_type { REGPHY_REG, REGPHY_TIMING, REGPHY_CAL, +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE /* dynamic registers => managed in driver or not changed, * can be dumped in interactive mode */ REG_DYN, REGPHY_DYN, +#endif REG_TYPE_NB }; @@ -271,10 +276,12 @@ const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE}, [REGPHY_CAL] = { "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE}, +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE [REG_DYN] = { "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE}, [REGPHY_DYN] = { "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE}, +#endif }; const char *base_name[] = { @@ -315,37 +322,6 @@ static void set_reg(const struct ddr_info *priv, } } -static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) -{ - u32 pgsr; - int ret; - - ret = readl_poll_timeout(&phy->pgsr, pgsr, - pgsr & (DDRPHYC_PGSR_IDONE | - DDRPHYC_PGSR_DTERR | - DDRPHYC_PGSR_DTIERR | - DDRPHYC_PGSR_DFTERR | - DDRPHYC_PGSR_RVERR | - DDRPHYC_PGSR_RVEIRR), - 1000000); - debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n", - (u32)&phy->pgsr, pgsr, ret); -} - -void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) -{ - pir |= DDRPHYC_PIR_INIT; - writel(pir, &phy->pir); - debug("[0x%08x] pir = 0x%08x -> 0x%08x\n", - (u32)&phy->pir, pir, readl(&phy->pir)); - - /* need to wait 10 configuration clock before start polling */ - udelay(10); - - /* Wait DRAM initialization and Gate Training Evaluation complete */ - ddrphy_idone_wait(phy); -} - #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc) { @@ -444,7 +420,7 @@ void stm32mp1_edit_reg(const struct ddr_info *priv, printf("%s not found\n", name); return; } - if (strict_strtoul(string, 16, &value) < 0) { + if (strict_strtoul(string, 16, &value) < 0) { printf("invalid value %s\n", string); return; } @@ -814,6 +790,37 @@ static void ddr3_dll_off(struct ddr_info *priv) debug("%s: exit\n", __func__); } +static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) +{ + u32 pgsr; + int ret; + + ret = readl_poll_timeout(&phy->pgsr, pgsr, + pgsr & (DDRPHYC_PGSR_IDONE | + DDRPHYC_PGSR_DTERR | + DDRPHYC_PGSR_DTIERR | + DDRPHYC_PGSR_DFTERR | + DDRPHYC_PGSR_RVERR | + DDRPHYC_PGSR_RVEIRR), + 1000000); + debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n", + (u32)&phy->pgsr, pgsr, ret); +} + +void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) +{ + pir |= DDRPHYC_PIR_INIT; + writel(pir, &phy->pir); + debug("[0x%08x] pir = 0x%08x -> 0x%08x\n", + (u32)&phy->pir, pir, readl(&phy->pir)); + + /* need to wait 10 configuration clock before start polling */ + udelay(10); + + /* Wait DRAM initialization and Gate Training Evaluation complete */ + ddrphy_idone_wait(phy); +} + void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) { start_sw_done(ctl); diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h index 90b4a4b95b80..52b748f3ca21 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h @@ -26,7 +26,6 @@ struct stm32mp1_ddrphy; * @ctl: DDR controleur base address * @clk: DDR clock * @phy: DDR PHY base address - * @pwr: pwr base address * @rcc: rcc base address */ struct ddr_info { @@ -35,7 +34,6 @@ struct ddr_info { struct clk clk; struct stm32mp1_ddrctl *ctl; struct stm32mp1_ddrphy *phy; - void *pwr; u32 rcc; }; diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index a5a24a2b1118..8df6a39ca57d 100644 --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include @@ -52,7 +52,9 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc) [DDR_CMD_STEP] = "step", [DDR_CMD_NEXT] = "next", [DDR_CMD_GO] = "go", +#ifdef CONFIG_STM32MP1_DDR_TESTS [DDR_CMD_TEST] = "test", +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING [DDR_CMD_TUNING] = "tuning", #endif @@ -69,7 +71,9 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc) [DDR_CMD_STEP] = { 0, 1 }, [DDR_CMD_NEXT] = { 0, 0 }, [DDR_CMD_GO] = { 0, 0 }, +#ifdef CONFIG_STM32MP1_DDR_TESTS [DDR_CMD_TEST] = { 0, 255 }, +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING [DDR_CMD_TUNING] = { 0, 255 }, #endif @@ -114,7 +118,9 @@ static void stm32mp1_do_usage(void) "next goes to the next step\n" "go continues the U-Boot SPL execution\n" "reset reboots machine\n" +#ifdef CONFIG_STM32MP1_DDR_TESTS "test [help] | [...] lists (with help) or executes test \n" +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING "tuning [help] | [...] lists (with help) or execute tuning \n" #endif @@ -300,6 +306,7 @@ static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step, return step; } +#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING) static const char * const s_result[] = { [TEST_PASSED] = "Pass", [TEST_FAILED] = "Failed", @@ -354,6 +361,7 @@ static void stm32mp1_ddr_subcmd(struct ddr_info *priv, end: printf("Result: %s [%s]\n", s_result[result], string); } +#endif bool stm32mp1_ddr_interactive(void *priv, enum stm32mp1_ddr_interact_step step, @@ -450,11 +458,13 @@ bool stm32mp1_ddr_interactive(void *priv, next_step = stm32mp1_do_step(step, argc, argv); break; +#ifdef CONFIG_STM32MP1_DDR_TESTS case DDR_CMD_TEST: if (!stm32mp1_check_step(step, STEP_DDR_READY)) continue; stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb); break; +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING case DDR_CMD_TUNING: diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index e0ab47575dfc..1da57ce89850 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -12,8 +12,6 @@ #include #include "stm32mp1_ddr.h" -DECLARE_GLOBAL_DATA_PTR; - static const char *const clkname[] = { "ddrc1", "ddrc2", @@ -52,7 +50,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) if (ddr_clk > (mem_speed * 100)) { pr_err("DDR expected freq %d kHz, current is %d kHz\n", mem_speed, (u32)(ddrphy_clk / 1000)); - return -1; + return -EINVAL; } return 0; } @@ -156,11 +154,6 @@ static int stm32mp1_ddr_probe(struct udevice *dev) priv->ctl = regmap_get_range(map, 0); priv->phy = regmap_get_range(map, 1); - map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR); - if (IS_ERR(map)) - return PTR_ERR(map); - priv->pwr = regmap_get_range(map, 0); - priv->rcc = STM32_RCC_BASE; priv->info.base = STM32_DDR_BASE; diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 0778921879b6..b928ac2d5166 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #if defined(DEBUG) @@ -17,30 +17,46 @@ #include "stm32mp1_ddr_regs.h" #include "stm32mp1_ddr.h" #include "stm32mp1_tests.h" -#include "stm32mp1_tuning.h" -/* TODO make enum for nominal_delay_m_1.... (for all arrays) */ - -/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */ -const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12}; - -/* New DQ delay value (index). These values are set during Deskew algo */ -u8 deskew_delay[NUM_BYTES][8]; - -/*If there is still skew on a bit, mark this bit. */ -u8 deskew_non_converge[NUM_BYTES][8]; - -/*Stores the DQS trim values (PHASE index, unit index) */ -u8 eye_training_val[NUM_BYTES][2]; +#define MAX_DQS_PHASE_IDX _144deg +#define MAX_DQS_UNIT_IDX 7 +#define MAX_GSL_IDX 5 +#define MAX_GPS_IDX 3 + +/* Number of bytes used in this SW. ( min 1--> max 4). */ +#define NUM_BYTES 4 + +enum dqs_phase_enum { + _36deg = 0, + _54deg = 1, + _72deg = 2, + _90deg = 3, + _108deg = 4, + _126deg = 5, + _144deg = 6 +}; -/* stores the log of pass/fail */ -u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1]; +/* BIST Result struct */ +struct BIST_result { + /* Overall test result: + * 0 Fail (any bit failed) , + * 1 Success (All bits success) + */ + bool test_result; + /* 1: true, all fail / 0: False, not all bits fail */ + bool all_bits_fail; + bool bit_i_test_result[8]; /* 0 fail / 1 success */ +}; -/* stores the dqs gate values (gsl index, gps index) */ -u8 dqs_gate_values[NUM_BYTES][2]; +/* a struct that defines tuning parameters of a byte. */ +struct tuning_position { + u8 phase; /* DQS phase */ + u8 unit; /* DQS unit delay */ + u32 bits_delay; /* Bits deskew in this byte */ +}; -static void itm_soft_reset(struct stm32mp1_ddrphy *phy); -static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte); +/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */ +const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12}; static u8 BIST_error_max = 1; static u32 BIST_seed = 0x1234ABCD; @@ -64,10 +80,16 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl) return nb_bytes; } +static void itm_soft_reset(struct stm32mp1_ddrphy *phy) +{ + stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); +} + +#ifdef UNUSED /* Read DQS PHASE delay register and provides the index of the retrieved * value in dx_dll_phase array. */ -u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDLLCR(phy, byte); u32 sdphase = 0; @@ -123,11 +145,13 @@ u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) return index; } +#endif +#ifdef UNUSED /* Read DQS unit delay register and provides the index of the retrieved value * We are assuming that the delay on DQS and DQSN are equal */ -u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); u32 index; @@ -141,12 +165,13 @@ u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) return index; } +#endif /* Read DQ unit delay register and provides the retrieved value for DQS * We are assuming that we have the same delay when clocking * by DQS and when clocking by DQSN */ -u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) +static u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) { u32 index; u32 addr = DXNDQTR(phy, byte); @@ -163,29 +188,33 @@ u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) return index; } +#ifdef UNUSED /* read r0dgsl value */ -u8 get_r0dgsl_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 get_r0dgsl_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGSL_MASK) >> DDRPHYC_DXNDQSTR_R0DGSL_SHIFT; } +#endif +#ifdef UNUSED /*read r0dgsl value */ -u8 get_r0dgps_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 get_r0dgps_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGPS_MASK) >> DDRPHYC_DXNDQSTR_R0DGPS_SHIFT; } +#endif /* Sets the DQS phase delay for a byte lane. *phase delay is specified by giving the index of the desired delay * in the dx_dll_phase array. */ -void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) +static void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) { u8 sdphase_val = 0; @@ -200,8 +229,8 @@ void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) * unit delay is specified by giving the index of the desired delay * for dgsdly and dqsndly (same value). */ -void DQS_unit_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 unit_dly_idx) +static void DQS_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 unit_dly_idx) { /* Write the same value in DXNDQSTR.DQSDLY and DXNDQSTR.DQSNDLY */ clrsetbits_le32(DXNDQSTR(phy, byte), @@ -219,9 +248,9 @@ void DQS_unit_delay(struct stm32mp1_ddrphy *phy, /* Sets the DQ unit delay for a bit line in particular byte lane. * unit delay is specified by giving the desired delay */ -void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 bit, - u8 dq_delay_index) +static void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 bit, + u8 dq_delay_index) { u8 dq_bit_delay_val = dq_delay_index | (dq_delay_index << 2); @@ -232,16 +261,16 @@ void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, dq_bit_delay_val << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit)); } -void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 r0dgsl_idx) +static void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgsl_idx) { clrsetbits_le32(DXNDQSTR(phy, byte), DDRPHYC_DXNDQSTR_R0DGSL_MASK, r0dgsl_idx << DDRPHYC_DXNDQSTR_R0DGSL_SHIFT); } -void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 r0dgps_idx) +static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgps_idx) { clrsetbits_le32(DXNDQSTR(phy, byte), DDRPHYC_DXNDQSTR_R0DGPS_MASK, @@ -249,7 +278,7 @@ void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, } /* Basic BIST configuration for data lane tests. */ -void config_BIST(struct stm32mp1_ddrphy *phy) +static void config_BIST(struct stm32mp1_ddrphy *phy) { /* Selects the SDRAM bank address to be used during BIST. */ u32 bbank = 0; @@ -309,7 +338,7 @@ void config_BIST(struct stm32mp1_ddrphy *phy) } /* Select the Byte lane to be tested by BIST. */ -void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) +static void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) { clrsetbits_le32(&phy->bistrr, DDRPHYC_BISTRR_BDXSEL_MASK, @@ -320,8 +349,8 @@ void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) } /* Perform BIST Write_Read test on a byte lane and return test result. */ -void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, - struct BIST_result *bist) +static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, + struct BIST_result *bist) { bool result = true; /* BIST_SUCCESS */ u32 cnt = 0; @@ -405,8 +434,9 @@ void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, #endif } +#ifdef UNUSED /* Init the Write_Read result struct. */ -void init_result_struct(struct BIST_result *result) +static void init_result_struct(struct BIST_result *result) { u8 i = 0; @@ -422,13 +452,16 @@ void init_result_struct(struct BIST_result *result) for (i = 0; i < 8; i++) result->bit_i_test_result[i] = true; } +#endif /* After running the deskew algo, this function applies the new DQ delays * by reading them from the array "deskew_delay"and writing in PHY registers. * The bits that are not deskewed parfectly (too much skew on them, * or data eye very wide) are marked in the array deskew_non_converge. */ -void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte) +static void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte, + u8 deskew_delay[NUM_BYTES][8], + u8 deskew_non_converge[NUM_BYTES][8]) { u8 bit_i; u8 index; @@ -464,6 +497,10 @@ void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte) static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, struct stm32mp1_ddrphy *phy, char *string) { + /* New DQ delay value (index), set during Deskew algo */ + u8 deskew_delay[NUM_BYTES][8]; + /*If there is still skew on a bit, mark this bit. */ + u8 deskew_non_converge[NUM_BYTES][8]; struct BIST_result result; s8 dqs_unit_delay_index = 0; u8 datx8 = 0; @@ -869,7 +906,8 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, pr_debug("The Deskew algorithm can't converge, there is too much margin in your design. Good job!\n"); } - apply_deskew_results(phy, datx8); + apply_deskew_results(phy, datx8, deskew_delay, + deskew_non_converge); /* Restore nominal value for DQS delay */ DQS_phase_delay(phy, datx8, 3); DQS_unit_delay(phy, datx8, 3); @@ -903,6 +941,8 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, struct stm32mp1_ddrphy *phy, char *string) { + /*Stores the DQS trim values (PHASE index, unit index) */ + u8 eye_training_val[NUM_BYTES][2]; u8 byte = 0; struct BIST_result result; s8 dqs_unit_delay_index = 0; @@ -1189,7 +1229,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, return TEST_PASSED; } -void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) +static void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) { u8 i = 0; @@ -1211,79 +1251,14 @@ void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) readl(DXNDQTR(phy, byte))); } -static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, - struct stm32mp1_ddrphy *phy, - char *string) -{ - u8 byte, gsl_idx, gps_idx = 0; - struct BIST_result result; - u8 success = 0; - u8 nb_bytes = get_nb_bytes(ctl); - - memset(dqs_gating, 0x0, sizeof(dqs_gating)); - - /*disable dqs drift compensation*/ - clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); - /*disable all bytes*/ - /* disable automatic power down of dll and ios when disabling a byte - * (to avoid having to add programming and delay - * for a dll re-lock when later re-enabling a disabled byte lane) - */ - clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); - - /* disable all data bytes */ - clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); - - /* config the bist block */ - config_BIST(phy); - - for (byte = 0; byte < nb_bytes; byte++) { - if (ctrlc()) { - sprintf(string, "interrupted at byte %d/%d", - byte + 1, nb_bytes); - return TEST_FAILED; - } - /* enable byte x (dxngcr, bit dxen) */ - setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); - - /* select the byte lane for comparison of read data */ - BIST_datx8_sel(phy, byte); - for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { - for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { - if (ctrlc()) { - sprintf(string, - "interrupted at byte %d/%d", - byte + 1, nb_bytes); - return TEST_FAILED; - } - /* write cfg to dxndqstr */ - set_r0dgsl_delay(phy, byte, gsl_idx); - set_r0dgps_delay(phy, byte, gps_idx); - - BIST_test(phy, byte, &result); - success = result.test_result; - if (success) - dqs_gating[byte][gsl_idx][gps_idx] = 1; - itm_soft_reset(phy); - } - } - set_midpoint_read_dqs_gating(phy, byte); - /* dummy reads */ - readl(0xc0000000); - readl(0xc0000000); - } - - /* re-enable drift compensation */ - /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */ - return TEST_PASSED; -} - /* analyse the dgs gating log table, and determine the midpoint.*/ -static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte, + u8 dqs_gating[NUM_BYTES] + [MAX_GSL_IDX + 1] + [MAX_GPS_IDX + 1]) { + /* stores the dqs gate values (gsl index, gps index) */ + u8 dqs_gate_values[NUM_BYTES][2]; u8 gsl_idx, gps_idx = 0; u8 left_bound_idx[2] = {0, 0}; u8 right_bound_idx[2] = {0, 0}; @@ -1389,9 +1364,76 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte) return !(intermittent || (left_bound_found && right_bound_found)); } -static void itm_soft_reset(struct stm32mp1_ddrphy *phy) +static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string) { - stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); + /* stores the log of pass/fail */ + u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1]; + u8 byte, gsl_idx, gps_idx = 0; + struct BIST_result result; + u8 success = 0; + u8 nb_bytes = get_nb_bytes(ctl); + + memset(dqs_gating, 0x0, sizeof(dqs_gating)); + + /*disable dqs drift compensation*/ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); + /*disable all bytes*/ + /* disable automatic power down of dll and ios when disabling a byte + * (to avoid having to add programming and delay + * for a dll re-lock when later re-enabling a disabled byte lane) + */ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); + + /* disable all data bytes */ + clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + /* config the bist block */ + config_BIST(phy); + + for (byte = 0; byte < nb_bytes; byte++) { + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* enable byte x (dxngcr, bit dxen) */ + setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); + + /* select the byte lane for comparison of read data */ + BIST_datx8_sel(phy, byte); + for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { + for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { + if (ctrlc()) { + sprintf(string, + "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* write cfg to dxndqstr */ + set_r0dgsl_delay(phy, byte, gsl_idx); + set_r0dgps_delay(phy, byte, gps_idx); + + BIST_test(phy, byte, &result); + success = result.test_result; + if (success) + dqs_gating[byte][gsl_idx][gps_idx] = 1; + itm_soft_reset(phy); + } + } + set_midpoint_read_dqs_gating(phy, byte, dqs_gating); + /* dummy reads */ + readl(0xc0000000); + readl(0xc0000000); + } + + /* re-enable drift compensation */ + /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */ + return TEST_PASSED; } /**************************************************************** diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.h b/drivers/ram/stm32mp1/stm32mp1_tuning.h deleted file mode 100644 index 964a05011c91..000000000000 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ -/* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ - -#ifndef _RAM_STM32MP1_TUNING_H_ -#define _RAM_STM32MP1_TUNING_H_ - -#define MAX_DQS_PHASE_IDX _144deg -#define MAX_DQS_UNIT_IDX 7 -#define MAX_GSL_IDX 5 -#define MAX_GPS_IDX 3 - -/* Number of bytes used in this SW. ( min 1--> max 4). */ -#define NUM_BYTES 4 - -enum dqs_phase_enum { - _36deg = 0, - _54deg = 1, - _72deg = 2, - _90deg = 3, - _108deg = 4, - _126deg = 5, - _144deg = 6 -}; - -/* BIST Result struct */ -struct BIST_result { - /* Overall test result: - * 0 Fail (any bit failed) , - * 1 Success (All bits success) - */ - bool test_result; - /* 1: true, all fail / 0: False, not all bits fail */ - bool all_bits_fail; - bool bit_i_test_result[8]; /* 0 fail / 1 success */ -}; - -u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte); -u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte); -u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit); - -void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte); -void init_result_struct(struct BIST_result *result); -void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, - struct BIST_result *result); - -/* a struct that defines tuning parameters of a byte. */ -struct tuning_position { - u8 phase; /* DQS phase */ - u8 unit; /* DQS unit delay */ - u32 bits_delay; /* Bits deskew in this byte */ -}; -#endif From a9e7ff977e509b2a5b46cde335aaab6c7d995edd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 Jun 2019 13:00:33 +0200 Subject: [PATCH 172/244] stm32mp1: display information when U-Boot is compiled for OP-TEE The added trace allows to detected error only with trace; For example boot with OP-TEE & U-Boot for trusted mode = FREEZE during relocation because end of Memory is reserved by OP-TEE. Signed-off-by: Patrick Delaunay Change-Id: I541efe80a8f049391cd0496dd2b5194a6dc22473 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135334 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/stm32mp1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index d3b2ea6eb048..da015ed5f1d7 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -86,7 +86,9 @@ int checkboard(void) const char *fdt_compat; int fdt_compat_len; - if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED)) + if (IS_ENABLED(CONFIG_STM32MP1_OPTEE)) + mode = "op-tee"; + else if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED)) mode = "trusted"; else mode = "basic"; From 42ffa538db566fcdc582867ff7c350e10e855b63 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 10 Jun 2019 18:03:40 +0200 Subject: [PATCH 173/244] pinctrl: stmfx: update pinconf settings Alignment with kernel driver. According to the following tab (coming from STMFX datasheet), updates have to done in stmfx_pinctrl_conf_set function: -"type" has to be set when "bias" is configured as "pull-up or pull-down" -PIN_CONFIG_DRIVE_PUSH_PULL should only be used when gpio is configured as output. There is so no need to check direction. DIR | TYPE | PUPD | MFX GPIO configuration ----|------|------|--------------------------------------------------- 1 | 1 | 1 | OUTPUT open drain with internal pull-up resistor ----|------|------|--------------------------------------------------- 1 | 1 | 0 | OUTPUT open drain with internal pull-down resistor ----|------|------|--------------------------------------------------- 1 | 0 | 0/1 | OUTPUT push pull no pull ----|------|------|--------------------------------------------------- 0 | 1 | 1 | INPUT with internal pull-up resistor ----|------|------|--------------------------------------------------- 0 | 1 | 0 | INPUT with internal pull-down resistor ----|------|------|--------------------------------------------------- 0 | 0 | 1 | INPUT floating ----|------|------|--------------------------------------------------- 0 | 0 | 0 | analog (GPIO not used, default setting) Signed-off-by: Patrick Delaunay Change-Id: Ic5087db15247c15f883ab012e11d8fb4d0673695 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135469 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/pinctrl/pinctrl-stmfx.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 275fdbff771d..8bb215fcd851 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -231,23 +231,23 @@ static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, switch (param) { case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_DRIVE_PUSH_PULL: + ret = stmfx_pinctrl_set_type(dev, pin, 0); + break; case PIN_CONFIG_BIAS_PULL_DOWN: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; ret = stmfx_pinctrl_set_pupd(dev, pin, 0); break; case PIN_CONFIG_BIAS_PULL_UP: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; 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); + ret = stmfx_pinctrl_set_type(dev, pin, 1); break; case PIN_CONFIG_OUTPUT: ret = stmfx_gpio_direction_output(plat->gpio, pin, arg); From 61082e30c2f335bfb2742c059c468a968d91b91c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 10 Jun 2019 19:03:11 +0200 Subject: [PATCH 174/244] stm32mp1: cleanup fdt support Signed-off-by: Patrick Delaunay Change-Id: I908b51649d35edc647c8fbe561d83a827df92b90 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135481 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/Makefile | 2 +- arch/arm/mach-stm32mp/cpu.c | 50 +------------ .../arm/mach-stm32mp/{stm32-etzpc.c => fdt.c} | 75 ++++++++++++------- arch/arm/mach-stm32mp/include/mach/stm32.h | 4 - .../arm/mach-stm32mp/include/mach/sys_proto.h | 9 +++ 5 files changed, 61 insertions(+), 79 deletions(-) rename arch/arm/mach-stm32mp/{stm32-etzpc.c => fdt.c} (79%) diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 11109ccc10a2..9158a20e3f54 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -20,4 +20,4 @@ obj-$(CONFIG_ARMV7_PSCI) += psci.o endif obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o -obj-$(CONFIG_STM32_ETZPC) += stm32-etzpc.o +obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 2c058f57e24e..1ce042d6ab7e 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -16,7 +16,6 @@ #include #include #include -#include /* RCC register */ #define RCC_TZCR (STM32_RCC_BASE + 0x00) @@ -84,11 +83,6 @@ #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 - DECLARE_GLOBAL_DATA_PTR; #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) @@ -285,7 +279,7 @@ u32 get_cpu_type(void) } /* Get Package options from OTP */ -static u32 get_cpu_package(void) +u32 get_cpu_package(void) { return get_otp(BSEC_OTP_PKG, PKG_SHIFT, PKG_MASK); } @@ -590,45 +584,3 @@ int arch_misc_init(void) return 0; } - -/* - * This function is called right before the kernel is booted. "blob" is the - * device tree that will be passed to the kernel. - */ -int ft_system_setup(void *blob, bd_t *bd) -{ - int ret = 0; - u32 pkg; - -#if CONFIG_STM32_ETZPC - ret = stm32_fdt_fixup_etzpc(blob); - if (ret) - return ret; -#endif - - switch (get_cpu_package()) { - case PKG_AA_LBGA448: - pkg = STM32MP157CAA; - break; - case PKG_AB_LBGA354: - pkg = STM32MP157CAB; - break; - case PKG_AC_TFBGA361: - pkg = STM32MP157CAC; - break; - case PKG_AD_TFBGA257: - pkg = STM32MP157CAD; - break; - default: - pkg = 0; - break; - } - if (pkg) { - do_fixup_by_compat_u32(blob, "st,stm32mp157-pinctrl", - "st,package", pkg, false); - do_fixup_by_compat_u32(blob, "st,stm32mp157-z-pinctrl", - "st,package", pkg, false); - } - - return ret; -} diff --git a/arch/arm/mach-stm32mp/stm32-etzpc.c b/arch/arm/mach-stm32mp/fdt.c similarity index 79% rename from arch/arm/mach-stm32mp/stm32-etzpc.c rename to arch/arm/mach-stm32mp/fdt.c index ea6dcca52fdd..259b99a055ac 100644 --- a/arch/arm/mach-stm32mp/stm32-etzpc.c +++ b/arch/arm/mach-stm32mp/fdt.c @@ -1,21 +1,18 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include #include #include -#include +#include +#include #include -#define ETZPC_DECPROT(n) (0x10 + 4 * (n)) +#define ETZPC_DECPROT(n) (STM32_ETZPC_BASE + 0x10 + 4 * (n)) #define ETZPC_DECPROT_NB 6 -#define ETZPC_IP_VER 0x3F4 - -#define IP_VER_STM32MP1 0x00000020 - #define DECPROT_MASK 0x03 #define NB_PROT_PER_REG 0x10 #define DECPROT_NB_BITS 2 @@ -147,32 +144,18 @@ static bool fdt_disable_subnode_by_address(void *fdt, int offset, u32 addr) return false; } -int stm32_fdt_fixup_etzpc(void *fdt) +static int stm32_fdt_fixup_etzpc(void *fdt) { - void *base; - u32 version; const u32 *array; int array_size, i; int soc_node, offset, shift; u32 addr, status, decprot[ETZPC_DECPROT_NB]; - base = syscon_get_first_range(STM32MP_SYSCON_ETZPC); - if (IS_ERR(base)) - return PTR_ERR(base); - - version = readl(base + ETZPC_IP_VER); - - switch (version) { - case IP_VER_STM32MP1: - array = stm32mp1_ip_addr; - array_size = ARRAY_SIZE(stm32mp1_ip_addr); - break; - default: - return 0; - } + array = stm32mp1_ip_addr; + array_size = ARRAY_SIZE(stm32mp1_ip_addr); for (i = 0; i < ETZPC_DECPROT_NB; i++) - decprot[i] = readl(base + ETZPC_DECPROT(i)); + decprot[i] = readl(ETZPC_DECPROT(i)); soc_node = fdt_path_offset(fdt, "/soc"); if (soc_node < 0) @@ -197,3 +180,45 @@ int stm32_fdt_fixup_etzpc(void *fdt) return 0; } + +/* + * This function is called right before the kernel is booted. "blob" is the + * device tree that will be passed to the kernel. + */ +int ft_system_setup(void *blob, bd_t *bd) +{ + int ret = 0; + u32 pkg; + + if (CONFIG_IS_ENABLED(STM32_ETZPC)) { + ret = stm32_fdt_fixup_etzpc(blob); + if (ret) + return ret; + } + + switch (get_cpu_package()) { + case PKG_AA_LBGA448: + pkg = STM32MP157CAA; + break; + case PKG_AB_LBGA354: + pkg = STM32MP157CAB; + break; + case PKG_AC_TFBGA361: + pkg = STM32MP157CAC; + break; + case PKG_AD_TFBGA257: + pkg = STM32MP157CAD; + break; + default: + pkg = 0; + break; + } + if (pkg) { + do_fixup_by_compat_u32(blob, "st,stm32mp157-pinctrl", + "st,package", pkg, false); + do_fixup_by_compat_u32(blob, "st,stm32mp157-z-pinctrl", + "st,package", pkg, false); + } + + return ret; +} diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index b52dc76c4392..c364c9858c84 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -125,9 +125,5 @@ enum forced_boot_mode { #define BSEC_OTP_BOARD 59 -#if CONFIG_STM32_ETZPC -int stm32_fdt_fixup_etzpc(void *fdt); -#endif - #endif /* __ASSEMBLY__*/ #endif /* _MACH_STM32_H_ */ diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 7ff9067a2348..871324b1ab2a 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -19,6 +19,15 @@ u32 get_cpu_type(void); /* return CPU_REV constants */ u32 get_cpu_rev(void); + +/* Get Package options from OTP */ +u32 get_cpu_package(void); + +#define PKG_AA_LBGA448 4 +#define PKG_AB_LBGA354 3 +#define PKG_AC_TFBGA361 2 +#define PKG_AD_TFBGA257 1 + /* return boot mode */ u32 get_bootmode(void); /* start IWDG watchdog */ From 95be59a62b82aea537f54e4804b143125af960b5 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 10 Jun 2019 20:04:35 +0200 Subject: [PATCH 175/244] stm32mp1: syscon: remove etzpc support Support for ETZPC is removed as this device is not present in Linux kernel device tree. Signed-off-by: Patrick Delaunay Change-Id: I12f90587e2b7b9307cbbbdd7201c1857844af2bd Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135482 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157-u-boot.dtsi | 6 ------ arch/arm/mach-stm32mp/include/mach/stm32.h | 1 - arch/arm/mach-stm32mp/syscon.c | 1 - 3 files changed, 8 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 7af6cdfae656..98cf1aa6575a 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -37,12 +37,6 @@ soc { u-boot,dm-pre-reloc; - etzpc: etzpc@5C007000 { - compatible = "st,stm32mp1-etzpc"; - reg = <0x5C007000 0x400>; - status = "okay"; - }; - stgen: stgen@5C008000 { compatible = "st,stm32-stgen"; reg = <0x5C008000 0x1000>; diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index c364c9858c84..5283e902a15a 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -44,7 +44,6 @@ /* enumerated used to identify the SYSCON driver instance */ enum { STM32MP_SYSCON_UNKNOWN, - 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 242f8340abb4..e10c42eb136a 100644 --- a/arch/arm/mach-stm32mp/syscon.c +++ b/arch/arm/mach-stm32mp/syscon.c @@ -9,7 +9,6 @@ #include static const struct udevice_id stm32mp_syscon_ids[] = { - { .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", From a717a8c96306242959879c0bcf0803072fd02197 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 Jun 2019 19:50:52 +0200 Subject: [PATCH 176/244] console: update silent tag after env load Update the "silent" property with the variable "silent" get from saved environment, it solves the issue when: - CONFIG_SILENT_CONSOLE is activated - silent is not defined in default environment - silent is requested in saved environment with: > env set silent 1; env save On next reboot the console is not disabled as expected after relocation and the environment load from flash (the callback is not called when the INSERT is requested in the created hash table) Signed-off-by: Patrick Delaunay Change-Id: I099a878524b6225164ae5fa1624402c21939a781 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135378 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- common/console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/console.c b/common/console.c index 9a94f3219224..04cad30c9e7d 100644 --- a/common/console.c +++ b/common/console.c @@ -786,6 +786,9 @@ int console_init_r(void) int iomux_err = 0; #endif + /* update silent for env loaded from flash (initr_env) */ + console_update_silent(); + /* set default handlers at first */ gd->jt->getc = serial_getc; gd->jt->tstc = serial_tstc; @@ -877,6 +880,7 @@ int console_init_r(void) struct list_head *pos; struct stdio_dev *dev; + /* update silent for env loaded from flash (initr_env) */ console_update_silent(); #ifdef CONFIG_SPLASH_SCREEN From 173c86b9806997482bec14898af21b3184778d2e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 Jun 2019 19:55:46 +0200 Subject: [PATCH 177/244] console: execute flush on uart when silent is removed Avoid to flush buffer when silent console is activated as the console can be reactivate later, after relocation, when the env will be updated with the saved one. Solve issue (missing beginning of U-Boot trace) when: - CONFIG_SILENT_CONSOLE is activated - silent=1 is defined in default environment (CONFIG_EXTRA_ENV_SETTINGS) - silent is removed in saved environment with: > env delete silent; env save Only functional when PRE_CONSOLE_BUFFER is activated. Signed-off-by: Patrick Delaunay Change-Id: Ib96067d6b0c74e86223e7ef829f25552cfe1b655 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135379 Reviewed-by: CITOOLS Reviewed-by: Patrice CHOTARD --- common/console.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/common/console.c b/common/console.c index 04cad30c9e7d..d0f2793370dc 100644 --- a/common/console.c +++ b/common/console.c @@ -463,6 +463,11 @@ static void print_pre_console_buffer(int flushpoint) char buf_out[CONFIG_PRE_CON_BUF_SZ + 1]; char *buf_in; +#ifdef CONFIG_SILENT_CONSOLE + if (gd->flags & GD_FLG_SILENT) + return; +#endif + buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ; @@ -511,8 +516,11 @@ void putc(const char c) membuff_putbyte(&gd->console_out, c); #endif #ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) + if (gd->flags & GD_FLG_SILENT) { + if (!(gd->flags & GD_FLG_DEVINIT)) + pre_console_putc(c); return; + } #endif #ifdef CONFIG_DISABLE_CONSOLE @@ -552,8 +560,11 @@ void puts(const char *s) membuff_put(&gd->console_out, s, strlen(s)); #endif #ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) + if (gd->flags & GD_FLG_SILENT) { + if (!(gd->flags & GD_FLG_DEVINIT)) + pre_console_puts(s); return; + } #endif #ifdef CONFIG_DISABLE_CONSOLE @@ -713,14 +724,22 @@ int console_assign(int file, const char *devname) return -1; } -static void console_update_silent(void) +/* return true if the 'silent' flag is removed */ +static bool console_update_silent(void) { #ifdef CONFIG_SILENT_CONSOLE - if (env_get("silent") != NULL) + if (env_get("silent") != NULL) { gd->flags |= GD_FLG_SILENT; - else + } else { + unsigned long flags = gd->flags; + gd->flags &= ~GD_FLG_SILENT; + + return !!(flags & GD_FLG_SILENT); + } #endif + + return false; } int console_announce_r(void) @@ -785,9 +804,13 @@ int console_init_r(void) #if CONFIG_IS_ENABLED(CONSOLE_MUX) int iomux_err = 0; #endif + int flushpoint; /* update silent for env loaded from flash (initr_env) */ - console_update_silent(); + if (console_update_silent()) + flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; + else + flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; /* set default handlers at first */ gd->jt->getc = serial_getc; @@ -865,7 +888,7 @@ int console_init_r(void) if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) return 0; #endif - print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL); + print_pre_console_buffer(flushpoint); return 0; } @@ -879,9 +902,13 @@ int console_init_r(void) struct list_head *list = stdio_get_list(); struct list_head *pos; struct stdio_dev *dev; + int flushpoint; /* update silent for env loaded from flash (initr_env) */ - console_update_silent(); + if (console_update_silent()) + flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; + else + flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; #ifdef CONFIG_SPLASH_SCREEN /* @@ -944,7 +971,7 @@ int console_init_r(void) if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) return 0; #endif - print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL); + print_pre_console_buffer(flushpoint); return 0; } From c77afe905df405b5b8b46cdfdd4053f1f08f01ef Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 Jun 2019 19:30:15 +0200 Subject: [PATCH 178/244] stm32mp1: activate CONFIG_SILENT_CONSOLE Allow to disable console with environment variable 'silent': > env set silent 1; env save Signed-off-by: Patrick Delaunay Change-Id: Ic9bdb0af617a9d61c03fc97a442a35d4f8325be8 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135380 Reviewed-by: CITOOLS Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 9545b69bbd82..be27f5cfdba8 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -39,6 +39,7 @@ config TARGET_STM32MP1 select STM32_RESET select STM32_SERIAL imply BOOTCOUNT_LIMIT + imply SILENT_CONSOLE imply SYSRESET_PSCI if STM32MP1_TRUSTED imply SYSRESET_SYSCON if !STM32MP1_TRUSTED help From a442d542f9f5730ae3579c1236986564b3e1b7e8 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 Jun 2019 19:31:02 +0200 Subject: [PATCH 179/244] stm32mp1: activate PRE_CONSOLE_BUFFER Correctly handle silent=1 in the default environment. Signed-off-by: Patrick Delaunay Change-Id: I31cc401c389468eb5e255fe81b90dc9e95006962 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135381 Reviewed-by: CITOOLS Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index be27f5cfdba8..470b51ff1927 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -39,6 +39,7 @@ config TARGET_STM32MP1 select STM32_RESET select STM32_SERIAL imply BOOTCOUNT_LIMIT + imply PRE_CONSOLE_BUFFER imply SILENT_CONSOLE imply SYSRESET_PSCI if STM32MP1_TRUSTED imply SYSRESET_SYSCON if !STM32MP1_TRUSTED @@ -130,6 +131,12 @@ config SYS_TEXT_BASE when DDR driver is used: DDR + 1MB (0xC0100000) +config PRE_CON_BUF_ADDR + default 0xC02FF000 + +config PRE_CON_BUF_SZ + default 4096 + config NR_DRAM_BANKS default 1 From 449958f9981f46b21808a59f12d1815d1c7f1a5e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 6 Jun 2019 18:18:45 +0200 Subject: [PATCH 180/244] cmd: dtimg: get devicetree index based on board identifier and revision The dtimg includes several devicetrees selected by an index. Each device tree is added in the dtimg associated with a board identifier (and optionally a board revision). This service is added to get back the index associated to the board id and optionally the board rev. Change-Id: Ie7670d4a9ee132953296a8616ce5575b6fa65de4 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135279 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- cmd/dtimg.c | 50 +++++++++++++++++++++++++++++++++++++- common/image-android-dt.c | 42 ++++++++++++++++++++++++++++++++ include/image-android-dt.h | 2 ++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/cmd/dtimg.c b/cmd/dtimg.c index 65c8d101b98e..eca6a23ad5ad 100644 --- a/cmd/dtimg.c +++ b/cmd/dtimg.c @@ -98,10 +98,52 @@ static int do_dtimg_size(cmd_tbl_t *cmdtp, int flag, int argc, return dtimg_get_fdt(argc, argv, CMD_DTIMG_SIZE); } +static int do_dtimg_getindex(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *endp; + ulong hdr_addr; + int index; + char buf[512] = { 0 }; + + if (argc < 4) + return CMD_RET_USAGE; + + hdr_addr = simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0') { + printf("Error: Wrong image address\n"); + return CMD_RET_FAILURE; + } + + if (!android_dt_check_header(hdr_addr)) { + printf("Error: DT image header is incorrect\n"); + return CMD_RET_FAILURE; + } + + index = android_dt_get_index(hdr_addr, strtoul(argv[2], NULL, 0), + strtoul(argv[3], NULL, 0)); + + if (index < 0) { + printf("Error: board id %04lx not found in DT table\n", + strtoul(argv[2], NULL, 0)); + return CMD_RET_FAILURE; + } + + snprintf(buf, sizeof(buf), "%i", index); + + if (argc == 5) + env_set(argv[4], buf); + else + printf("%s\n", buf); + + return CMD_RET_SUCCESS; +} + static cmd_tbl_t cmd_dtimg_sub[] = { U_BOOT_CMD_MKENT(dump, 2, 0, do_dtimg_dump, "", ""), U_BOOT_CMD_MKENT(start, 4, 0, do_dtimg_start, "", ""), U_BOOT_CMD_MKENT(size, 4, 0, do_dtimg_size, "", ""), + U_BOOT_CMD_MKENT(getindex, 5, 0, do_dtimg_getindex, "", ""), }; static int do_dtimg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -137,5 +179,11 @@ U_BOOT_CMD( " - get size (hex, bytes) of FDT in the image, by index\n" " : image address in RAM, in hex\n" " : index of desired FDT in the image\n" - " : name of variable where to store size of FDT" + " : name of variable where to store size of FDT\n" + "dtimg getindex [varname]\n" + " - get index of FDT in the image, by board identifier and revision\n" + " : image address in RAM, in hex\n" + " : board identifier\n" + " : board revision (0 if not used)\n" + " [varname]: name of variable where to store index of FDT" ); diff --git a/common/image-android-dt.c b/common/image-android-dt.c index c0683ee70f36..90499d719293 100644 --- a/common/image-android-dt.c +++ b/common/image-android-dt.c @@ -153,4 +153,46 @@ void android_dt_print_contents(ulong hdr_addr) unmap_sysmem(fdt); } } + #endif + +/** + * Get dtb index based on board identifier and revision. + * + * @param hdr_addr Start address of DT image + * @param board_id board identifier + * @param board_rev board revision (0 if not used) + * + * @return index in dt table + */ +int android_dt_get_index(ulong hdr_addr, u32 board_id, u32 board_rev) +{ + const struct dt_table_header *hdr; + u32 entry_count, entries_offset, entry_size; + u32 i; + int ret = -1; + + hdr = map_sysmem(hdr_addr, sizeof(*hdr)); + entry_count = fdt32_to_cpu(hdr->dt_entry_count); + entries_offset = fdt32_to_cpu(hdr->dt_entries_offset); + entry_size = fdt32_to_cpu(hdr->dt_entry_size); + unmap_sysmem(hdr); + + for (i = 0; i < entry_count; ++i) { + const ulong e_addr = hdr_addr + entries_offset + i * entry_size; + const struct dt_table_entry *e; + + e = map_sysmem(e_addr, sizeof(*e)); + + if ((fdt32_to_cpu(e->id) == board_id) && + (board_rev == 0 || fdt32_to_cpu(e->rev) == board_rev)) { + ret = i; + unmap_sysmem(e); + break; + } + + unmap_sysmem(e); + } + + return ret; +} diff --git a/include/image-android-dt.h b/include/image-android-dt.h index 9a3aa8fa30fb..f9abe8519533 100644 --- a/include/image-android-dt.h +++ b/include/image-android-dt.h @@ -17,4 +17,6 @@ bool android_dt_get_fdt_by_index(ulong hdr_addr, u32 index, ulong *addr, void android_dt_print_contents(ulong hdr_addr); #endif +int android_dt_get_index(ulong hdr_addr, u32 board_id, u32 board_rev); + #endif /* IMAGE_ANDROID_DT_H */ From c3fc0de32b5ce92f8c8ff90576c23d639f515f84 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 6 Jun 2019 18:19:41 +0200 Subject: [PATCH 181/244] cmd: part: get partition number based on partition name Add a service to get the partition number from the partition name. This command can be used to set a variable with the correct partition identifier and manage command with don't support selection with the partition name, or for bootargs by example: part nb mmc 0 system_a rootpart_nb env set bootargs root=/dev/mmcblk0p${rootpart_nb} Change-Id: Ia48c0a83612d8240e9f345dc04100108b152a7e3 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135280 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- cmd/part.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/part.c b/cmd/part.c index bfb6488b0f2b..6a7585659a3f 100644 --- a/cmd/part.c +++ b/cmd/part.c @@ -24,6 +24,7 @@ enum cmd_part_info { CMD_PART_INFO_START = 0, CMD_PART_INFO_SIZE, + CMD_PART_INFO_NB, }; static int do_part_uuid(int argc, char * const argv[]) @@ -149,6 +150,9 @@ static int do_part_info(int argc, char * const argv[], enum cmd_part_info param) case CMD_PART_INFO_SIZE: snprintf(buf, sizeof(buf), LBAF, info.size); break; + case CMD_PART_INFO_NB: + snprintf(buf, sizeof(buf), "%i", part); + break; default: printf("** Unknown cmd_part_info value: %d\n", param); return 1; @@ -172,6 +176,11 @@ static int do_part_size(int argc, char * const argv[]) return do_part_info(argc, argv, CMD_PART_INFO_SIZE); } +static int do_part_nb(int argc, char * const argv[]) +{ + return do_part_info(argc, argv, CMD_PART_INFO_NB); +} + static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) @@ -185,6 +194,8 @@ static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_part_start(argc - 2, argv + 2); else if (!strcmp(argv[1], "size")) return do_part_size(argc - 2, argv + 2); + else if (!strcmp(argv[1], "nb")) + return do_part_nb(argc - 2, argv + 2); return CMD_RET_USAGE; } @@ -206,5 +217,8 @@ U_BOOT_CMD( " part can be either partition number or partition name\n" "part size \n" " - set environment variable to the size of the partition (in blocks)\n" - " part can be either partition number or partition name" + " part can be either partition number or partition name\n" + "part nb \n" + " - set environment variable to the number of the partition\n" + " part shall be the partition name" ); From 8cdd05a6782dcf098fadb11654b9a464bdff0888 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 13 Jun 2019 16:05:00 +0200 Subject: [PATCH 182/244] stm32mp1: add environment variable for board id and board rev Add variable to identify board with HW id (read from OTP) and revision. Change-Id: Ie94060ff60c185630a5decbd1398b00511e09a93 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135281 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index da015ed5f1d7..f852b1ed0dd9 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -929,6 +929,10 @@ int board_late_init(void) #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG const void *fdt_compat; int fdt_compat_len; + int ret; + u32 otp; + struct udevice *dev; + char buf[10]; fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible", &fdt_compat_len); @@ -938,6 +942,21 @@ int board_late_init(void) else env_set("board_name", fdt_compat + 3); } + 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) { + snprintf(buf, sizeof(buf), "0x%04x", otp >> 16); + env_set("board_id", buf); + + snprintf(buf, sizeof(buf), "0x%04x", + ((otp >> 8) & 0xF) - 1 + 0xA); + env_set("board_rev", buf); + } #endif /* Check the boot-source to disable bootdelay */ From be067d43709e249b4841d5fb4b2aa6f776315a28 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 6 Jun 2019 17:47:17 +0200 Subject: [PATCH 183/244] stm32mp1: add boot command for Android Allow to boot android with CONFIG_BOOTCOMMAND="run bootcmd_android" The bootcmd override DISTRO script "mmc_boot" to boot android on mmc using system_${suffix} partition (with "_a") by default - display splash screen - load device tree form dtimg - load kernel and set bootargs - start kernel Signed-off-by: Patrick Delaunay Change-Id: I8c6b3b7fc0252ccba15eb1af76fb6f7b3a1ef8e4 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135282 Reviewed-by: CITOOLS --- include/configs/stm32mp1.h | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 1e3738ea11ac..6ca42065e290 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -140,6 +140,7 @@ /* * bootcmd for stm32mp1: + * CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" * 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 @@ -160,6 +161,63 @@ "run distro_bootcmd;" \ "fi;\0" +/* DTIMG command added only for Android distribution */ +#ifdef CONFIG_CMD_DTIMG +/* + * bootcmd for android on MMC: + * CONFIG_BOOTCOMMAND="run bootcmd_android" + * overidde DISTRO script "mmc_boot" to boot android on mmc + * using system_${suffix} partition (with "_a") by default + * - display splash screen + * - load device tree form dtimg + * - load kernel and set bootargs + * - start kernel + */ + +#define STM32MP_ANDROID \ + "suffix=a\0" \ + "dtimg_addr=0xc4500000\0" \ + "android_mmc_splash="\ + "if part start mmc ${devnum} splash splash_start && " \ + "part size mmc ${devnum} splash splash_size;"\ + "then " \ + "mmc read ${splashimage} ${splash_start} ${splash_size};" \ + "cls; bmp display ${splashimage} m m;" \ + "fi\0" \ + "android_mmc_fdt="\ + "if part start mmc ${devnum} dt_${suffix} dt_start &&" \ + "part size mmc ${devnum} dt_${suffix} dt_size;"\ + "then " \ + "mmc read ${dtimg_addr} ${dt_start} ${dt_size};" \ + "dtimg getindex ${dtimg_addr} ${board_id} ${board_rev}" \ + " dt_index;" \ + "dtimg start ${dtimg_addr} ${dt_index} fdt_addr_r;"\ + "fi\0" \ + "android_mmc_kernel="\ + "if part start mmc ${devnum} boot_${suffix} boot_start &&" \ + "part size mmc ${devnum} boot_${suffix} boot_size;"\ + "then " \ + "mmc read ${kernel_addr_r} ${boot_start} ${boot_size};" \ + "part nb mmc ${devnum} system_${suffix} rootpart_nb;" \ + "env set bootargs" \ + "root=/dev/mmcblk${devnum}p${rootpart_nb} " \ + "androidboot.serialno=${serial#} " \ + "androidboot.slot_suffix=_${suffix};"\ + "fi\0" \ + "android_mmc_boot="\ + "mmc dev ${devnum};"\ + "run android_mmc_splash;" \ + "run android_mmc_fdt;" \ + "run android_mmc_kernel;" \ + "bootm ${kernel_addr_r} - ${fdt_addr_r};\0" \ + "bootcmd_android=" \ + "env set mmc_boot run android_mmc_boot;" \ + "run bootcmd_stm32mp\0" + +#else +#define STM32MP_ANDROID +#endif/* CONFIG_CMD_DTIMG */ + #include #ifdef CONFIG_STM32MP1_OPTEE @@ -205,6 +263,7 @@ " then env set env_default 0;env save;fi\0" \ STM32MP_BOOTCMD \ STM32MP_MTDPARTS \ + STM32MP_ANDROID \ BOOTENV \ "boot_net_usb_start=true\0" From b329a6493b06fce02b4213a020d4b4c9c2d70442 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 6 Jun 2019 17:58:06 +0200 Subject: [PATCH 184/244] stm32mp1: activate command dtimg Add command dtimg used to boot ANDROID Signed-off-by: Patrick Delaunay Change-Id: Ia6565b2a30ada3fe212be395acbd3f191fc616b0 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/135283 Reviewed-by: CITOOLS --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 134e901cc139..10da418fd2ab 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -17,6 +17,7 @@ CONFIG_SPL_MTD_SUPPORT=y CONFIG_SPL_POWER_SUPPORT=y CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set +CONFIG_CMD_DTIMG=y # CONFIG_CMD_ELF is not set # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 826a959ca2c7..155107f2b838 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -8,6 +8,7 @@ CONFIG_FIT=y CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set +CONFIG_CMD_DTIMG=y # CONFIG_CMD_ELF is not set # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index c240eb427ef0..567327926dc9 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -7,6 +7,7 @@ CONFIG_FIT=y CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_BOOTD is not set +CONFIG_CMD_DTIMG=y # CONFIG_CMD_ELF is not set # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set From d57907dcd9d5b331af694db0b135b7e15e4648a2 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 23 May 2019 10:03:56 +0200 Subject: [PATCH 185/244] spi: stm32_qspi: Remove STM32_QSPI_CR_FTHRES_MASK On STM32 F4/F7/H7 SoCs, FTHRES is a 5 bits field in QSPI_CR register, but for STM32MP1 SoCs, FTHRES is a 4 bits field long. STM32_QSPI_CR_FTHRES_MASK definition is not correct. Even if it is currently not used, remove STM32_QSPI_CR_FTHRES_MASK to avoid confusion in the future. Change-Id: I3afebd86dc2f413bf013715d712e0e02b93f09f5 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134149 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe KERELLO Reviewed-by: Patrick DELAUNAY --- drivers/spi/stm32_qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index fd7fea40469b..39e95c2bcbcf 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -47,7 +47,6 @@ 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_TEIE BIT(16) #define STM32_QSPI_CR_TCIE BIT(17) From 08961a8ba0999b11bd301c09f81dc0d92d3cbbe4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 6 Jun 2019 12:55:34 +0200 Subject: [PATCH 186/244] clk: stm32mp1: Add RTC clock entry Add RTCAPB and RTC clock support. Signed-off-by: Benjamin Gaignard Signed-off-by: Patrick Delaunay Change-Id: I6c56cc375fe8e96b6925c43c76a4594cc47adf0e Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134631 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/clk/clk_stm32mp1.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index eb7068c05cbe..2d7b185f9fd2 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -304,6 +304,7 @@ enum stm32mp1_parent_sel { _DSI_SEL, _ADC12_SEL, _SPI1_SEL, + _RTC_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -554,6 +555,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), + STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2), @@ -589,6 +591,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), + + STM32MP1_CLK(RCC_BDCR, 20, RTC, _RTC_SEL), }; static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER}; @@ -614,6 +618,7 @@ static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, _PLL3_R}; +static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), @@ -639,6 +644,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), + STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT, + (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT), + rtc_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT @@ -754,6 +762,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", [_SPI1_SEL] = "SPI1", + [_RTC_SEL] = "RTC", }; static const struct stm32mp1_clk_data stm32mp1_data = { From 368f7883c6191df33429e3c4b3ef1ec34c5ace70 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 28 May 2019 14:04:16 +0200 Subject: [PATCH 187/244] rtc: Add rtc driver for stm32mp1 Add support of STM32MP1 rtc driver. Enable it trusted, basic and optee configurations. Signed-off-by: Benjamin Gaignard Change-Id: Ied132f9956314118b5d4592a2027f0bab01123d3 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134632 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD Reviewed-by: Amelie DELAUNAY Reviewed-by: Patrick DELAUNAY --- configs/stm32mp15_basic_defconfig | 2 + configs/stm32mp15_optee_defconfig | 2 + configs/stm32mp15_trusted_defconfig | 2 + drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/stm32_rtc.c | 308 ++++++++++++++++++++++++++++ 6 files changed, 322 insertions(+) create mode 100644 drivers/rtc/stm32_rtc.c diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 10da418fd2ab..3eff6b5e2d4d 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -101,6 +101,8 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_STM32MP1_DDR_INTERACTIVE=y CONFIG_REMOTEPROC_STM32_COPRO=y +CONFIG_DM_RTC=y +CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 155107f2b838..9ef8f628946c 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -87,6 +87,8 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_REMOTEPROC_STM32_COPRO=y +CONFIG_DM_RTC=y +CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 567327926dc9..7635d7f6c761 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -86,6 +86,8 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_REMOTEPROC_STM32_COPRO=y +CONFIG_DM_RTC=y +CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SPI=y CONFIG_DM_SPI=y diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bcc01b135e52..e6167c175385 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -94,4 +94,11 @@ config RTC_MC146818 clock with a wide array of features and 50 bytes of general-purpose, battery-backed RAM. The driver supports access to the clock and RAM. +config RTC_STM32 + bool "Enable STM32 RTC driver" + depends on DM_RTC + help + Enable STM32 RTC driver. This driver supports the rtc that is present + on some STM32 SoCs. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1724602f1cb6..90e79fb30daf 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -50,5 +50,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o obj-$(CONFIG_RTC_S35392A) += s35392a.o +obj-$(CONFIG_RTC_STM32) += stm32_rtc.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o diff --git a/drivers/rtc/stm32_rtc.c b/drivers/rtc/stm32_rtc.c new file mode 100644 index 000000000000..c2c74ce0f19d --- /dev/null +++ b/drivers/rtc/stm32_rtc.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ +#include +#include +#include +#include +#include +#include + +#define STM32_RTC_TR 0x00 +#define STM32_RTC_DR 0x04 +#define STM32_RTC_ISR 0x0C +#define STM32_RTC_PRER 0x10 +#define STM32_RTC_CR 0x18 +#define STM32_RTC_WPR 0x24 + +/* STM32_RTC_TR bit fields */ +#define STM32_RTC_SEC_SHIFT 0 +#define STM32_RTC_SEC GENMASK(6, 0) +#define STM32_RTC_MIN_SHIFT 8 +#define STM32_RTC_MIN GENMASK(14, 8) +#define STM32_RTC_HOUR_SHIFT 16 +#define STM32_RTC_HOUR GENMASK(21, 16) + +/* STM32_RTC_DR bit fields */ +#define STM32_RTC_DATE_SHIFT 0 +#define STM32_RTC_DATE GENMASK(5, 0) +#define STM32_RTC_MONTH_SHIFT 8 +#define STM32_RTC_MONTH GENMASK(12, 8) +#define STM32_RTC_WDAY_SHIFT 13 +#define STM32_RTC_WDAY GENMASK(15, 13) +#define STM32_RTC_YEAR_SHIFT 16 +#define STM32_RTC_YEAR GENMASK(23, 16) + +/* STM32_RTC_CR bit fields */ +#define STM32_RTC_CR_FMT BIT(6) + +/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ +#define STM32_RTC_ISR_INITS BIT(4) +#define STM32_RTC_ISR_RSF BIT(5) +#define STM32_RTC_ISR_INITF BIT(6) +#define STM32_RTC_ISR_INIT BIT(7) + +/* STM32_RTC_PRER bit fields */ +#define STM32_RTC_PRER_PRED_S_SHIFT 0 +#define STM32_RTC_PRER_PRED_S GENMASK(14, 0) +#define STM32_RTC_PRER_PRED_A_SHIFT 16 +#define STM32_RTC_PRER_PRED_A GENMASK(22, 16) + +/* STM32_RTC_WPR key constants */ +#define RTC_WPR_1ST_KEY 0xCA +#define RTC_WPR_2ND_KEY 0x53 +#define RTC_WPR_WRONG_KEY 0xFF + +struct stm32_rtc_priv { + fdt_addr_t base; +}; + +static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 tr, dr; + + tr = readl(priv->base + STM32_RTC_TR); + dr = readl(priv->base + STM32_RTC_DR); + + tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT); + tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT); + tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT); + + tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT); + tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT); + tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT); + tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static void stm32_rtc_unlock(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + + writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR); + writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR); +} + +static void stm32_rtc_lock(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + + writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR); +} + +static int stm32_rtc_enter_init_mode(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + if (!(isr & STM32_RTC_ISR_INITF)) { + isr |= STM32_RTC_ISR_INIT; + writel(isr, priv->base + STM32_RTC_ISR); + + return readl_poll_timeout(priv->base + STM32_RTC_ISR, + isr, + (isr & STM32_RTC_ISR_INITF), + 100000); + } + + return 0; +} + +static int stm32_rtc_wait_sync(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + isr &= ~STM32_RTC_ISR_RSF; + writel(isr, priv->base + STM32_RTC_ISR); + + /* + * Wait for RSF to be set to ensure the calendar registers are + * synchronised, it takes around 2 rtc_ck clock cycles + */ + return readl_poll_timeout(priv->base + STM32_RTC_ISR, + isr, (isr & STM32_RTC_ISR_RSF), + 100000); +} + +static void stm32_rtc_exit_init_mode(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + isr &= ~STM32_RTC_ISR_INIT; + writel(isr, priv->base + STM32_RTC_ISR); +} + +static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + int ret; + + stm32_rtc_unlock(dev); + + ret = stm32_rtc_enter_init_mode(dev); + if (ret) + goto lock; + + writel(time, priv->base + STM32_RTC_TR); + writel(date, priv->base + STM32_RTC_DR); + + stm32_rtc_exit_init_mode(dev); + + ret = stm32_rtc_wait_sync(dev); + +lock: + stm32_rtc_lock(dev); + return ret; +} + +static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + u32 t, d; + + dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + /* Time in BCD format */ + t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC; + t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN; + t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR; + + /* Date in BCD format */ + d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE; + d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH; + d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR; + d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY; + + return stm32_rtc_set_time(dev, t, d); +} + +static int stm32_rtc_reset(struct udevice *dev) +{ + dev_dbg(dev, "Reset DATE\n"); + + return stm32_rtc_set_time(dev, 0, 0); +} + +static int stm32_rtc_init(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; + unsigned int rate; + struct clk clk; + int ret; + u32 isr = readl(priv->base + STM32_RTC_ISR); + + if (isr & STM32_RTC_ISR_INITS) + return 0; + + ret = clk_get_by_index(dev, 1, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + rate = clk_get_rate(&clk); + + /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */ + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; + + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + + /* + * Can't find a 1Hz, so give priority to RTC power consumption + * by choosing the higher possible value for prediv_a + */ + if (pred_s > pred_s_max || pred_a > pred_a_max) { + pred_a = pred_a_max; + pred_s = (rate / (pred_a + 1)) - 1; + } + + stm32_rtc_unlock(dev); + + ret = stm32_rtc_enter_init_mode(dev); + if (ret) { + dev_err(dev, + "Can't enter in init mode. Prescaler config failed.\n"); + goto unlock; + } + + prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; + prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; + writel(prer, priv->base + STM32_RTC_PRER); + + /* Force 24h time format */ + cr = readl(priv->base + STM32_RTC_CR); + cr &= ~STM32_RTC_CR_FMT; + writel(cr, priv->base + STM32_RTC_CR); + + stm32_rtc_exit_init_mode(dev); + + ret = stm32_rtc_wait_sync(dev); +unlock: + stm32_rtc_lock(dev); + + return ret; +} + +static int stm32_rtc_probe(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + ret = stm32_rtc_init(dev); + + return ret; +} + +static const struct rtc_ops stm32_rtc_ops = { + .get = stm32_rtc_get, + .set = stm32_rtc_set, + .reset = stm32_rtc_reset, +}; + +static const struct udevice_id stm32_rtc_ids[] = { + { .compatible = "st,stm32mp1-rtc" }, + { } +}; + +U_BOOT_DRIVER(rtc_stm32) = { + .name = "rtc-stm32", + .id = UCLASS_RTC, + .probe = stm32_rtc_probe, + .of_match = stm32_rtc_ids, + .ops = &stm32_rtc_ops, + .priv_auto_alloc_size = sizeof(struct stm32_rtc_priv), +}; From b17bf204453225c69791906ac97e10bb33cccb48 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 20 May 2019 17:51:35 +0200 Subject: [PATCH 188/244] dts: stm32: alignment with v4.19-stm32mp-r2 Device tree alignment with the latest kernel delivery v4.19-stm32mp-r2 Signed-off-by: Patrick Delaunay Change-Id: Ib10a27589a5fb36c22c276f12a5d2b67daf1f3e2 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133369 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 212 +----------------- arch/arm/dts/stm32mp157a-dk1.dts | 46 +++- arch/arm/dts/stm32mp157c-dk2.dts | 3 +- arch/arm/dts/stm32mp157c-ed1.dts | 3 +- arch/arm/dts/stm32mp157c-ev1.dts | 15 +- arch/arm/dts/stm32mp157c-m4-srm.dtsi | 4 +- arch/arm/dts/stm32mp157c.dtsi | 48 +++- doc/device-tree-bindings/i2c/i2c-stm32.txt | 61 ++--- doc/device-tree-bindings/net/stm32-dwmac.txt | 6 +- .../regulator/st,stm32mp1-pwr-reg.txt | 11 + .../spi/spi-stm32-qspi.txt | 69 +++--- 11 files changed, 172 insertions(+), 306 deletions(-) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 3813f98023c7..dd796ec03816 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -291,13 +291,18 @@ , /* ETH_RGMII_TXD2 */ , /* ETH_RGMII_TXD3 */ , /* ETH_RGMII_TX_CTL */ - , /* ETH_MDIO */ ; /* ETH_MDC */ bias-disable; drive-push-pull; slew-rate = <2>; }; pins2 { + pinmux = ; /* ETH_MDIO */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins3 { pinmux = , /* ETH_RGMII_RXD0 */ , /* ETH_RGMII_RXD1 */ , /* ETH_RGMII_RXD2 */ @@ -387,171 +392,6 @@ }; }; - hdp0_pins_b: hdp0-1 { - pins { - pinmux = ; /* HDP0 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp0_pins_sleep_b: hdp0-sleep-1 { - pins { - pinmux = ; /* HDP0 */ - }; - }; - - hdp1_pins_a: hdp1-0 { - pins { - pinmux = ; /* HDP1 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp1_pins_sleep_a: hdp1-sleep-0 { - pins { - pinmux = ; /* HDP1 */ - }; - }; - - hdp1_pins_b: hdp1-1 { - pins { - pinmux = ; /* HDP1 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp1_pins_sleep_b: hdp1-sleep-1 { - pins { - pinmux = ; /* HDP1 */ - }; - }; - - hdp2_pins_a: hdp2-0 { - pins { - pinmux = ; /* HDP2 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp2_pins_sleep_a: hdp2-sleep-0 { - pins { - pinmux = ; /* HDP2 */ - }; - }; - - hdp2_pins_b: hdp2-1 { - pins { - pinmux = ; /* HDP2 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp2_pins_sleep_b: hdp2-sleep-1 { - pins { - pinmux = ; /* HDP2 */ - }; - }; - - hdp3_pins_a: hdp3-0 { - pins { - pinmux = ; /* HDP3 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp3_pins_sleep_a: hdp3-sleep-0 { - pins { - pinmux = ; /* HDP3 */ - }; - }; - - hdp3_pins_b: hdp3-1 { - pins { - pinmux = ; /* HDP3 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp3_pins_sleep_b: hdp3-sleep-1 { - pins { - pinmux = ; /* HDP3 */ - }; - }; - - hdp4_pins_a: hdp4-0 { - pins { - pinmux = ; /* HDP4 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp4_pins_sleep_a: hdp4-sleep-0 { - pins { - pinmux = ; /* HDP4 */ - }; - }; - - hdp4_pins_b: hdp4-1 { - pins { - pinmux = ; /* HDP4 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp4_pins_sleep_b: hdp4-sleep-1 { - pins { - pinmux = ; /* HDP4 */ - }; - }; - - hdp5_pins_a: hdp5-0 { - pins { - pinmux = ; /* HDP5 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp5_pins_sleep_a: hdp5-sleep-0 { - pins { - pinmux = ; /* HDP5 */ - }; - }; - - hdp5_pins_b: hdp5-1 { - pins { - pinmux = ; /* HDP5 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp5_pins_sleep_b: hdp5-sleep-1 { - pins { - pinmux = ; /* HDP5 */ - }; - }; - hdp6_pins_a: hdp6-0 { pins { pinmux = ; /* HDP6 */ @@ -567,21 +407,6 @@ }; }; - hdp6_pins_b: hdp6-1 { - pins { - pinmux = ; /* HDP6 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp6_pins_sleep_b: hdp6-sleep-1 { - pins { - pinmux = ; /* HDP6 */ - }; - }; - hdp7_pins_a: hdp7-0 { pins { pinmux = ; /* HDP7 */ @@ -597,21 +422,6 @@ }; }; - hdp7_pins_b: hdp7-1 { - pins { - pinmux = ; /* HDP7 */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - }; - - hdp7_pins_sleep_b: hdp7-sleep-1 { - pins { - pinmux = ; /* HDP7 */ - }; - }; - i2c1_pins_a: i2c1-0 { pins { pinmux = , /* I2C1_SCL */ @@ -1637,16 +1447,6 @@ status = "disabled"; }; - btreg: bt_reg_on-0 { - pins { - pinmux = ; - drive-push-pull; - bias-pull-up; - output-high; - slew-rate = <0>; - }; - }; - i2c4_pins_a: i2c4-0 { pins { pinmux = , /* I2C4_SCL */ diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index be5497316ff4..2b01a01d18b5 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -9,7 +9,6 @@ #include "stm32mp157c.dtsi" #include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157cac-pinctrl.dtsi" -#include #include #include @@ -127,11 +126,11 @@ &adc { pinctrl-names = "default"; - pinctrl-0 = <&adc12_usb_pwr_pins_a>; + pinctrl-0 = <&adc12_ain_pins_a>, <&adc12_usb_pwr_pins_a>; vdd-supply = <&vdd>; vdda-supply = <&vdd>; vref-supply = <&vrefbuf>; - status = "okay"; + status = "disabled"; adc1: adc@0 { /* * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in18 & in19. @@ -140,13 +139,13 @@ * 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>; + /* AIN connector, USB Type-C CC1 & CC2 */ + st,adc-channels = <0 1 6 13 18 19>; status = "okay"; }; adc2: adc@100 { - /* ANA0, ANA1, temp sensor, USB Type-C CC1 & CC2 */ - st,adc-channels = <0 1 12 18 19>; + /* AIN connector, temp sensor, USB Type-C CC1 & CC2 */ + st,adc-channels = <0 1 2 6 12 18 19>; /* temperature sensor min sample time */ st,min-sample-time-nsecs = <10000>; status = "okay"; @@ -301,7 +300,7 @@ typec_con: connector { compatible = "usb-c-connector"; label = "USB-C"; - power-role = "sink"; + power-role = "dual"; power-opmode = "default"; }; }; @@ -452,6 +451,15 @@ }; }; +&i2c5 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&i2c5_pins_a>; + pinctrl-1 = <&i2c5_pins_sleep_a>; + /delete-property/dmas; + /delete-property/dma-names; + status = "disabled"; +}; + &i2s2 { clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>; clock-names = "pclk", "i2sclk", "x8k", "x11k"; @@ -500,6 +508,7 @@ interrupt-parent = <&exti>; interrupts = <68 1>; interrupt-names = "wdg"; + wakeup-source; recovery; status = "okay"; }; @@ -507,6 +516,7 @@ &pwr { pwr-regulators { vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; }; }; @@ -575,6 +585,18 @@ status = "okay"; }; +&sdmmc3 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc3_b4_pins_a>; + pinctrl-1 = <&sdmmc3_b4_od_pins_a>; + pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>; + broken-cd; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + status = "disabled"; +}; + &spi4 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&spi4_pins_a>; @@ -593,6 +615,7 @@ /* spare dmas for other usage */ /delete-property/dmas; /delete-property/dma-names; + status = "disabled"; pwm { pinctrl-0 = <&pwm1_pins_a>; pinctrl-1 = <&pwm1_sleep_pins_a>; @@ -607,6 +630,7 @@ &timers3 { /delete-property/dmas; /delete-property/dma-names; + status = "disabled"; pwm { pinctrl-0 = <&pwm3_pins_a>; pinctrl-1 = <&pwm3_sleep_pins_a>; @@ -621,6 +645,7 @@ &timers4 { /delete-property/dmas; /delete-property/dma-names; + status = "disabled"; pwm { pinctrl-0 = <&pwm4_pins_a &pwm4_pins_b>; pinctrl-1 = <&pwm4_sleep_pins_a &pwm4_sleep_pins_b>; @@ -635,6 +660,7 @@ &timers5 { /delete-property/dmas; /delete-property/dma-names; + status = "disabled"; pwm { pinctrl-0 = <&pwm5_pins_a>; pinctrl-1 = <&pwm5_sleep_pins_a>; @@ -659,6 +685,7 @@ &timers12 { /delete-property/dmas; /delete-property/dma-names; + status = "disabled"; pwm { pinctrl-0 = <&pwm12_pins_a>; pinctrl-1 = <&pwm12_sleep_pins_a>; @@ -702,8 +729,7 @@ }; &usbotg_hs { - dr_mode = "peripheral"; - force-b-session-valid; + extcon = <&typec>; phys = <&usbphyc_port1 0>; phy-names = "usb2-phy"; status = "okay"; diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts index f41c3a900b45..d11fbb8c5386 100644 --- a/arch/arm/dts/stm32mp157c-dk2.dts +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -138,8 +138,7 @@ status = "okay"; bluetooth { - pinctrl-names = "default"; - pinctrl-0 = <&btreg>; + shutdown-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; compatible = "brcm,bcm43438-bt"; max-speed = <3000000>; }; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 12c46f225018..c9eabc1328e6 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -8,7 +8,6 @@ #include "stm32mp157c.dtsi" #include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157caa-pinctrl.dtsi" -#include #include / { @@ -337,6 +336,7 @@ interrupt-parent = <&exti>; interrupts = <68 1>; interrupt-names = "wdg"; + wakeup-source; recovery; status = "okay"; }; @@ -344,6 +344,7 @@ &pwr { pwr-regulators { vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; }; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 63ebabdbeb8e..559b9b94cab4 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -7,7 +7,6 @@ #include "stm32mp157c-ed1.dts" #include -#include #include / { @@ -442,14 +441,12 @@ ov5640: camera@3c { compatible = "ovti,ov5640"; - pinctrl-names = "default"; - pinctrl-0 = <&ov5640_pins>; reg = <0x3c>; clocks = <&clk_ext_camera>; clock-names = "xclk"; DOVDD-supply = <&v2v8>; - powerdown-gpios = <&stmfx_pinctrl 18 GPIO_ACTIVE_HIGH>; - reset-gpios = <&stmfx_pinctrl 19 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&stmfx_pinctrl 18 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>; + reset-gpios = <&stmfx_pinctrl 19 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; rotation = <180>; status = "okay"; @@ -485,21 +482,13 @@ hog_pins: hog { pins = "gpio14"; - drive-push-pull; bias-pull-down; }; joystick_pins: joystick { pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; - drive-push-pull; bias-pull-down; }; - - ov5640_pins: camera { - pins = "agpio2", "agpio3"; /* stmfx pins 18 & 19 */ - drive-push-pull; - output-low; - }; }; }; diff --git a/arch/arm/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/dts/stm32mp157c-m4-srm.dtsi index 5ebe24b511a0..9ea97369ddff 100644 --- a/arch/arm/dts/stm32mp157c-m4-srm.dtsi +++ b/arch/arm/dts/stm32mp157c-m4-srm.dtsi @@ -295,14 +295,14 @@ m4_m_can1: can@4400e000 { compatible = "rproc-srm-dev"; reg = <0x4400e000>, <0x44011000>; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; status = "disabled"; }; m4_m_can2: can@4400f000 { compatible = "rproc-srm-dev"; reg = <0x4400f000>, <0x44011000>; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; status = "disabled"; }; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index c969d9b9a766..c94a1f254e37 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -5,6 +5,7 @@ */ #include #include +#include #include / { @@ -132,12 +133,6 @@ thermal-sensors = <&dts>; trips { - cpu_alert1: cpu-alert1 { - temperature = <85000>; - hysteresis = <0>; - type = "passive"; - }; - cpu-crit { temperature = <120000>; hysteresis = <0>; @@ -204,6 +199,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -232,6 +228,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -258,6 +255,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -286,6 +284,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -343,6 +342,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -364,6 +364,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -385,6 +386,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -624,7 +626,7 @@ compatible = "st,stm32-cec"; reg = <0x40016000 0x400>; interrupts = ; - clocks = <&rcc CEC_K>, <&clk_lse>; + clocks = <&rcc CEC_K>, <&rcc CEC>; clock-names = "cec", "hdmi-cec"; power-domains = <&pd_core>; status = "disabled"; @@ -700,6 +702,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -730,6 +733,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -810,6 +814,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -834,6 +839,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; timer@15 { @@ -857,6 +863,7 @@ pwm { compatible = "st,stm32-pwm"; + #pwm-cells = <3>; status = "disabled"; }; @@ -1084,6 +1091,7 @@ , ; clocks = <&rcc DMA1>; + resets = <&rcc DMA1_R>; #dma-cells = <4>; st,mem2mem; dma-requests = <8>; @@ -1110,6 +1118,7 @@ , ; clocks = <&rcc DMA2>; + resets = <&rcc DMA2_R>; #dma-cells = <4>; st,mem2mem; dma-requests = <8>; @@ -1132,6 +1141,7 @@ dma-masters = <&dma1 &dma2>; dma-channels = <16>; clocks = <&rcc DMAMUX>; + resets = <&rcc DMAMUX_R>; }; adc: adc@48003000 { @@ -1232,12 +1242,16 @@ clock-names = "otg"; resets = <&rcc USBO_R>; reset-names = "dwc2"; - interrupts = ; + interrupts-extended = <&intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, + <&exti 44 1>; + interrupt-names = "event", "wakeup"; g-rx-fifo-size = <256>; g-np-tx-fifo-size = <32>; g-tx-fifo-size = <128 128 64 64 64 64 32 32>; dr_mode = "otg"; usb33d-supply = <&usb33>; + power-domains = <&pd_core>; + wakeup-source; status = "disabled"; }; @@ -1641,7 +1655,7 @@ interrupts = ; clocks = <&rcc HASH1>; resets = <&rcc HASH1_R>; - dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0 0x0>; + dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0>; dma-names = "in"; dma-maxburst = <2>; status = "disabled"; @@ -1660,6 +1674,7 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; + resets = <&rcc MDMA_R>; #dma-cells = <6>; dma-channels = <32>; dma-requests = <48>; @@ -1782,8 +1797,12 @@ reg = <0x5800d000 0x1000>; clocks = <&rcc USBH>; resets = <&rcc USBH_R>; - interrupts = ; + interrupts-extended = <&intc GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, + <&exti 43 1>; + interrupt-names = "event", "wakeup"; companion = <&usbh_ohci>; + power-domains = <&pd_core>; + wakeup-source; status = "disabled"; }; @@ -1850,6 +1869,15 @@ }; }; + ddrperfm: perf@5a007000 { + compatible = "st,stm32-ddr-pmu"; + reg = <0x5a007000 0x400>; + clocks = <&rcc DDRPERFM>, <&rcc PLL2_R>; + clock-names = "bus", "ddr"; + resets = <&rcc DDRPERFM_R>; + status = "okay"; + }; + usart1: serial@5c000000 { compatible = "st,stm32h7-uart"; reg = <0x5c000000 0x400>; diff --git a/doc/device-tree-bindings/i2c/i2c-stm32.txt b/doc/device-tree-bindings/i2c/i2c-stm32.txt index 352dba530655..7f7686ebbfb3 100644 --- a/doc/device-tree-bindings/i2c/i2c-stm32.txt +++ b/doc/device-tree-bindings/i2c/i2c-stm32.txt @@ -7,6 +7,7 @@ Required properties : - reg : Offset and length of the register set for the device - interrupts : Must contain the interrupt id for I2C event and then the interrupt id for I2C error. + Optionnaly a wakeup interrupt may be specified. - resets: Must contain the phandle to the reset controller. - clocks: Must contain the input clock of the I2C instance. - A pinctrl state named "default" must be defined to set pins in mode of @@ -20,18 +21,25 @@ Optional properties : the default 100 kHz frequency will be used. For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are 100000 and 400000. - For STM32F7 SoC, Standard-mode, Fast-mode and Fast-mode Plus are supported, - possible values are 100000, 400000 and 1000000. -- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board - (default: 25) -- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board - (default: 10) + For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode, Fast-mode and Fast-mode + Plus are supported, possible values are 100000, 400000 and 1000000. +- i2c-scl-rising-time-ns: I2C SCL Rising time for the board (default: 25) + For STM32F7, STM32H7 and STM32MP1 only. +- i2c-scl-falling-time-ns: I2C SCL Falling time for the board (default: 10) + For STM32F7, STM32H7 and STM32MP1 only. I2C Timings are derived from these 2 values -- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG - whether Fast Mode Plus speed is selected by slave. +- st,syscfg-fmp: Use to set Fast Mode Plus bit within SYSCFG when Fast Mode + Plus speed is selected by slave. 1st cell : phandle to syscfg 2nd cell : register offset within SYSCFG 3rd cell : register bitmask for FMP bit + For STM32F7, STM32H7 and STM32MP1 only. +- st,syscfg-fmp-clr: Use to clear Fast Mode Plus bit within SYSCFG when Fast + Mode Plus speed is selected by slave. + 1st cell: phandle to syscfg + 2nd cell: clear register offset within SYSCFG + 3rd cell: register bitmask for FMP clear bit + For STM32MP1 family only. Example : @@ -61,8 +69,25 @@ Example : pinctrl-1 = <&i2c1_sda_pin_sleep>, <&i2c1_scl_pin_sleep>; pinctrl-names = "default", "sleep"; st,syscfg-fmp = <&syscfg 0x4 0x1>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x1>; }; + i2c@40013000 { + compatible = "st,stm32f7-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40013000 0x400>; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>, + <&exti 22 1>; + clocks = <&rcc I2C2_K>; + resets = <&rcc I2C2_R>; + st,syscfg-fmp = <&syscfg 0x4 0x2>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x2>; + }; + + * I2C Devices An I2C device connected onto STM32 I2C controller must use a format described by @@ -75,28 +100,10 @@ Required properties : I2C slave addresses (see i2c.txt for more details) Optional properties : -- wakeup-source - device can be used as a wakeup source. Valid only if device is a - master. -- interrupt-names - should be set as "wakeup" if a dedicated wakeup source is used. - Imply "wakeup-source" property -- interrupts - defined dedicated IRQ wakeup source from controller. - i2c@40005400 { + i2c@40013000 { camera@3c { compatible = "ovti,ov5640"; reg = <0x3c>; }; }; - - i2c@40005400 { - eeprom@64 { - compatible = "linux,slave-24c02"; - reg = <0x40000064>; - wakeup-source; - interrupt-names = "wakeup"; - interrupts-extended = <&exti 25 1>; - }; - }; diff --git a/doc/device-tree-bindings/net/stm32-dwmac.txt b/doc/device-tree-bindings/net/stm32-dwmac.txt index 73773ec58ba4..e675803dd1f5 100644 --- a/doc/device-tree-bindings/net/stm32-dwmac.txt +++ b/doc/device-tree-bindings/net/stm32-dwmac.txt @@ -14,8 +14,7 @@ Required properties: - clock-names: Should be "stmmaceth" for the host clock. Should be "mac-clk-tx" for the MAC TX clock. Should be "mac-clk-rx" for the MAC RX clock. - For MPU family need to add also "ethstp" for power mode clock and, - "syscfg-clk" for SYSCFG clock. + For MPU family need to add also "ethstp" for power mode clock. - interrupt-names: Should contain a list of interrupt names corresponding to the interrupts in the interrupts property, if available. Should be "macirq" for the main MAC IRQ @@ -24,7 +23,8 @@ Required properties: encompases the glue register, and the offset of the control register. Optional properties: -- clock-names: For MPU family "mac-clk-ck" for PHY without quartz +- clock-names: For MPU family "eth-ck" for PHY without quartz + "syscfg-clk" for SYSCFG clock. - st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz - st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz diff --git a/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt index cee27d52edcd..12acf9dbbbc0 100644 --- a/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt +++ b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt @@ -10,12 +10,17 @@ Required properties: - st,tzcr: syscon of Trust Zone Configuration Register. Usefull to know if we are in secure mode. st,tzcr = & ; +Optional properties: +- vdd-supply: phandle to the parent supply/regulator node for vdd input +- vdd_3v3_usbfs-supply: phandle to the parent supply/regulator node for usb33 Example: pwr-regulators@c { compatible = "st,stm32mp1,pwr-reg"; st,tzcr = <&rcc 0x0 0x1>; + vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; reg11: reg11 { regulator-name = "reg11"; @@ -28,4 +33,10 @@ Example: regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; + + usb33: usb33 { + regulator-name = "usb33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; }; diff --git a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt index 6c7da1d76c1d..551a8d6bfa7d 100644 --- a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt +++ b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt @@ -1,39 +1,44 @@ -STM32 QSPI controller device tree bindings --------------------------------------------- +* STMicroelectronics Quad Serial Peripheral Interface(QSPI) Required properties: -- compatible : should be "st,stm32-qspi". -- reg : 1. Physical base address and size of SPI registers map. - 2. Physical base address & size of mapped NOR Flash. -- spi-max-frequency : Max supported spi frequency. -- status : enable in requried dts. - -Connected flash properties --------------------------- -- spi-max-frequency : Max supported spi frequency. -- spi-tx-bus-width : Bus width (number of lines) for writing (1-4) -- spi-rx-bus-width : Bus width (number of lines) for reading (1-4) -- memory-map : Address and size for memory-mapping the flash +- compatible: should be "st,stm32f469-qspi" +- reg: the first contains the register location and length. + the second contains the memory mapping address and length +- reg-names: should contain the reg names "qspi" "qspi_mm" +- interrupts: should contain the interrupt for the device +- clocks: the phandle of the clock needed by the QSPI controller +- A pinctrl must be defined to set pins in mode of operation for QSPI transfer + +Optional properties: +- resets: must contain the phandle to the reset controller. + +A spi flash (NOR/NAND) must be a child of spi node and could have some +properties. Also see jedec,spi-nor.txt. + +Required properties: +- reg: chip-Select number (QSPI controller may connect 2 flashes) +- spi-max-frequency: max frequency of spi bus + +Optional property: +- spi-rx-bus-width: see ./spi-bus.txt for the description Example: - qspi: quadspi@A0001000 { - compatible = "st,stm32-qspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>; - reg-names = "QuadSPI", "QuadSPI-memory"; - interrupts = <92>; - spi-max-frequency = <108000000>; - status = "okay"; - - qflash0: n25q128a { - #address-cells = <1>; - #size-cells = <1>; - compatible = "micron,n25q128a13", "spi-flash"; - spi-max-frequency = <108000000>; - spi-tx-bus-width = <4>; - spi-rx-bus-width = <4>; - memory-map = <0x90000000 0x1000000>; + +qspi: spi@a0001000 { + compatible = "st,stm32f469-qspi"; + reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = <91>; + resets = <&rcc STM32F4_AHB3_RESET(QSPI)>; + clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0>; + + flash@0 { + compatible = "jedec,spi-nor"; reg = <0>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; + ... }; }; From b09e8d74303cd3550eb85712b3b2f1243e3f3571 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 3 Jun 2019 14:55:18 +0200 Subject: [PATCH 189/244] ARM: dts: stm32: dk1: activate adc used for usb power check The ADC is deactivated in kernel but U-Boot uses ADC measurements on adc1 channels 18 and 19 for USB power check. Signed-off-by: Patrick Delaunay Change-Id: I90ae4ebf67c39de79927bd586c3614e4279c2a33 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/134895 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index f1a22249ffab..c61fc909e0da 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -33,6 +33,10 @@ }; }; +&adc { + status = "okay"; +}; + &clk_hse { st,digbypass; }; From 0470194891fdd311f483567fd96673fd2bf32242 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 24 Jun 2019 18:35:27 +0200 Subject: [PATCH 190/244] stm32mp1: ram: fix address issue in 2 tests If user choose to test memory size is 1GByte (0x40000000), memory address would overflow in test "Random" and test "FrequencySelectivePattern". Thus the system would hangs up when running DDR test. Signed-off-by: Patrick Delaunay Signed-off-by: Bossen WU Change-Id: I61354d6c7a8f90f3ba20d3130339ef5d37905d8e Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/136875 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- drivers/ram/stm32mp1/stm32mp1_tests.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 2df6962da096..e09ca31a09e8 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -580,27 +580,29 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, u32 error = 0; unsigned int seed; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 8 * 1024)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; if (get_addr(string, argc, argv, 2, &addr)) return TEST_ERROR; - printf("running %d loops at 0x%x\n", nb_loop, addr); + bufsize /= 2; + printf("running %d loops copy from 0x%x to 0x%x (buffer size=0x%x)\n", + nb_loop, addr, addr + bufsize, bufsize); while (!error) { seed = rand(); - for (offset = addr; offset < addr + bufsize; offset += 4) - writel(rand(), offset); + for (offset = 0; offset < bufsize; offset += 4) + writel(rand(), addr + offset); memcpy((void *)addr + bufsize, (void *)addr, bufsize); srand(seed); - for (offset = addr; offset < addr + 2 * bufsize; offset += 4) { - if (offset == (addr + bufsize)) + for (offset = 0; offset < 2 * bufsize; offset += 4) { + if (offset == bufsize) srand(seed); value = rand(); - error = check_addr(offset, value); + error = check_addr(addr + offset, value); if (error) break; if (progress(offset)) @@ -609,6 +611,7 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, if (test_loop_end(&loop, nb_loop, 100)) break; } + putc('\n'); if (error) { sprintf(string, @@ -793,9 +796,9 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, int i; int j; enum test_result res = TEST_PASSED; - u32 *offset, testsize, remaining; + u32 offset, testsize, remaining; - offset = address; + offset = (u32)address; remaining = bufsize; while (remaining) { testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize; @@ -811,7 +814,7 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); - __asm__("subs r2, r2, #8"); + __asm__("subs r2, r2, #128"); __asm__("bge loop2"); __asm__("pop {R0-R10}"); @@ -1411,7 +1414,7 @@ const struct test_desc test[] = { "Verifies r/w and memcopy(burst for pseudo random value.", 3 }, - {test_freq_pattern, "FrequencySelectivePattern ", "[size]", + {test_freq_pattern, "FrequencySelectivePattern", "[size]", "write & test patterns: Mostly Zero, Mostly One and F/n", 1 }, From 026ca8e670a9d7fc1996c88b39a1191376452170 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Jul 2019 14:29:19 +0200 Subject: [PATCH 191/244] dt-bindings: clock: stm32mp1: support disabled fixed clock Add precision for disabled fixed clock in stm32mp1 binding. Signed-off-by: Patrick Delaunay Change-Id: I2a53ba272337036ba919b19cfcba63a9653568f6 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/137812 Reviewed-by: CITOOLS --- doc/device-tree-bindings/clock/st,stm32mp1.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt index 02e14609bb77..ec1d703f34ec 100644 --- a/doc/device-tree-bindings/clock/st,stm32mp1.txt +++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt @@ -164,8 +164,10 @@ used to define the state of associated ST32MP1 oscillators: - clk-csi At boot the clock tree initialization will - - enable oscillators present in device tree + - enable oscillators present in device tree and not disabled + (node with status="disabled"), - disable HSI oscillator if the node is absent (always activated by bootrom) + and not disabled (node with status="disabled"). Optional properties : From 2ac7bedb81c20eb3fdca6b5750343319b188e290 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 19 Jul 2019 17:34:14 +0200 Subject: [PATCH 192/244] configs: stm32mp1: Enable CONFIG_ENV_OVERWRITE flag Allows to overwrite environment variable This is needed to overwrite serial and mac address environment variable. Change-Id: I3464b3072b9839287cebaed9272b4b72b852e838 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139194 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- include/configs/stm32mp1.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 6ca42065e290..15018456598e 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -48,6 +48,7 @@ /* * Env parameters */ +#define CONFIG_ENV_OVERWRITE #define CONFIG_ENV_SIZE SZ_8K #if defined(CONFIG_ENV_IS_IN_UBI) From 57eeb4d8cc6321c3d0a3c61ab486a1825777fabb Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 19 Jul 2019 17:36:46 +0200 Subject: [PATCH 193/244] mach-stm32mp1: Overwrite serial and MAC address from OTP Force read of serial and MAC address from OTP and overwrite serial and MAC address environment variable. Change-Id: I2a4d1fdedad7c6f9857073901dfefe82f82e1fdb Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139195 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/cpu.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 1ce042d6ab7e..efe8b79a9001 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -462,12 +462,9 @@ static int setup_mac_address(void) int i; u32 otp[2]; uchar enetaddr[6]; + char buf[ARP_HLEN_ASCII + 1]; struct udevice *dev; - /* MAC already in environment */ - if (eth_env_get_enetaddr("ethaddr", enetaddr)) - return 0; - ret = uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(stm32mp_bsec), &dev); @@ -486,9 +483,11 @@ static int setup_mac_address(void) pr_err("invalid MAC address in OTP %pM", enetaddr); return -EINVAL; } + pr_debug("OTP MAC address = %pM\n", enetaddr); - ret = !eth_env_set_enetaddr("ethaddr", enetaddr); - if (!ret) + sprintf(buf, "%pM", enetaddr); + ret = env_set("ethaddr", buf); + if (ret) pr_err("Failed to set mac address %pM from OTP: %d\n", enetaddr, ret); #endif @@ -503,9 +502,6 @@ static int setup_serial_number(void) struct udevice *dev; int ret; - if (env_get("serial#")) - return 0; - ret = uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(stm32mp_bsec), &dev); From 91d9cea7d202fee3330d8f645ac8b9e32af7e083 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 18 Jul 2019 17:44:16 +0200 Subject: [PATCH 194/244] Revert "mmc: increase timeout for erase command" This patch didn't fix anymore the original issue visible on v2018.11. On v2019.07, this patch must be reverted, the fix must be done in stm32_sdmmc.c driver. This reverts commit 710aa969bef754253df3ce9f9f8b586b830f96b6. Signed-off-by: Patrice Chotard Change-Id: I61bca0431a20571e2a62f04b760fe124b9c427aa Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139037 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe KERELLO Reviewed-by: Patrick DELAUNAY --- drivers/mmc/mmc_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 1a3f5615b279..b8acc33c76d0 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -79,7 +79,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) u32 start_rem, blkcnt_rem; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; - int timeout = 2000; + int timeout = 1000; if (!mmc) return -1; From 89cd4a751311ba1c0dfe717e9025ccb13e2dff7f Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 18 Jul 2019 17:07:08 +0200 Subject: [PATCH 195/244] mmc: stm32_sdmmc2: Increase SDMMC_BUSYD0END_TIMEOUT_US Increase SDMMC_BUSYD0END_TIMEOUT_US from 1s to 2s to avoid timeout error during blocks erase on some sdcard Issue seen on Kingston 16GB : Device: STM32 SDMMC2 Manufacturer ID: 27 OEM: 5048 Name: SD16G Bus Speed: 50000000 Mode: SD High Speed (50MHz) card capabilities: widths [4, 1] modes [SD Legacy, SD High Speed (50MHz)] host capabilities: widths [4, 1] modes [MMC legacy, SD Legacy, MMC High Speed (26MHz), SD High Speed (50MHz), MMC High Speed (52MHz)] Rd Block Len: 512 SD version 3.0 High Capacity: Yes Capacity: 14.5 GiB Bus Width: 4-bit Erase Group Size: 512 Bytes Issue reproduced with following command: STM32MP> mmc erase 0 100000 MMC erase: dev # 0, block # 0, count 1048576 ... mmc erase failed 16384 blocks erased: ERROR By by setting SDMMC_BUSYD0END_TIMEOUT_US at 2 seconds and by adding time measurement in stm32_sdmmc2_end_cmd() as shown below: +start = get_timer(0); /* Polling status register */ ret = readl_poll_timeout(priv->base + SDMMC_STA, status, status & mask, SDMMC_BUSYD0END_TIMEOUT_US); +printf("time = %ld ms\n", get_timer(start)); We get the following trace: STM32MP> mmc erase 0 100000 MMC erase: dev # 0, block # 0, count 1048576 ... time = 17 ms time = 1 ms time = 1025 ms time = 54 ms time = 56 ms time = 1021 ms time = 57 ms time = 56 ms time = 1020 ms time = 53 ms time = 57 ms time = 1021 ms time = 53 ms time = 57 ms time = 1313 ms time = 54 ms time = 56 ms time = 1026 ms time = 54 ms time = 56 ms time = 1036 ms time = 54 ms time = 56 ms time = 1028 ms time = 53 ms time = 56 ms time = 1027 ms time = 54 ms time = 56 ms time = 1024 ms time = 54 ms time = 56 ms time = 1020 ms time = 54 ms time = 57 ms time = 1023 ms time = 54 ms time = 56 ms time = 1033 ms time = 53 ms time = 57 ms .... time = 53 ms time = 57 ms time = 1021 ms time = 56 ms time = 56 ms time = 1026 ms time = 54 ms time = 56 ms 1048576 blocks erased: OK We see that 1 second timeout is not enough, we also see one measurement up to 1313 ms. Set the timeout to 2 second to keep a security margin. Change-Id: I51a798f5dd2deae42daedf6a8d65dfad45de5f4c Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139038 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe KERELLO Reviewed-by: Patrick DELAUNAY --- drivers/mmc/stm32_sdmmc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index e7058cbe0822..32434a4762f7 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -191,7 +191,7 @@ struct stm32_sdmmc2_ctx { #define SDMMC_IDMACTRL_IDMAEN BIT(0) #define SDMMC_CMD_TIMEOUT 0xFFFFFFFF -#define SDMMC_BUSYD0END_TIMEOUT_US 1000000 +#define SDMMC_BUSYD0END_TIMEOUT_US 2000000 static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, struct mmc_data *data, From d62f14dece32e41c2854b9ff44aca7b8384aa8a0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 3 Aug 2019 17:15:06 +0200 Subject: [PATCH 196/244] ARM: dts: stm32mp1: move FDCAN to PLL4_R LTDC modifies the clock frequency to adapt it to the display. Such frequency change is not detected by the FDCAN driver that instead cache the value at probe and pretend to use it later. Keep the LTDC alone on PLL4_Q by moving the FDCAN to PLL4_R. Signed-off-by: Antonio Borneo Change-Id: Ide537d091d8ee33f89ee50edad59ea237e517e42 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/140379 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 2 +- arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index c61fc909e0da..757df241051b 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -109,7 +109,7 @@ CLK_UART6_HSI CLK_UART78_HSI CLK_SPDIF_PLL4P - CLK_FDCAN_PLL4Q + CLK_FDCAN_PLL4R CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 517de819169a..5ab4eeb183f1 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -107,7 +107,7 @@ CLK_UART6_HSI CLK_UART78_HSI CLK_SPDIF_PLL4P - CLK_FDCAN_PLL4Q + CLK_FDCAN_PLL4R CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q From 22eea618b3295cfae777aa80789eb1b46824db12 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 8 Jul 2019 10:58:22 +0200 Subject: [PATCH 197/244] Prepare v2018.11-stm32mp-r3 - Add SPI driver - Add RTC driver for UEFI - Migrate qspi driver to spi-mem framework - DDR setting v1.45 / alignment with latest CubeMX generation - Solve issues of ethernet driver and phy - Activate UEFI support for EBBR (https://github.com/ARM-software/ebbr) - Update bootcmd and migrate to Kconfig (CONFIG_BOOTCOMMAND) - Prepare bootcmd for Android - Alignment for latest kernel device tree v4.19-stm32mp-r2 - Alignment with up-streamed drivers - Many other corrections Signed-off-by: Patrick Delaunay Change-Id: If45cf134951830d1c4e3428512d042c8f82b0bda Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/138045 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5cd64b52cc46..b9579b21a2ef 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2.5 +EXTRAVERSION = -stm32mp-r3 NAME = # *DOCUMENTATION* From 6b2a20d5e918998b711a43973a7655f297396dbf Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Sep 2019 15:51:07 +0200 Subject: [PATCH 198/244] remoteproc: rproc-uclass: Fix elf header parsing If p_type is different from LOAD type the phdr pointer is not incremented. As consequence following sections are never loaded. Change-Id: Ia4f55e56f34cf235bb12d0e48af88639040f55ef Signed-off-by: Arnaud Pouliquen Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/141879 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Fabien DESSENNE Reviewed-by: Patrick DELAUNAY --- drivers/remoteproc/rproc-uclass.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 36f1e971fc16..a817bc0507c5 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -432,7 +432,7 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, } /* Load each program header */ - for (i = 0; i < ehdr->e_phnum; ++i) { + for (i = 0; i < ehdr->e_phnum; ++i, phdr++) { void *dst = (void *)(uintptr_t)phdr->p_paddr; void *src = (void *)addr + phdr->p_offset; @@ -453,7 +453,6 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, roundup((unsigned long)dst + phdr->p_filesz, ARCH_DMA_MINALIGN) - rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); - ++phdr; } *entry = ehdr->e_entry; From 0521742dac1ad3238bc5512fd07b5af72e4ea9d9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 4 Sep 2019 17:03:05 +0200 Subject: [PATCH 199/244] Prepare v2018.11-stm32mp-r3.1 Signed-off-by: Patrick Delaunay Change-Id: I5c0736307d87ee0b68456869eb060ec2fcb4690a --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b9579b21a2ef..143e7dd9543e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r3 +EXTRAVERSION = -stm32mp-r3.1 NAME = # *DOCUMENTATION* From 16b00d6151e5d6d7cc9a5f3a2a9fa73dc03ba5c8 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 27 Nov 2019 17:49:25 +0100 Subject: [PATCH 200/244] stm32mp1: Keep error led ON in case of low power detection Since commit 2b1399e98c33 ("stm32mp1: support of error led on ed1/ev1 board") the attended behavior was no more respected in case of low power source detection on DK2. The expected behavior is either the error LED keeps blinking for ever, or blinks 2 or 3 times and must stay ON. Change-Id: I5954842931a3f46d943b91004a060d6fb5072109 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151155 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index f852b1ed0dd9..1d6cc06d0ca4 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -517,6 +517,7 @@ static void __maybe_unused led_error_blink(u32 nb_blink) mdelay(125); WATCHDOG_RESET(); } + led_set_state(led, LEDST_ON); } #endif From 6cf129b9b90bce2ffcdf34af9b4f8675fc9ea12e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 4 Dec 2019 18:13:11 +0100 Subject: [PATCH 201/244] dts: stm32: alignment with v4.19-stm32mp-r2.4 Device tree alignment with the latest kernel delivery v4.19-stm32mp-r2.4 Signed-off-by: Patrick Delaunay Change-Id: I23f44856b0e2cd15492bf3295b6f3df87f8d35f6 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/152032 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/dts/stm32mp157a-dk1.dts | 1 + arch/arm/dts/stm32mp157c-ev1.dts | 4 +-- arch/arm/dts/stm32mp157c.dtsi | 57 ++++++++++++++++++-------------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 2b01a01d18b5..15fb78f20656 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -719,6 +719,7 @@ pinctrl-0 = <&usart3_pins_b>; pinctrl-1 = <&usart3_sleep_pins_b>; pinctrl-2 = <&usart3_idle_pins_b>; + st,hw-flow-ctrl; status = "disabled"; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 559b9b94cab4..bcb103979b13 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -647,9 +647,8 @@ }; &spdifrx { - pinctrl-names = "default", "sleep"; + pinctrl-names = "default"; pinctrl-0 = <&spdifrx_pins_a>; - pinctrl-1 = <&spdifrx_sleep_pins_a>; status = "okay"; spdifrx_port: port { @@ -717,6 +716,7 @@ pinctrl-0 = <&usart3_pins_a>; pinctrl-1 = <&usart3_sleep_pins_a>; pinctrl-2 = <&usart3_idle_pins_a>; + st,hw-flow-ctrl; status = "disabled"; }; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index c94a1f254e37..80081dde4ebc 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -1060,7 +1060,7 @@ interrupts = , ; interrupt-names = "int0", "int1"; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; status = "disabled"; @@ -1073,7 +1073,7 @@ interrupts = , ; interrupt-names = "int0", "int1"; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; status = "disabled"; @@ -1095,14 +1095,14 @@ #dma-cells = <4>; st,mem2mem; dma-requests = <8>; - dmas = <&mdma1 0 0x11 0x1200000a 0x48000008 0x00000020 1>, - <&mdma1 1 0x11 0x1200000a 0x48000008 0x00000800 1>, - <&mdma1 2 0x11 0x1200000a 0x48000008 0x00200000 1>, - <&mdma1 3 0x11 0x1200000a 0x48000008 0x08000000 1>, - <&mdma1 4 0x11 0x1200000a 0x4800000C 0x00000020 1>, - <&mdma1 5 0x11 0x1200000a 0x4800000C 0x00000800 1>, - <&mdma1 6 0x11 0x1200000a 0x4800000C 0x00200000 1>, - <&mdma1 7 0x11 0x1200000a 0x4800000C 0x08000000 1>; + dmas = <&mdma1 0 0x3 0x1200000a 0x48000008 0x00000020 1>, + <&mdma1 1 0x3 0x1200000a 0x48000008 0x00000800 1>, + <&mdma1 2 0x3 0x1200000a 0x48000008 0x00200000 1>, + <&mdma1 3 0x3 0x1200000a 0x48000008 0x08000000 1>, + <&mdma1 4 0x3 0x1200000a 0x4800000C 0x00000020 1>, + <&mdma1 5 0x3 0x1200000a 0x4800000C 0x00000800 1>, + <&mdma1 6 0x3 0x1200000a 0x4800000C 0x00200000 1>, + <&mdma1 7 0x3 0x1200000a 0x4800000C 0x08000000 1>; dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; @@ -1122,14 +1122,14 @@ #dma-cells = <4>; st,mem2mem; dma-requests = <8>; - dmas = <&mdma1 8 0x11 0x1200000a 0x48001008 0x00000020 1>, - <&mdma1 9 0x11 0x1200000a 0x48001008 0x00000800 1>, - <&mdma1 10 0x11 0x1200000a 0x48001008 0x00200000 1>, - <&mdma1 11 0x11 0x1200000a 0x48001008 0x08000000 1>, - <&mdma1 12 0x11 0x1200000a 0x4800100C 0x00000020 1>, - <&mdma1 13 0x11 0x1200000a 0x4800100C 0x00000800 1>, - <&mdma1 14 0x11 0x1200000a 0x4800100C 0x00200000 1>, - <&mdma1 15 0x11 0x1200000a 0x4800100C 0x08000000 1>; + dmas = <&mdma1 8 0x3 0x1200000a 0x48001008 0x00000020 1>, + <&mdma1 9 0x3 0x1200000a 0x48001008 0x00000800 1>, + <&mdma1 10 0x3 0x1200000a 0x48001008 0x00200000 1>, + <&mdma1 11 0x3 0x1200000a 0x48001008 0x08000000 1>, + <&mdma1 12 0x3 0x1200000a 0x4800100C 0x00000020 1>, + <&mdma1 13 0x3 0x1200000a 0x4800100C 0x00000800 1>, + <&mdma1 14 0x3 0x1200000a 0x4800100C 0x00200000 1>, + <&mdma1 15 0x3 0x1200000a 0x4800100C 0x08000000 1>; dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; @@ -1309,6 +1309,13 @@ interrupt-controller; #interrupt-cells = <3>; + wakeup-gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>, + <&gpioa 2 GPIO_ACTIVE_HIGH>, + <&gpioc 13 GPIO_ACTIVE_HIGH>, + <&gpioi 8 GPIO_ACTIVE_HIGH>, + <&gpioi 11 GPIO_ACTIVE_HIGH>, + <&gpioc 1 GPIO_ACTIVE_HIGH>; + pwr-regulators { compatible = "st,stm32mp1,pwr-reg"; st,tzcr = <&rcc 0x0 0x1>; @@ -1655,7 +1662,7 @@ interrupts = ; clocks = <&rcc HASH1>; resets = <&rcc HASH1_R>; - dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0>; + dmas = <&mdma1 31 0x2 0x1000A02 0x0 0x0 0x0>; dma-names = "in"; dma-maxburst = <2>; status = "disabled"; @@ -1690,22 +1697,22 @@ <0x89010000 0x1000>, <0x89020000 0x1000>; interrupts = ; - dmas = <&mdma1 20 0x10 0x12000A02 0x0 0x0 0>, - <&mdma1 20 0x10 0x12000A08 0x0 0x0 0>, - <&mdma1 21 0x10 0x12000A0A 0x0 0x0 0>; + dmas = <&mdma1 20 0x2 0x12000A02 0x0 0x0 0>, + <&mdma1 20 0x2 0x12000A08 0x0 0x0 0>, + <&mdma1 21 0x2 0x12000A0A 0x0 0x0 0>; dma-names = "tx", "rx", "ecc"; clocks = <&rcc FMC_K>; resets = <&rcc FMC_R>; status = "disabled"; }; - qspi: qspi@58003000 { + qspi: spi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; - dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, - <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; + dmas = <&mdma1 22 0x2 0x100002 0x0 0x0 0x0>, + <&mdma1 22 0x2 0x100008 0x0 0x0 0x0>; dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; From 4299e2f9d6764ec0031213009f213db72479f160 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 2 Dec 2019 17:54:19 +0100 Subject: [PATCH 202/244] Prepare v2018.11-stm32mp-r3.2 Signed-off-by: Patrick Delaunay Change-Id: I74c70e03797c1483f117940879a7fdc616d50a90 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151673 Reviewed-by: CITOOLS --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 143e7dd9543e..61d804cee422 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r3.1 +EXTRAVERSION = -stm32mp-r3.2 NAME = # *DOCUMENTATION* From 0803eb6f0a001205110ca9846a41f11f532487bd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 24 Jun 2019 15:54:19 +0200 Subject: [PATCH 203/244] stm32mp1: support of STM32MP15x Rev.Z Add support for Rev.Z of STM32MP15x cpu. Signed-off-by: Patrick Delaunay Change-Id: Ia92100c29f7ea0bac70daee811aea2d32b00773d Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/136826 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- arch/arm/mach-stm32mp/cpu.c | 3 +++ arch/arm/mach-stm32mp/include/mach/sys_proto.h | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index efe8b79a9001..42c14cdea554 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -341,6 +341,9 @@ int print_cpuinfo(void) case CPU_REVB: cpu_r = "B"; break; + case CPU_REVZ: + cpu_r = "Z"; + break; default: cpu_r = "?"; break; diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 871324b1ab2a..d15687d0b112 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -16,6 +16,7 @@ u32 get_cpu_type(void); #define CPU_REVA 0x1000 #define CPU_REVB 0x2000 +#define CPU_REVZ 0x2001 /* return CPU_REV constants */ u32 get_cpu_rev(void); From a99ea99adefeea4f85951f76480e4c19a833b743 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 13 May 2019 19:00:37 +0200 Subject: [PATCH 204/244] stm32mp1: updade cpu info for 800 MHz profile support Add support of overdrive OTP in the CPU identifier and add more STM32 MPUs Part = STM32MP151Fxx, STM32MP153Fxx, STM32MP157Fxx, STM32MP151Dxx, STM32MP153Dxx, STM32MP157Dxx The STM32MP1 series is available in 3 different lines which are pin-to-pin compatible: - STM32MP157: Dual Cortex-A7 cores, Cortex-M4 core @ 209 MHz, 3D GPU, DSI display interface and CAN FD - STM32MP153: Dual Cortex-A7 cores, Cortex-M4 core @ 209 MHz and CAN FD - STM32MP151: Single Cortex-A7 core, Cortex-M4 core @ 209 MHz Each line comes with a security option (cryptography & secure boot) & a Cortex-A frequency option : - A Basic + Cortex-A7 @ 650 MHz - C Secure Boot + HW Crypto + Cortex-A7 @ 650 MHz - D Basic + Cortex-A7 @ 800 MHz - F Secure Boot + HW Crypto + Cortex-A7 @ 800 MHz Change-Id: I7571dedb712ab25c96d11250fe0897161e7afde1 Signed-off-by: Patrick Delaunay Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133344 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrice CHOTARD --- arch/arm/mach-stm32mp/cpu.c | 18 ++++++++++++++++++ arch/arm/mach-stm32mp/include/mach/sys_proto.h | 8 +++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 42c14cdea554..5d43f0b3a617 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -291,18 +291,36 @@ int print_cpuinfo(void) /* MPUs Part Numbers */ switch (get_cpu_type()) { + case CPU_STM32MP157Fxx: + cpu_s = "157F"; + break; + case CPU_STM32MP157Dxx: + cpu_s = "157D"; + break; case CPU_STM32MP157Cxx: cpu_s = "157C"; break; case CPU_STM32MP157Axx: cpu_s = "157A"; break; + case CPU_STM32MP153Fxx: + cpu_s = "153F"; + break; + case CPU_STM32MP153Dxx: + cpu_s = "153D"; + break; case CPU_STM32MP153Cxx: cpu_s = "153C"; break; case CPU_STM32MP153Axx: cpu_s = "153A"; break; + case CPU_STM32MP151Fxx: + cpu_s = "151F"; + break; + case CPU_STM32MP151Dxx: + cpu_s = "151D"; + break; case CPU_STM32MP151Cxx: cpu_s = "151C"; break; diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index d15687d0b112..731a53e46c79 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -3,13 +3,19 @@ * Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved */ -/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit15:0)*/ +/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit7: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 +#define CPU_STM32MP157Fxx 0x05000080 +#define CPU_STM32MP157Dxx 0x05000081 +#define CPU_STM32MP153Fxx 0x050000A4 +#define CPU_STM32MP153Dxx 0x050000A5 +#define CPU_STM32MP151Fxx 0x050000AE +#define CPU_STM32MP151Dxx 0x050000AF /* return CPU_STMP32MP...Xxx constants */ u32 get_cpu_type(void); From ff234a202c563cc70ee35ad3e4ea2510602c8025 Mon Sep 17 00:00:00 2001 From: Lionel Debieve Date: Wed, 15 May 2019 10:05:07 +0200 Subject: [PATCH 205/244] ARM: dts: stm32: reduce vddcore max voltage Reduce vddcore max voltage to follow SoC specifications for 800MHz new cpu profile. Change-Id: I24ca415d48b8cce145ec659aa91ddb7828a7e792 Signed-off-by: Lionel Debieve Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/133440 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Reviewed-by: Patrice CHOTARD Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157a-dk1.dts | 2 +- arch/arm/dts/stm32mp157c-ed1.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 15fb78f20656..3eb13fd399dd 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -329,7 +329,7 @@ vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1350000>; + regulator-max-microvolt = <1325000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index c9eabc1328e6..cc2db0a46303 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -203,7 +203,7 @@ vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1350000>; + regulator-max-microvolt = <1325000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; From c25ecf17186e0977e411658d672a34aade9b67a1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 23 Jul 2019 11:51:03 +0200 Subject: [PATCH 206/244] stm32mp1: stm32prog: correctly handle buffers in create_partitions Use 8Kb bytes buffer in create_partitions to avoid stack corruption when the 1KB is not enought (with many partitions). Remove cmdbuf buffer to avoid overflow. Add protection when the 8KB-100 bytes limit is reached to detect overflow. Signed-off-by: Patrick Delaunay Change-Id: I97f97df3c557070ef9e16c801d21b8bc169d88ce Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139275 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index 8325b565c529..b1fd6d4a622a 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -842,8 +842,8 @@ static int treat_partition_list(struct stm32prog_data *data) static int create_partitions(struct stm32prog_data *data) { int offset = 0; - char cmdbuf[32]; - char buf[ENV_BUF_LEN]; + const int buflen = SZ_8K; + char *buf; char uuid[UUID_STR_LEN + 1]; unsigned char *uuid_bin; unsigned int mmc_id; @@ -851,6 +851,10 @@ static int create_partitions(struct stm32prog_data *data) bool rootfs_found; struct stm32prog_part_t *part; + buf = malloc(buflen); + if (!buf) + return -ENOMEM; + puts("partitions : "); /* initialize the selected device */ for (i = 0; i < data->dev_nb; i++) { @@ -860,7 +864,7 @@ static int create_partitions(struct stm32prog_data *data) offset = 0; rootfs_found = false; - memset(buf, 0, sizeof(buf)); + memset(buf, 0, buflen); list_for_each_entry(part, &data->dev[i].part_list, list) { /* skip eMMC boot partitions */ @@ -871,7 +875,17 @@ static int create_partitions(struct stm32prog_data *data) if (part->part_type == RAW_IMAGE) continue; - offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + if (offset + 100 > buflen) { + pr_debug("\n%s: buffer too small, %s skippped", + __func__, part->name); + continue; + } + + if (!offset) + offset += sprintf(buf, "gpt write mmc %d \"", + data->dev[i].dev_id); + + offset += snprintf(buf + offset, buflen - offset, "name=%s,start=0x%llx,size=0x%llx", part->name, part->addr, @@ -879,17 +893,17 @@ static int create_partitions(struct stm32prog_data *data) if (part->part_type == PART_BINARY) offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + buflen - offset, ",type=" LINUX_RESERVED_UUID); else offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + buflen - offset, ",type=linux"); if (part->part_type == PART_SYSTEM) offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + buflen - offset, ",bootable"); if (!rootfs_found && !strcmp(part->name, "rootfs")) { @@ -901,23 +915,21 @@ static int create_partitions(struct stm32prog_data *data) uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID); offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + buflen - offset, ",uuid=%s", uuid); } } - offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, - ";"); + offset += snprintf(buf + offset, buflen - offset, ";"); } if (offset) { - sprintf(cmdbuf, "gpt write mmc %d \"%s\"", - data->dev[i].dev_id, buf); - pr_debug("cmd: %s\n", cmdbuf); - if (run_command(cmdbuf, 0)) { - stm32prog_err("partitionning fail : %s", - cmdbuf); + offset += snprintf(buf + offset, buflen - offset, "\""); + pr_debug("\ncmd: %s\n", buf); + if (run_command(buf, 0)) { + stm32prog_err("partitionning fail : %s", buf); + free(buf); + return -1; } } @@ -926,21 +938,21 @@ static int create_partitions(struct stm32prog_data *data) part_init(data->dev[i].block_dev); #ifdef DEBUG - sprintf(cmdbuf, "gpt verify mmc %d", - data->dev[i].dev_id); - pr_debug("cmd: %s ", cmdbuf); - if (run_command(cmdbuf, 0)) + sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id); + pr_debug("\ncmd: %s", buf); + if (run_command(buf, 0)) printf("fail !\n"); else printf("OK\n"); /* TEMP : for debug, display partition */ - sprintf(cmdbuf, "part list mmc %d", - data->dev[i].dev_id); - run_command(cmdbuf, 0); + sprintf(buf, "part list mmc %d", data->dev[i].dev_id); + run_command(buf, 0); #endif } puts("done\n"); + free(buf); + return 0; } From 1c51ffe4b1fd2016f148d8ee58fc8f63e4841279 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 23 Jul 2019 11:52:59 +0200 Subject: [PATCH 207/244] stm32mp1: stm32prog rename ENV_BUF_LEN to ALT_BUF_LEN Use correct name for dfu alternate buffer max length: ALT_BUF_LEN. Signed-off-by: Patrick Delaunay Change-Id: I50c3bbbd4010c9f0228d4d5bb7e0cda2e8f7fe3b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/139276 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index b1fd6d4a622a..c6d8f14113f5 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -63,7 +63,7 @@ static const efi_guid_t uuid_mmc[3] = { }; DECLARE_GLOBAL_DATA_PTR; -#define ENV_BUF_LEN SZ_1K +#define ALT_BUF_LEN SZ_1K /* order of column in flash layout file */ enum stm32prog_col_t { @@ -964,7 +964,7 @@ static int stm32prog_alt_add(struct stm32prog_data *data, int offset = 0; char devstr[4]; char dfustr[10]; - char buf[ENV_BUF_LEN]; + char buf[ALT_BUF_LEN]; u32 size; char multiplier, type; @@ -985,7 +985,7 @@ static int stm32prog_alt_add(struct stm32prog_data *data, type = 'a';/*Readable*/ memset(buf, 0, sizeof(buf)); - offset = snprintf(buf, ENV_BUF_LEN - offset, + offset = snprintf(buf, ALT_BUF_LEN - offset, "@%s/0x%02x/1*%d%c%c ", part->name, part->id, size, multiplier, type); @@ -997,29 +997,29 @@ static int stm32prog_alt_add(struct stm32prog_data *data, dfu_size = part->size / part->dev->lba_blk_size; else dfu_size = part->size; - offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + offset += snprintf(buf + offset, ALT_BUF_LEN - offset, "raw 0x0 0x%llx", dfu_size); } else if (part->part_id < 0) { u64 nb_blk = part->size / part->dev->lba_blk_size; /* lba_blk_size, mmc->read_bl_len */ - offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + offset += snprintf(buf + offset, ALT_BUF_LEN - offset, "raw 0x%llx 0x%llx", part->addr, nb_blk); - offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + offset += snprintf(buf + offset, ALT_BUF_LEN - offset, " mmcpart %d;", -(part->part_id)); } else { if (part->part_type == PART_SYSTEM && (part->dev_type == DFU_DEV_NAND || part->dev_type == DFU_DEV_SF)) offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + ALT_BUF_LEN - offset, "partubi"); else offset += snprintf(buf + offset, - ENV_BUF_LEN - offset, + ALT_BUF_LEN - offset, "part"); - offset += snprintf(buf + offset, ENV_BUF_LEN - offset, + offset += snprintf(buf + offset, ALT_BUF_LEN - offset, " %d %d;", part->dev_id, part->part_id); @@ -1053,7 +1053,7 @@ static int stm32prog_alt_add_virt(struct dfu_entity *dfu, { int ret = 0; char devstr[4]; - char buf[ENV_BUF_LEN]; + char buf[ALT_BUF_LEN]; sprintf(devstr, "%d", phase); sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size); @@ -1112,7 +1112,7 @@ static int dfu_init_entities(struct stm32prog_data *data) ret = stm32prog_alt_add(data, dfu, part); } } else { - char buf[ENV_BUF_LEN]; + char buf[ALT_BUF_LEN]; sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000", PHASE_FLASHLAYOUT, STM32_DDR_BASE); From 5cd4de52ec96b9cf6e1b5f8ad2041bfeb434fdb0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 5 Sep 2019 16:32:36 +0200 Subject: [PATCH 208/244] board: stm32mp1: fixup the USB product id for fastboot Select a specific product id used during USB enumeration when the fastboot gadget is used. For ST Microelectronics board we are using the VID:PID = 0x0483:0x0AFB for fastboot as defined in http://www.linux-usb.org/usb.ids This patch avoid conflict when the same USB VID/PID is used for fastboot and DFU (two different protocols associated to the same PID). Signed-off-by: Patrick Delaunay Change-Id: Id25154105bef11c7ed8031aed96e7c67b1805885 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/142124 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe GUIBOUT Reviewed-by: Patrice CHOTARD Reviewed-by: Nicolas LOUBOUTIN Tested-by: Christophe GUIBOUT --- board/st/stm32mp1/stm32mp1.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 1d6cc06d0ca4..1d6a5861c29e 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -388,10 +388,15 @@ int g_dnl_board_usb_cable_connected(void) } #define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11 +#define STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM 0x0afb + int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) { if (!strcmp(name, "usb_dnl_dfu")) put_unaligned(STM32MP1_G_DNL_DFU_PRODUCT_NUM, &dev->idProduct); + else if (!strcmp(name, "usb_dnl_fastboot")) + put_unaligned(STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM, + &dev->idProduct); else put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct); From 02d5c1dfa679d63bc266b26f16e4d8784c8416aa Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 9 Sep 2019 18:19:57 +0200 Subject: [PATCH 209/244] stm32mp1: ram: increase vdd2_ddr: buck2 for 32bits LPDDR Need to increase the LPDDR2/LPDDR3 the voltage vdd2_ddr: buck2 form 1.2V to 1.25V for 32bits configuration. Signed-off-by: Patrick Delaunay Change-Id: Ifeb02af238a2e3d0407465a868761e5efd7f968b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/142535 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Nicolas LE BAYON --- arch/arm/mach-stm32mp/include/mach/ddr.h | 6 +++-- board/st/stm32mp1/board.c | 23 ++++++++++++++---- drivers/ram/stm32mp1/stm32mp1_ddr.c | 30 ++++++++++++++++++++---- include/power/stpmic1.h | 1 + 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/ddr.h b/arch/arm/mach-stm32mp/include/mach/ddr.h index b8a17cfbddb8..bfc42a7c4899 100644 --- a/arch/arm/mach-stm32mp/include/mach/ddr.h +++ b/arch/arm/mach-stm32mp/include/mach/ddr.h @@ -9,8 +9,10 @@ /* DDR power initializations */ enum ddr_type { STM32MP_DDR3, - STM32MP_LPDDR2, - STM32MP_LPDDR3, + STM32MP_LPDDR2_16, + STM32MP_LPDDR2_32, + STM32MP_LPDDR3_16, + STM32MP_LPDDR3_32, }; int board_ddr_power_init(enum ddr_type ddr_type); diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index c3d832f58489..4e35d36c76dd 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -43,6 +43,7 @@ int board_ddr_power_init(enum ddr_type ddr_type) struct udevice *dev; bool buck3_at_1800000v = false; int ret; + u32 buck2; ret = uclass_get_device_by_driver(UCLASS_PMIC, DM_GET_DRIVER(pmic_stpmic1), &dev); @@ -102,8 +103,10 @@ int board_ddr_power_init(enum ddr_type ddr_type) break; - case STM32MP_LPDDR2: - case STM32MP_LPDDR3: + case STM32MP_LPDDR2_16: + case STM32MP_LPDDR2_32: + case STM32MP_LPDDR3_16: + case STM32MP_LPDDR3_32: /* * configure VDD_DDR1 = LDO3 * Set LDO3 to 1.8V @@ -133,11 +136,23 @@ int board_ddr_power_init(enum ddr_type ddr_type) if (ret < 0) return ret; - /* VDD_DDR2 : Set BUCK2 to 1.2V */ + /* VDD_DDR2 : Set BUCK2 to 1.2V (16bits) or 1.25V (32 bits)*/ + switch (ddr_type) { + case STM32MP_LPDDR2_32: + case STM32MP_LPDDR3_32: + buck2 = STPMIC1_BUCK2_1250000V; + break; + default: + case STM32MP_LPDDR2_16: + case STM32MP_LPDDR3_16: + buck2 = STPMIC1_BUCK2_1200000V; + break; + } + ret = pmic_clrsetbits(dev, STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2), STPMIC1_BUCK_VOUT_MASK, - STPMIC1_BUCK2_1200000V); + buck2); if (ret < 0) return ret; diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index f6484da5ce20..c87882deed2d 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -855,14 +855,34 @@ void stm32mp1_ddr_init(struct ddr_info *priv, { u32 pir; int ret = -EINVAL; + char bus_width; + + switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { + case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER: + bus_width = 8; + break; + case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: + bus_width = 16; + break; + default: + bus_width = 32; + break; + } + if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) ret = board_ddr_power_init(STM32MP_DDR3); - else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) - ret = board_ddr_power_init(STM32MP_LPDDR2); - else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) - ret = board_ddr_power_init(STM32MP_LPDDR3); - + else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) { + if (bus_width == 32) + ret = board_ddr_power_init(STM32MP_LPDDR2_32); + else + ret = board_ddr_power_init(STM32MP_LPDDR2_16); + } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) { + if (bus_width == 32) + ret = board_ddr_power_init(STM32MP_LPDDR3_32); + else + ret = board_ddr_power_init(STM32MP_LPDDR3_16); + } if (ret) panic("ddr power init failed\n"); diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h index d90a1a9c9398..b5a6d5290fd4 100644 --- a/include/power/stpmic1.h +++ b/include/power/stpmic1.h @@ -37,6 +37,7 @@ #define STPMIC1_BUCK_VOUT(sel) (sel << STPMIC1_BUCK_VOUT_SHIFT) #define STPMIC1_BUCK2_1200000V STPMIC1_BUCK_VOUT(24) +#define STPMIC1_BUCK2_1250000V STPMIC1_BUCK_VOUT(26) #define STPMIC1_BUCK2_1350000V STPMIC1_BUCK_VOUT(30) #define STPMIC1_BUCK3_1800000V STPMIC1_BUCK_VOUT(39) From ec157da292d9274948b41a34db8e05b76bef2dd9 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Fri, 6 Sep 2019 17:40:01 +0200 Subject: [PATCH 210/244] mmc: add a driver callback for power-cycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some MMC peripherals require specific power cycle sequence, where some registers need to be written between the regulator is turned off and then back on. This is the case for the MMC IP embedded in STM32MP1 SoC. In STM32MP157 reference manual [1], the power cycle sequence is: 1. Reset the SDMMC with the RCC.SDMMCxRST register bit. This will reset the SDMMC to the reset state and the CPSM and DPSM to the Idle state. 2. Disable the Vcc power to the card. 3. Set the SDMMC in power-cycle state. This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven low, to prevent the card from being supplied through the signal lines. 4. After minimum 1ms enable the Vcc power to the card. 5. After the power ramp period set the SDMMC to the power-off state for minimum 1ms. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are set to drive “1”. 6. After the 1ms delay set the SDMMC to power-on state in which the SDMMC_CK clock will be enabled. 7. After 74 SDMMC_CK cycles the first command can be sent to the card. The step 3. cannot be handled by the current framework implementation. A new callback (host_power_cycle) is created, and called in mmc_power_cycle(), after mmc_power_off(). The incorrect power cycle sequence has shown some boot failures on STM32MP1 with some SD-cards, especially on cold boots when the input frequency is low (<= 25MHz). Those failures are no more seen with this correct power cycle sequence. [1] https://www.st.com/resource/en/reference_manual/DM00327659.pdf Signed-off-by: Yann Gautier Change-Id: Ie04221759e9ff16b2f47cff3818c4b9321cd3f7b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/142393 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe KERELLO Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/mmc/mmc-uclass.c | 14 ++++++++++++++ drivers/mmc/mmc.c | 15 +++++++++++++++ include/mmc.h | 13 +++++++++++++ 3 files changed, 42 insertions(+) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index f73f07254be6..79ced50c4d9e 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -120,6 +120,20 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode) } #endif +int dm_mmc_host_power_cycle(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->host_power_cycle) + return ops->host_power_cycle(dev); + return 0; +} + +int mmc_host_power_cycle(struct mmc *mmc) +{ + return dm_mmc_host_power_cycle(mmc->dev); +} + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 585951cd78e9..826565fa5406 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1486,6 +1486,16 @@ static int mmc_set_ios(struct mmc *mmc) return ret; } + +static int mmc_host_power_cycle(struct mmc *mmc) +{ + int ret = 0; + + if (mmc->cfg->ops->host_power_cycle) + ret = mmc->cfg->ops->host_power_cycle(mmc); + + return ret; +} #endif int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) @@ -2566,6 +2576,11 @@ static int mmc_power_cycle(struct mmc *mmc) ret = mmc_power_off(mmc); if (ret) return ret; + + ret = mmc_host_power_cycle(mmc); + if (ret) + return ret; + /* * SD spec recommends at least 1ms of delay. Let's wait for 2ms * to be on the safer side. diff --git a/include/mmc.h b/include/mmc.h index 95548e94c4d8..a3974a89039f 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -461,6 +461,16 @@ struct dm_mmc_ops { */ int (*wait_dat0)(struct udevice *dev, int state, int timeout); #endif + + /** + * host_power_cycle - host specific tasks in power cycle sequence + * Called between mmc_power_off() and + * mmc_power_on() + * + * @dev: Device to check + * @return 0 if not present, 1 if present, -ve on error + */ + int (*host_power_cycle)(struct udevice *dev); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -473,6 +483,7 @@ int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout); +int dm_mmc_host_power_cycle(struct udevice *dev); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); @@ -481,6 +492,7 @@ int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); int mmc_wait_dat0(struct mmc *mmc, int state, int timeout); +int mmc_host_power_cycle(struct mmc *mmc); #else struct mmc_ops { @@ -490,6 +502,7 @@ struct mmc_ops { int (*init)(struct mmc *mmc); int (*getcd)(struct mmc *mmc); int (*getwp)(struct mmc *mmc); + int (*host_power_cycle)(struct mmc *mmc); }; #endif From b3a725aba6d9f38964da51345b2644e9fb858e85 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Fri, 6 Sep 2019 17:40:08 +0200 Subject: [PATCH 211/244] mmc: stm32_sdmmc2: implement host_power_cycle callback For the correct power cycle sequence with stm32_sdmmc2, the write of the power cycle value in PWRCTL field of SDMMC_POWER register is now done in stm32_sdmmc2_host_power_cycle() and no more in stm32_sdmmc2_pwrcycle(). Signed-off-by: Yann Gautier Change-Id: I0e2b14a7529118831672e3c564a23b3e1ad98013 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/142394 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Christophe KERELLO Reviewed-by: Patrick DELAUNAY --- drivers/mmc/stm32_sdmmc2.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 32434a4762f7..1726ed72efca 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -524,8 +524,6 @@ static void stm32_sdmmc2_pwrcycle(struct stm32_sdmmc2_priv *priv) return; stm32_sdmmc2_reset(priv); - writel(SDMMC_POWER_PWRCTRL_CYCLE | priv->pwr_reg_msk, - priv->base + SDMMC_POWER); } /* @@ -619,10 +617,21 @@ static int stm32_sdmmc2_getcd(struct udevice *dev) return 1; } +static int stm32_sdmmc2_host_power_cycle(struct udevice *dev) +{ + struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); + + writel(SDMMC_POWER_PWRCTRL_CYCLE | priv->pwr_reg_msk, + priv->base + SDMMC_POWER); + + return 0; +} + static const struct dm_mmc_ops stm32_sdmmc2_ops = { .send_cmd = stm32_sdmmc2_send_cmd, .set_ios = stm32_sdmmc2_set_ios, .get_cd = stm32_sdmmc2_getcd, + .host_power_cycle = stm32_sdmmc2_host_power_cycle, }; static int stm32_sdmmc2_probe(struct udevice *dev) From bdbf4d750641cc1efda495e7669e9bfaed0bcd1c Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 23 Sep 2019 15:30:23 +0200 Subject: [PATCH 212/244] i2c: stm32f7_i2c: allows for any bus frequency Do not limitate to 3 (100KHz, 400KHz, 1MHz) bus frequencies, but instead allow for any frequency. Depending on the requested frequency (via the clock-frequency DT entry), use the spec data from either Standard, Fast or Fast Plus mode. In order to do so, the driver do not use anymore spec identifier by directly handle the requested frequency and from it retrieve the corresponding spec data to be used for the computation of the timing register. Change-Id: I44e04e48643f0d3554334318ff2111860ca0f8ab Signed-off-by: Alain Volmat Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/144006 Reviewed-by: Patrick DELAUNAY --- drivers/i2c/stm32f7_i2c.c | 116 ++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 2b18735fea6b..db363a2d4f63 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -119,13 +119,6 @@ struct stm32_i2c_regs { #define FAST_RATE 400000 #define FAST_PLUS_RATE 1000000 -enum stm32_i2c_speed { - STM32_I2C_SPEED_STANDARD, /* 100 kHz */ - STM32_I2C_SPEED_FAST, /* 400 kHz */ - STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */ - STM32_I2C_SPEED_END, -}; - /** * struct stm32_i2c_spec - private i2c specification timing * @rate: I2C bus speed (Hz) @@ -155,7 +148,6 @@ struct stm32_i2c_spec { /** * struct stm32_i2c_setup - private I2C timing setup parameters - * @speed: I2C speed mode (standard, Fast Plus) * @speed_freq: I2C speed frequency (Hz) * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) @@ -164,7 +156,6 @@ struct stm32_i2c_spec { * @analog_filter: Analog filter delay (On/Off) */ struct stm32_i2c_setup { - enum stm32_i2c_speed speed; u32 speed_freq; u32 clock_src; u32 rise_time; @@ -194,11 +185,12 @@ struct stm32_i2c_priv { struct stm32_i2c_regs *regs; struct clk clk; struct stm32_i2c_setup *setup; - int speed; + u32 speed; }; static const struct stm32_i2c_spec i2c_specs[] = { - [STM32_I2C_SPEED_STANDARD] = { + /* Standard speed - 100 KHz */ + { .rate = STANDARD_RATE, .rate_min = 8000, .rate_max = 120000, @@ -210,7 +202,8 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 4700, .h_min = 4000, }, - [STM32_I2C_SPEED_FAST] = { + /* Fast speed - 400 KHz */ + { .rate = FAST_RATE, .rate_min = 320000, .rate_max = 480000, @@ -222,7 +215,8 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 1300, .h_min = 600, }, - [STM32_I2C_SPEED_FAST_PLUS] = { + /* Fast Plus Speed - 1 MHz */ + { .rate = FAST_PLUS_RATE, .rate_min = 800000, .rate_max = 1200000, @@ -484,6 +478,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, } static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions) { struct stm32_i2c_timings *v; @@ -500,13 +495,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, af_delay_max = setup->analog_filter ? STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0; - sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - + sdadel_min = specs->hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; - sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - + sdadel_max = specs->vddat_max - setup->rise_time - af_delay_max - (setup->dnf + 4) * i2cclk; - scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min; + scldel_min = setup->rise_time + specs->sudat_min; if (sdadel_min < 0) sdadel_min = 0; @@ -558,6 +553,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, } static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions, struct stm32_i2c_timings *s) { @@ -580,8 +576,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, dnf_delay = setup->dnf * i2cclk; tsync = af_delay_min + dnf_delay + (2 * i2cclk); - clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; - clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; + clk_max = STM32_NSEC_PER_SEC / specs->rate_min; + clk_min = STM32_NSEC_PER_SEC / specs->rate_max; /* * Among Prescaler possibilities discovered above figures out SCL Low @@ -599,7 +595,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, for (l = 0; l < STM32_SCLL_MAX; l++) { u32 tscl_l = (l + 1) * prescaler + tsync; - if ((tscl_l < i2c_specs[setup->speed].l_min) || + if (tscl_l < specs->l_min || (i2cclk >= ((tscl_l - af_delay_min - dnf_delay) / 4))) { continue; @@ -611,7 +607,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, setup->rise_time + setup->fall_time; if ((tscl >= clk_min) && (tscl <= clk_max) && - (tscl_h >= i2c_specs[setup->speed].h_min) && + (tscl_h >= specs->h_min) && (i2cclk < tscl_h)) { u32 clk_error; @@ -640,26 +636,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, return ret; } +static const struct stm32_i2c_spec *get_specs(u32 rate) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) + if (rate <= i2c_specs[i].rate) + return &i2c_specs[i]; + + /* NOT REACHED */ + return ERR_PTR(-EINVAL); +} + static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_setup *setup, struct stm32_i2c_timings *output) { + const struct stm32_i2c_spec *specs; struct stm32_i2c_timings *v, *_v; struct list_head solutions; int ret; - if (setup->speed >= STM32_I2C_SPEED_END) { - pr_err("%s: speed out of bound {%d/%d}\n", __func__, - setup->speed, STM32_I2C_SPEED_END - 1); + specs = get_specs(setup->speed_freq); + if (specs == ERR_PTR(-EINVAL)) { + pr_err("%s: speed out of bound {%d}\n", __func__, + setup->speed_freq); return -EINVAL; } - if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || - (setup->fall_time > i2c_specs[setup->speed].fall_max)) { + if (setup->rise_time > specs->rise_max || + setup->fall_time > specs->fall_max) { pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", __func__, - setup->rise_time, i2c_specs[setup->speed].rise_max, - setup->fall_time, i2c_specs[setup->speed].fall_max); + setup->rise_time, specs->rise_max, + setup->fall_time, specs->fall_max); return -EINVAL; } @@ -669,18 +679,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, return -EINVAL; } - if (setup->speed_freq > i2c_specs[setup->speed].rate) { - pr_err("%s: Freq {%d/%d}\n", __func__, - setup->speed_freq, i2c_specs[setup->speed].rate); - return -EINVAL; - } - INIT_LIST_HEAD(&solutions); - ret = stm32_i2c_compute_solutions(setup, &solutions); + ret = stm32_i2c_compute_solutions(setup, specs, &solutions); if (ret) goto exit; - ret = stm32_i2c_choose_solution(setup, &solutions, output); + ret = stm32_i2c_choose_solution(setup, specs, &solutions, output); if (ret) goto exit; @@ -699,14 +703,24 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, return ret; } +static u32 get_lower_rate(u32 rate) +{ + int i; + + for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) + if (rate > i2c_specs[i].rate) + return i2c_specs[i].rate; + + return i2c_specs[0].rate; +} + static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_timings *timing) { struct stm32_i2c_setup *setup = i2c_priv->setup; int ret = 0; - setup->speed = i2c_priv->speed; - setup->speed_freq = i2c_specs[setup->speed].rate; + setup->speed_freq = i2c_priv->speed; setup->clock_src = clk_get_rate(&i2c_priv->clk); if (!setup->clock_src) { @@ -719,13 +733,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, if (ret) { debug("%s: failed to compute I2C timings.\n", __func__); - if (i2c_priv->speed > STM32_I2C_SPEED_STANDARD) { - i2c_priv->speed--; - setup->speed = i2c_priv->speed; + if (setup->speed_freq > STANDARD_RATE) { setup->speed_freq = - i2c_specs[setup->speed].rate; + get_lower_rate(setup->speed_freq); debug("%s: downgrade I2C Speed Freq to (%i)\n", - __func__, i2c_specs[setup->speed].rate); + __func__, setup->speed_freq); } else { break; } @@ -737,13 +749,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, return ret; } - debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__, - setup->speed, setup->speed_freq, setup->clock_src); + debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__, + setup->speed_freq, setup->clock_src); debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__, setup->rise_time, setup->fall_time); debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__, setup->analog_filter ? "On" : "Off", setup->dnf); + i2c_priv->speed = setup->speed_freq; + return 0; } @@ -783,21 +797,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus); - switch (speed) { - case STANDARD_RATE: - i2c_priv->speed = STM32_I2C_SPEED_STANDARD; - break; - case FAST_RATE: - i2c_priv->speed = STM32_I2C_SPEED_FAST; - break; - case FAST_PLUS_RATE: - i2c_priv->speed = STM32_I2C_SPEED_FAST_PLUS; - break; - default: + if (speed > FAST_PLUS_RATE) { debug("%s: Speed %d not supported\n", __func__, speed); return -EINVAL; } + i2c_priv->speed = speed; + return stm32_i2c_hw_config(i2c_priv); } From 4d084310cafbaff7271006a39581ff209e0a3a63 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 23 Sep 2019 09:48:07 +0200 Subject: [PATCH 213/244] remoteproc: store resource table address and size When rproc-uclass rproc_load_rsc_table() is called, store the address and the size of the resource table in the private data, so these information can be used by the drivers. Change-Id: I6b4f0de4ff9876856e24388c80a01af4b1228241 Signed-off-by: Fabien Dessenne Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143686 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Arnaud POULIQUEN Reviewed-by: Patrick DELAUNAY --- drivers/remoteproc/rproc-uclass.c | 32 ++++++++++++++++++------------- include/remoteproc.h | 11 +++++++++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index a817bc0507c5..89eed8c4a51c 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -244,6 +244,7 @@ UCLASS_DRIVER(rproc) = { .flags = DM_UC_FLAG_SEQ_ALIAS, .pre_probe = rproc_pre_probe, .post_probe = rproc_post_probe, + .per_device_auto_alloc_size = sizeof(struct rproc_priv), .per_device_platdata_auto_alloc_size = sizeof(struct dm_rproc_uclass_pdata), }; @@ -624,6 +625,7 @@ int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr, { struct udevice *dev = NULL; const struct dm_rproc_ops *ops; + struct rproc_priv *priv; int ret; ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); @@ -639,23 +641,27 @@ int rproc_load_rsc_table(int id, ulong addr, ulong size, ulong *rsc_addr, return -EINVAL; } - dev_dbg(dev, "Loocking for resource table from address 0x%08lX size of %lu bytes\n", + dev_dbg(dev, "Looking for resource table from address 0x%08lX size of %lu bytes\n", addr, size); - if (!rproc_elf_sanity_check(dev, addr, size)) { - /* load elf image */ - ret = rproc_elf_find_load_rsc_table(dev, addr, size, rsc_addr, - rsc_size); - if (ret) { - dev_dbg(dev, "No resource table found\n"); - return -ENODATA; - } - dev_dbg(dev, "Resource table at 0x%08lx, size 0x%x!\n", - *rsc_addr, *rsc_size); - return 0; + ret = rproc_elf_sanity_check(dev, addr, size); + if (ret) + return ret; + + ret = rproc_elf_find_load_rsc_table(dev, addr, size, rsc_addr, + rsc_size); + if (ret) { + dev_dbg(dev, "No resource table found\n"); + return -ENODATA; } - return -ENODATA; + priv = dev_get_uclass_priv(dev); + priv->rsc_table_addr = *rsc_addr; + priv->rsc_table_size = *rsc_size; + dev_dbg(dev, "Resource table at 0x%08lx, size 0x%x!\n", + priv->rsc_table_addr, priv->rsc_table_size); + + return 0; }; /* diff --git a/include/remoteproc.h b/include/remoteproc.h index fa82531b9b51..e25702b4b7fc 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -44,6 +44,17 @@ struct dm_rproc_uclass_pdata { void *driver_plat_data; }; +/** + * struct rproc_priv - Device information used by the rproc uclass + * + * @rsc_table_addr: Resource Table address (if any) + * @rsc_table_size: Resource Table size + */ +struct rproc_priv { + ulong rsc_table_addr; + unsigned int rsc_table_size; +}; + /** * struct dm_rproc_ops - Operations that are provided by remote proc driver * @init: Initialize the remoteproc device invoked after probe (optional) From 88dfe17619c4fdb606c1099fec076d2d7be6128c Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 23 Sep 2019 15:15:24 +0200 Subject: [PATCH 214/244] stm32mp1: declare backup register for copro resource table address Use the backup register #17 as coprocessor resource table address. Change-Id: I9d52bab22058735c7790a38f165f88f074322304 Signed-off-by: Fabien Dessenne Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143687 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/include/mach/stm32.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 5283e902a15a..70fb235232e3 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -96,6 +96,7 @@ enum boot_device { #define TAMP_BACKUP_MAGIC_NUMBER TAMP_BACKUP_REGISTER(4) #define TAMP_BACKUP_BRANCH_ADDRESS TAMP_BACKUP_REGISTER(5) /* non secure access */ +#define TAMP_COPRO_RSC_TBL_ADDRESS TAMP_BACKUP_REGISTER(17) #define TAMP_BOOT_CONTEXT TAMP_BACKUP_REGISTER(20) #define TAMP_BOOTCOUNT TAMP_BACKUP_REGISTER(21) From 71d5ed8066b1edc8bde4b13737c07f2700fe107b Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 23 Sep 2019 15:16:55 +0200 Subject: [PATCH 215/244] remoteproc: stm32: store resource table address in backup register Store the firmware resource table address in the dedicated backup register. Change-Id: I55a3f20f5fe2a6138a57d1d1c506422473648189 Signed-off-by: Fabien Dessenne Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143688 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/remoteproc/stm32_copro.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 0a8b90017a78..9fed8c8d8eef 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -12,6 +12,7 @@ #include #include #include +#include #define RCC_GCR_HOLD_BOOT 0 #define RCC_GCR_RELEASE_BOOT 1 @@ -202,6 +203,7 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) */ static int stm32_copro_start(struct udevice *dev) { + struct rproc_priv *uc_priv = dev_get_uclass_priv(dev); int ret; /* move hold boot from true to false start the copro */ @@ -213,7 +215,12 @@ static int stm32_copro_start(struct udevice *dev) * Once copro running, reset hold boot flag to avoid copro * rebooting autonomously */ - return stm32_copro_set_hold_boot(dev, true); + ret = stm32_copro_set_hold_boot(dev, true); + if (!ret) + /* Store rsc_address in bkp register */ + writel(uc_priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS); + + return ret; } /** From 658e38f1a76771ba64427fadf7697fab90cb6879 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 23 Sep 2019 15:17:21 +0200 Subject: [PATCH 216/244] stm32mp1: do not fixup the DeviceTree with coproc_rsc_addr/size Do not update the DeviceTree with the coproc_rsc_addr/size properties as this is no more required now that stm32_copro writes the resource table address in a backup register. Also consider some more error cases. Change-Id: I13fa076ba9d138ab510e88601b858ec0d359c55c Signed-off-by: Fabien Dessenne Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143689 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 27 ++++++++------------------- cmd/remoteproc.c | 4 ---- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 1d6a5861c29e..e09b39f47efe 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1085,9 +1085,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts) #if defined(CONFIG_OF_BOARD_SETUP) int ft_board_setup(void *blob, bd_t *bd) { - ulong copro_rsc_addr, copro_rsc_size; int off; - char *s_copro = NULL; #ifdef CONFIG_FDT_FIXUP_PARTITIONS struct node_info nodes[] = { { "st,stm32f469-qspi", MTD_DEV_TYPE_NOR, }, @@ -1099,20 +1097,11 @@ int ft_board_setup(void *blob, bd_t *bd) /* Update DT if coprocessor started */ off = fdt_path_offset(blob, "/m4"); if (off > 0) { - s_copro = env_get("copro_state"); - copro_rsc_addr = env_get_hex("copro_rsc_addr", 0); - copro_rsc_size = env_get_hex("copro_rsc_size", 0); - - if (s_copro) { + if (env_get("copro_state")) { fdt_setprop_empty(blob, off, "early-booted"); - if (copro_rsc_addr) - fdt_setprop_u32(blob, off, "rsc-address", - copro_rsc_addr); - if (copro_rsc_size) - fdt_setprop_u32(blob, off, "rsc-size", - copro_rsc_size); } else { fdt_delprop(blob, off, "early-booted"); + writel(0, TAMP_COPRO_RSC_TBL_ADDRESS); } } @@ -1134,18 +1123,18 @@ static void board_stm32copro_image_process(ulong fw_image, size_t fw_size) } ret = rproc_load_rsc_table(id, fw_image, fw_size, &rsc_addr, &rsc_size); - if (!ret) { - env_set_hex("copro_rsc_addr", rsc_addr); - env_set_hex("copro_rsc_size", rsc_size); - } + if (ret && ret != -ENODATA) + return; ret = rproc_load(id, fw_image, fw_size); printf("Load Remote Processor %d with data@addr=0x%08lx %u bytes:%s\n", id, fw_image, fw_size, ret ? " Failed!" : " Success!"); if (!ret) { - rproc_start(id); - env_set("copro_state", "booted"); + ret = rproc_start(id); + printf("Start firmware:%s\n", ret ? " Failed!" : " Success!"); + if (!ret) + env_set("copro_state", "booted"); } } diff --git a/cmd/remoteproc.c b/cmd/remoteproc.c index 755e9331f43c..56650320a46b 100644 --- a/cmd/remoteproc.c +++ b/cmd/remoteproc.c @@ -177,10 +177,6 @@ static int do_remoteproc_load_rsc_table(cmd_tbl_t *cmdtp, int flag, int argc, } ret = rproc_load_rsc_table(id, addr, size, &rsc_addr, &rsc_size); - if (!ret) { - env_set_hex("copro_rsc_addr", rsc_addr); - env_set_hex("copro_rsc_size", rsc_size); - } printf("Remote Processor %d resource table %s : 0x%08lx-0x%x\n", id, ret ? "Not found" : "Found", ret ? 0 : rsc_addr, From a0162f45e272d488dd47c95dc6c2f862a22ea04e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 20 Sep 2019 11:13:10 +0200 Subject: [PATCH 217/244] stm32mp1: reset halt workaround: extend SoC revision check Not only version 0x20000500 but also 0x20010500 needs the same workaround. Modify the mask to include the second version in the check. Signed-off-by: Antonio Borneo Change-Id: I5e8adfe8b70fdeeca03c89c5d1bae9be43f99db1 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143706 Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S index 37a1b062d16d..d17a37a8d967 100644 --- a/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S +++ b/arch/arm/mach-stm32mp/stm32mp1_helper_dbg.S @@ -10,6 +10,9 @@ * fixes the limitation. Anyway, this source code identifies the Soc revision * and is only executed if it corresponds, so it can be kept on other * revisions without any consequence. + * The revisions that need the workaround have ID values: + * - 0x2000X500 + * - 0x2001X500 ****************************************************************************/ #include @@ -30,7 +33,7 @@ #define PWR_CR1_DBP BIT(8) #define DBGMCU_IDC_ADDR 0x50081000 -#define DBGMCU_IDC_MASK 0xFFFF0FFF +#define DBGMCU_IDC_MASK 0xFFFE0FFF #define DBGMCU_IDC_VALUE 0x20000500 #define TAMP_BKP_REGISTER_20 (0x5C00A100 + (20 << 2)) From 37045967c3228ec1828204351b8a5bcb172846e4 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Thu, 12 Sep 2019 17:22:59 +0200 Subject: [PATCH 218/244] net: dwc_et_qos: implement phy-reset-gpios for stm32 Add management of property "phy-reset-gpios" to configure any GPIO used to reset the PHY Change-Id: If510c11ecfdf4e33feded847da6899b99e75df75 Signed-off-by: Christophe Roullier Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/143175 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/net/dwc_eth_qos.c | 47 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 5b933fb0d326..d8887c17a9b0 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -692,6 +692,30 @@ static int eqos_start_resets_tegra186(struct udevice *dev) static int eqos_start_resets_stm32(struct udevice *dev) { + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", + ret); + return ret; + } + + udelay(2); + + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", + ret); + return ret; + } + } + + debug("%s: OK\n", __func__); return 0; } @@ -707,6 +731,11 @@ static int eqos_stop_resets_tegra186(struct udevice *dev) static int eqos_stop_resets_stm32(struct udevice *dev) { + struct eqos_priv *eqos = dev_get_priv(dev); + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) + dm_gpio_set_value(&eqos->phy_reset_gpio, 1); + return 0; } @@ -1604,7 +1633,7 @@ static int eqos_probe_resources_stm32(struct udevice *dev) int interface; bool eth_clk_sel_reg = false; bool eth_ref_clk_sel_reg = false; - + struct ofnode_phandle_args phandle_args; debug("%s(dev=%p):\n", __func__, dev); @@ -1650,6 +1679,19 @@ static int eqos_probe_resources_stm32(struct udevice *dev) if (ret) pr_warn("No phy clock provided %d", ret); + /* search "reset-gpios" in phy node */ + ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args); + if (!ret) { + ret = gpio_request_by_name_nodev(phandle_args.node, + "reset-gpios", 0, + &eqos->phy_reset_gpio, + GPIOD_IS_OUT | + GPIOD_IS_OUT_ACTIVE); + } + if (ret) + pr_warn("gpio_request_by_name(phy reset) not provided %d", ret); + debug("%s: OK\n", __func__); return 0; @@ -1713,6 +1755,9 @@ static int eqos_remove_resources_stm32(struct udevice *dev) if (clk_valid(&eqos->clk_ck)) clk_free(&eqos->clk_ck); + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) + dm_gpio_free(dev, &eqos->phy_reset_gpio); + debug("%s: OK\n", __func__); return 0; } From b7db3619f8ced77f3140dfe95c9e35d0778bc5c3 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 8 Oct 2019 11:05:08 +0200 Subject: [PATCH 219/244] dts: stm32: alignment with v4.19-stm32mp-r3 Device tree alignment with Kernel v4.19-stm32mp-r3 Change-Id: I30f44f7f4c0558c17ba6106668e6aaa593809507 Signed-off-by: Patrice Chotard Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/145708 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157a-dk1.dts | 34 +- arch/arm/dts/stm32mp157c-dk2.dts | 4 +- arch/arm/dts/stm32mp157c-ed1.dts | 27 +- arch/arm/dts/stm32mp157c-ev1.dts | 8 +- arch/arm/dts/stm32mp157c-m4-srm.dtsi | 525 ++++++++++++++++++++ arch/arm/dts/stm32mp157c.dtsi | 52 +- include/dt-bindings/mfd/st,stpmic1.h | 4 + include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + 8 files changed, 627 insertions(+), 28 deletions(-) diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts index 3eb13fd399dd..9ec45de3c664 100644 --- a/arch/arm/dts/stm32mp157a-dk1.dts +++ b/arch/arm/dts/stm32mp157a-dk1.dts @@ -7,8 +7,8 @@ /dts-v1/; #include "stm32mp157c.dtsi" -#include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157cac-pinctrl.dtsi" +#include "stm32mp157c-m4-srm.dtsi" #include #include @@ -162,6 +162,14 @@ status = "okay"; }; +&cpu0{ + cpu-supply = <&vddcore>; +}; + +&cpu1{ + cpu-supply = <&vddcore>; +}; + &dma1 { sram = <&dma_pool>; }; @@ -252,9 +260,6 @@ reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; interrupts = <1 IRQ_TYPE_EDGE_FALLING>; interrupt-parent = <&gpiog>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <<dc_pins_a>; - pinctrl-1 = <<dc_pins_sleep_a>; status = "okay"; ports { @@ -284,6 +289,7 @@ pinctrl-1 = <&i2c4_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; + clock-frequency = <400000>; status = "okay"; /delete-property/dmas; /delete-property/dma-names; @@ -312,10 +318,7 @@ interrupt-controller; #interrupt-cells = <2>; status = "okay"; - - st,main-control-register = <0x04>; - st,vin-control-register = <0xc0>; - st,usb-control-register = <0x20>; + wakeup-source; regulators { compatible = "st,stpmic1-regulators"; @@ -329,7 +332,7 @@ vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1325000>; + regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; @@ -427,20 +430,20 @@ vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - regulator-active-discharge; }; vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; onkey { compatible = "st,stpmic1-onkey"; - interrupts = , ; + interrupts = , ; interrupt-names = "onkey-falling", "onkey-rising"; + power-off-time-sec = <10>; status = "okay"; }; @@ -487,6 +490,9 @@ }; <dc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <<dc_pins_a>; + pinctrl-1 = <<dc_pins_sleep_a>; status = "okay"; port { @@ -703,6 +709,8 @@ pinctrl-1 = <&uart4_sleep_pins_a>; pinctrl-2 = <&uart4_idle_pins_a>; pinctrl-3 = <&uart4_pins_a>; + /delete-property/dmas; + /delete-property/dma-names; status = "okay"; }; @@ -711,6 +719,8 @@ pinctrl-0 = <&uart7_pins_a>; pinctrl-1 = <&uart7_sleep_pins_a>; pinctrl-2 = <&uart7_idle_pins_a>; + /delete-property/dmas; + /delete-property/dma-names; status = "disabled"; }; diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts index d11fbb8c5386..5523dc3b1595 100644 --- a/arch/arm/dts/stm32mp157c-dk2.dts +++ b/arch/arm/dts/stm32mp157c-dk2.dts @@ -47,7 +47,7 @@ }; }; - panel@0 { + panel: panel@0 { compatible = "orisetech,otm8009a"; reg = <0>; reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; @@ -71,6 +71,7 @@ interrupt-controller; touchscreen-size-x = <480>; touchscreen-size-y = <800>; + panel = <&panel>; status = "okay"; }; touchscreen@38 { @@ -81,6 +82,7 @@ interrupt-controller; touchscreen-size-x = <480>; touchscreen-size-y = <800>; + panel = <&panel>; status = "okay"; }; }; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index cc2db0a46303..f5e685d51caf 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -6,8 +6,8 @@ /dts-v1/; #include "stm32mp157c.dtsi" -#include "stm32mp157c-m4-srm.dtsi" #include "stm32mp157caa-pinctrl.dtsi" +#include "stm32mp157c-m4-srm.dtsi" #include / { @@ -137,6 +137,14 @@ }; }; +&cpu0{ + cpu-supply = <&vddcore>; +}; + +&cpu1{ + cpu-supply = <&vddcore>; +}; + &dac { pinctrl-names = "default"; pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; @@ -173,6 +181,7 @@ pinctrl-1 = <&i2c4_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; + clock-frequency = <400000>; status = "okay"; /delete-property/dmas; /delete-property/dma-names; @@ -184,14 +193,10 @@ interrupt-controller; #interrupt-cells = <2>; status = "okay"; - - st,main-control-register = <0x04>; - st,vin-control-register = <0xc0>; - st,usb-control-register = <0x20>; + wakeup-source; regulators { compatible = "st,stpmic1-regulators"; - ldo1-supply = <&v3v3>; ldo2-supply = <&v3v3>; ldo3-supply = <&vdd_ddr>; @@ -203,7 +208,7 @@ vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1325000>; + regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; @@ -295,20 +300,20 @@ vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - regulator-active-discharge; }; vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; onkey { compatible = "st,stpmic1-onkey"; - interrupts = , ; + interrupts = , ; interrupt-names = "onkey-falling", "onkey-rising"; + power-off-time-sec = <10>; status = "okay"; }; @@ -408,6 +413,8 @@ pinctrl-1 = <&uart4_sleep_pins_a>; pinctrl-2 = <&uart4_idle_pins_a>; pinctrl-3 = <&uart4_pins_a>; + /delete-property/dmas; + /delete-property/dma-names; status = "okay"; }; diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index bcb103979b13..7323f40afcfe 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -98,7 +98,7 @@ }; }; - sound { + sound: sound { compatible = "audio-graph-card"; label = "STM32MP1-EV"; routing = @@ -325,7 +325,7 @@ }; }; - panel-dsi@0 { + panel_dsi: panel-dsi@0 { compatible = "raydium,rm68200"; reg = <0>; reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; @@ -495,6 +495,7 @@ gt9147: goodix_ts@5d { compatible = "goodix,gt9147"; reg = <0x5d>; + panel = <&panel_dsi>; status = "okay"; irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; @@ -647,8 +648,9 @@ }; &spdifrx { - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&spdifrx_pins_a>; + pinctrl-1 = <&spdifrx_pins_a>; status = "okay"; spdifrx_port: port { diff --git a/arch/arm/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/dts/stm32mp157c-m4-srm.dtsi index 9ea97369ddff..4d641a99c14e 100644 --- a/arch/arm/dts/stm32mp157c-m4-srm.dtsi +++ b/arch/arm/dts/stm32mp157c-m4-srm.dtsi @@ -1,3 +1,528 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Fabien Dessenne for STMicroelectronics. + */ + +&pinctrl { + m4_adc1_in6_pins_a: m4-adc1-in6 { + pins { + pinmux = ; + }; + }; + + m4_adc12_ain_pins_a: m4-adc12-ain-0 { + pins { + pinmux = , /* ADC1 in13 */ + , /* ADC1 in6 */ + , /* ADC2 in2 */ + ; /* ADC2 in6 */ + }; + }; + + m4_adc12_usb_pwr_pins_a: m4-adc12-usb-pwr-pins-0 { + pins { + pinmux = , /* ADC12 in18 */ + ; /* ADC12 in19 */ + }; + }; + + m4_cec_pins_a: m4-cec-0 { + pins { + pinmux = ; + }; + }; + + m4_cec_pins_b: m4-cec-1 { + pins { + pinmux = ; + }; + }; + + m4_dac_ch1_pins_a: m4-dac-ch1 { + pins { + pinmux = ; + }; + }; + + m4_dac_ch2_pins_a: m4-dac-ch2 { + pins { + pinmux = ; + }; + }; + + m4_dcmi_pins_a: m4-dcmi-0 { + pins { + pinmux = ,/* DCMI_HSYNC */ + ,/* DCMI_VSYNC */ + ,/* DCMI_PIXCLK */ + ,/* DCMI_D0 */ + ,/* DCMI_D1 */ + ,/* DCMI_D2 */ + ,/* DCMI_D3 */ + ,/* DCMI_D4 */ + ,/* DCMI_D5 */ + ,/* DCMI_D6 */ + ,/* DCMI_D7 */ + ,/* DCMI_D8 */ + ,/* DCMI_D9 */ + ,/* DCMI_D10 */ + ;/* DCMI_D11 */ + }; + }; + + m4_dfsdm_clkout_pins_a: m4-dfsdm-clkout-pins-0 { + pins { + pinmux = ; /* DFSDM_CKOUT */ + }; + }; + + m4_dfsdm_data1_pins_a: m4-dfsdm-data1-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA1 */ + }; + }; + + m4_dfsdm_data3_pins_a: m4-dfsdm-data3-pins-0 { + pins { + pinmux = ; /* DFSDM_DATA3 */ + }; + }; + + m4_ethernet0_rgmii_pins_a: m4-rgmii-0 { + pins { + 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_MDC */ + , /* ETH_MDIO */ + , /* ETH_RGMII_RXD0 */ + , /* ETH_RGMII_RXD1 */ + , /* ETH_RGMII_RXD2 */ + , /* ETH_RGMII_RXD3 */ + , /* ETH_RGMII_RX_CLK */ + ; /* ETH_RGMII_RX_CTL */ + }; + }; + + m4_fmc_pins_a: m4-fmc-0 { + pins { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + , /* FMC_NE2_FMC_NCE */ + ; /* FMC_NWAIT */ + }; + }; + + m4_hdp0_pins_a: m4-hdp0-0 { + pins { + pinmux = ; /* HDP0 */ + }; + }; + + m4_hdp6_pins_a: m4-hdp6-0 { + pins { + pinmux = ; /* HDP6 */ + }; + }; + + m4_hdp7_pins_a: m4-hdp7-0 { + pins { + pinmux = ; /* HDP7 */ + }; + }; + + m4_i2c1_pins_a: m4-i2c1-0 { + pins { + pinmux = , /* I2C1_SCL */ + ; /* I2C1_SDA */ + }; + }; + + m4_i2c2_pins_a: m4-i2c2-0 { + pins { + pinmux = , /* I2C2_SCL */ + ; /* I2C2_SDA */ + }; + }; + + m4_i2c5_pins_a: m4-i2c5-0 { + pins { + pinmux = , /* I2C5_SCL */ + ; /* I2C5_SDA */ + }; + }; + + m4_i2s2_pins_a: m4-i2s2-0 { + pins { + pinmux = , /* I2S2_SDO */ + , /* I2S2_WS */ + ; /* I2S2_CK */ + }; + }; + + m4_ltdc_pins_a: m4-ltdc-a-0 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + }; + }; + + m4_ltdc_pins_b: m4-ltdc-b-0 { + pins { + pinmux = , /* LCD_CLK */ + , /* LCD_HSYNC */ + , /* LCD_VSYNC */ + , /* LCD_DE */ + , /* LCD_R0 */ + , /* LCD_R1 */ + , /* LCD_R2 */ + , /* LCD_R3 */ + , /* LCD_R4 */ + , /* LCD_R5 */ + , /* LCD_R6 */ + , /* LCD_R7 */ + , /* LCD_G0 */ + , /* LCD_G1 */ + , /* LCD_G2 */ + , /* LCD_G3 */ + , /* LCD_G4 */ + , /* LCD_G5 */ + , /* LCD_G6 */ + , /* LCD_G7 */ + , /* LCD_B0 */ + , /* LCD_B1 */ + , /* LCD_B2 */ + , /* LCD_B3 */ + , /* LCD_B4 */ + , /* LCD_B5 */ + , /* LCD_B6 */ + ; /* LCD_B7 */ + }; + }; + + m4_m_can1_pins_a: m4-m-can1-0 { + pins { + pinmux = , /* CAN1_TX */ + ; /* CAN1_RX */ + }; + }; + + m4_pwm1_pins_a: m4-pwm1-0 { + pins { + pinmux = , /* TIM1_CH1 */ + , /* TIM1_CH2 */ + ; /* TIM1_CH4 */ + }; + }; + + m4_pwm2_pins_a: m4-pwm2-0 { + pins { + pinmux = ; /* TIM2_CH4 */ + }; + }; + + m4_pwm3_pins_a: m4-pwm3-0 { + pins { + pinmux = ; /* TIM3_CH2 */ + }; + }; + + m4_pwm4_pins_a: m4-pwm4-0 { + pins { + pinmux = , /* TIM4_CH3 */ + ; /* TIM4_CH4 */ + }; + }; + + m4_pwm4_pins_b: m4-pwm4-1 { + pins { + pinmux = ; /* TIM4_CH2 */ + }; + }; + + m4_pwm5_pins_a: m4-pwm5-0 { + pins { + pinmux = ; /* TIM5_CH2 */ + }; + }; + + m4_pwm8_pins_a: m4-pwm8-0 { + pins { + pinmux = ; /* TIM8_CH4 */ + }; + }; + + m4_pwm12_pins_a: m4-pwm12-0 { + pins { + pinmux = ; /* TIM12_CH1 */ + }; + }; + + m4_qspi_bk1_pins_a: m4-qspi-bk1-0 { + pins { + pinmux = , /* QSPI_BK1_IO0 */ + , /* QSPI_BK1_IO1 */ + , /* QSPI_BK1_IO2 */ + , /* QSPI_BK1_IO3 */ + ; /* QSPI_BK1_NCS */ + }; + }; + + m4_qspi_bk2_pins_a: m4-qspi-bk2-0 { + pins { + pinmux = , /* QSPI_BK2_IO0 */ + , /* QSPI_BK2_IO1 */ + , /* QSPI_BK2_IO2 */ + , /* QSPI_BK2_IO3 */ + ; /* QSPI_BK2_NCS */ + }; + }; + + m4_qspi_clk_pins_a: m4-qspi-clk-0 { + pins { + pinmux = ; /* QSPI_CLK */ + }; + }; + + m4_rtc_out2_rmp_pins_a: m4-rtc-out2-rmp-pins-0 { + pins { + pinmux = ; /* RTC_OUT2_RMP */ + }; + }; + + m4_sai2a_pins_a: m4-sai2a-0 { + pins { + pinmux = , /* SAI2_SCK_A */ + , /* SAI2_SD_A */ + , /* SAI2_FS_A */ + ; /* SAI2_MCLK_A */ + }; + }; + + m4_sai2b_pins_a: m4-sai2b-0 { + pins { + pinmux = , /* SAI2_SCK_B */ + , /* SAI2_FS_B */ + , /* SAI2_MCLK_B */ + ; /* SAI2_SD_B */ + }; + }; + + m4_sai2b_pins_b: m4-sai2b-2 { + pins { + pinmux = ; /* SAI2_SD_B */ + }; + }; + + m4_sai4a_pins_a: m4-sai4a-0 { + pins { + pinmux = ; /* SAI4_SD_A */ + }; + }; + + m4_sdmmc1_b4_pins_a: m4-sdmmc1-b4-0 { + pins { + pinmux = , /* SDMMC1_D0 */ + , /* SDMMC1_D1 */ + , /* SDMMC1_D2 */ + , /* SDMMC1_D3 */ + , /* SDMMC1_CMD */ + ; /* SDMMC1_CK */ + }; + }; + + m4_sdmmc1_dir_pins_a: m4-sdmmc1-dir-0 { + pins { + pinmux = , /* SDMMC1_D0DIR */ + , /* SDMMC1_D123DIR */ + , /* SDMMC1_CDIR */ + ; /* SDMMC1_CKIN */ + }; + }; + + m4_sdmmc2_b4_pins_a: m4-sdmmc2-b4-0 { + pins { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ + , /* SDMMC2_CMD */ + ; /* SDMMC2_CK */ + }; + }; + + m4_sdmmc2_b4_pins_b: m4-sdmmc2-b4-1 { + pins { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ + , /* SDMMC2_CMD */ + ; /* SDMMC2_CK */ + }; + }; + + m4_sdmmc2_d47_pins_a: m4-sdmmc2-d47-0 { + pins { + pinmux = , /* SDMMC2_D4 */ + , /* SDMMC2_D5 */ + , /* SDMMC2_D6 */ + ; /* SDMMC2_D7 */ + }; + }; + + m4_sdmmc3_b4_pins_a: m4-sdmmc3-b4-0 { + pins { + pinmux = , /* SDMMC3_D0 */ + , /* SDMMC3_D1 */ + , /* SDMMC3_D2 */ + , /* SDMMC3_D3 */ + , /* SDMMC3_CMD */ + ; /* SDMMC3_CK */ + }; + }; + + m4_spdifrx_pins_a: m4-spdifrx-0 { + pins { + pinmux = ; /* SPDIF_IN1 */ + }; + }; + + m4_spi4_pins_a: m4-spi4-0 { + pins { + pinmux = , /* SPI4_SCK */ + , /* SPI4_MOSI */ + ; /* SPI4_MISO */ + }; + }; + + m4_spi5_pins_a: m4-spi5-0 { + pins { + pinmux = , /* SPI5_SCK */ + , /* SPI5_MOSI */ + ; /* SPI5_MISO */ + }; + }; + + m4_stusb1600_pins_a: m4-stusb1600-0 { + pins { + pinmux = ; + }; + }; + + m4_uart4_pins_a: m4-uart4-0 { + pins { + pinmux = , /* UART4_TX */ + ; /* UART4_RX */ + }; + }; + + m4_uart7_pins_a: m4-uart7-0 { + pins { + pinmux = , /* USART7_TX */ + ; /* USART7_RX */ + }; + }; + + m4_usart2_pins_a: m4-usart2-0 { + pins { + pinmux = , /* USART2_TX */ + , /* USART2_RTS */ + , /* USART2_RX */ + ; /* USART2_CTS_NSS */ + }; + }; + + m4_usart3_pins_a: m4-usart3-0 { + pins { + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + , /* USART3_RX */ + ; /* USART3_CTS_NSS */ + }; + }; + + m4_usart3_pins_b: m4-usart3-1 { + pins { + pinmux = , /* USART3_TX */ + , /* USART3_RTS */ + , /* USART3_RX */ + ; /* USART3_CTS_NSS */ + }; + }; + + m4_usbotg_hs_pins_a: m4-usbotg_hs-0 { + pins { + pinmux = ; /* OTG_ID */ + }; + }; + + m4_usbotg_fs_dp_dm_pins_a: m4-usbotg-fs-dp-dm-0 { + pins { + pinmux = , /* OTG_FS_DM */ + ; /* OTG_FS_DP */ + }; + }; +}; + +&pinctrl_z { + m4_i2c4_pins_a: m4-i2c4-0 { + pins { + pinmux = , /* I2C4_SCL */ + ; /* I2C4_SDA */ + }; + }; + + m4_spi1_pins_a: m4-spi1-0 { + pins { + pinmux = , /* SPI1_SCK */ + , /* SPI1_MOSI */ + ; /* SPI1_MISO */ + }; + }; +}; + &m4_rproc { m4_system_resources { #address-cells = <1>; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 80081dde4ebc..d56e0f98475c 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -20,14 +20,36 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; - clock-frequency = <650000000>; + clocks = <&rcc CK_MPU>; + clock-names = "cpu"; + operating-points-v2 = <&cpu0_opp_table>; + nvmem-cells = <&part_number_otp>; + nvmem-cell-names = "part_number"; }; cpu1: cpu@1 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <1>; - clock-frequency = <650000000>; + clocks = <&rcc CK_MPU>; + clock-names = "cpu"; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: cpu0-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + opp-microvolt = <1200000>; + opp-supported-hw = <0x1>; + }; + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1350000>; + opp-supported-hw = <0x2>; }; }; @@ -500,6 +522,9 @@ resets = <&rcc USART2_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 43 0x400 0x21>, + <&dmamux1 44 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -513,6 +538,9 @@ resets = <&rcc USART3_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 45 0x400 0x21>, + <&dmamux1 46 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -526,6 +554,9 @@ resets = <&rcc UART4_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 63 0x400 0x21>, + <&dmamux1 64 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -539,6 +570,9 @@ resets = <&rcc UART5_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 65 0x400 0x21>, + <&dmamux1 66 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -666,6 +700,9 @@ resets = <&rcc UART7_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 79 0x400 0x21>, + <&dmamux1 80 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -679,6 +716,9 @@ resets = <&rcc UART8_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 81 0x400 0x21>, + <&dmamux1 82 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -754,6 +794,9 @@ resets = <&rcc USART6_R>; wakeup-source; power-domains = <&pd_core>; + dmas = <&dmamux1 71 0x400 0x21>, + <&dmamux1 72 0x400 0x1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1948,6 +1991,10 @@ reg = <0x5c005000 0x400>; #address-cells = <1>; #size-cells = <1>; + + part_number_otp: part_number_otp@4 { + reg = <0x4 0x1>; + }; ts_cal1: calib@5c { reg = <0x5c 0x2>; }; @@ -2008,6 +2055,7 @@ st,syscfg-pdds = <&pwr 0x014 0x1>; st,syscfg-holdboot = <&rcc 0x10C 0x1>; st,syscfg-tz = <&rcc 0x000 0x1>; + st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; status = "disabled"; m4_system_resources { diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h index b2d6c83462a6..321cd08797d9 100644 --- a/include/dt-bindings/mfd/st,stpmic1.h +++ b/include/dt-bindings/mfd/st,stpmic1.h @@ -43,4 +43,8 @@ #define IT_SWIN_F 30 #define IT_SWIN_R 31 +/* BUCK MODES definitions */ +#define STPMIC1_BUCK_MODE_NORMAL 0 +#define STPMIC1_BUCK_MODE_LP 2 + #endif /* __DT_BINDINGS_STPMIC1_H__ */ diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h index e928aea7a6d2..e3b45a841c73 100644 --- a/include/dt-bindings/pinctrl/stm32-pinfunc.h +++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h @@ -26,6 +26,7 @@ #define AF14 0xf #define AF15 0x10 #define ANALOG 0x11 +#define RSVD 0x12 /* define Pins number*/ #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) From 3de9b926c4f876fdfb85f1be6048bae8ec9c960f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 23 Oct 2019 19:32:40 +0200 Subject: [PATCH 220/244] ram: stm32mp1: don't display the prompt two times Remove one "DDR>" display on command - next - step - go Signed-off-by: Patrick Delaunay Change-Id: I6004c77337da88fcc073b421245687c3f74b30a8 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/147443 Reviewed-by: CITOOLS --- drivers/ram/stm32mp1/stm32mp1_interactive.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index 8df6a39ca57d..62da59693daa 100644 --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -367,7 +367,6 @@ bool stm32mp1_ddr_interactive(void *priv, enum stm32mp1_ddr_interact_step step, const struct stm32mp1_ddr_config *config) { - const char *prompt = "DDR>"; char buffer[CONFIG_SYS_CBSIZE]; char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ int argc; @@ -403,13 +402,12 @@ bool stm32mp1_ddr_interactive(void *priv, } printf("%d:%s\n", step, step_str[step]); - printf("%s\n", prompt); if (next_step > step) return false; while (next_step == step) { - cli_readline_into_buffer(prompt, buffer, 0); + cli_readline_into_buffer("DDR>", buffer, 0); argc = cli_simple_parse_line(buffer, argv); if (!argc) continue; From 68b5cfba086a48e746703d0738cb2736f7647662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= Date: Thu, 24 Oct 2019 14:40:36 +0200 Subject: [PATCH 221/244] video: stm32mp1 update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yannick Fertré Change-Id: Ifcf29254db59a786e457ebe31ba76ad2aad67d21 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149072 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/video/Kconfig | 13 +- drivers/video/Makefile | 5 +- drivers/video/dsi-host-uclass.c | 39 ++ drivers/video/dw_mipi_dsi.c | 140 +++--- drivers/video/{mipi_display.c => mipi_dsi.c} | 79 ++-- drivers/video/orisetech_otm8009a.c | 111 +++-- drivers/video/raydium-rm68200.c | 49 +- drivers/video/stm32/stm32_dsi.c | 160 ++++--- drivers/video/stm32/stm32_ltdc.c | 50 +- include/dm/uclass-id.h | 1 + include/dsi_host.h | 57 +++ include/mipi_display.h | 249 +--------- include/mipi_dsi.h | 467 +++++++++++++++++++ 13 files changed, 923 insertions(+), 497 deletions(-) create mode 100644 drivers/video/dsi-host-uclass.c rename drivers/video/{mipi_display.c => mipi_dsi.c} (94%) create mode 100644 include/dsi_host.h create mode 100644 include/mipi_dsi.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8809552370ee..890212de5e7e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -74,7 +74,8 @@ config VIDEO_ANSI console. config VIDEO_MIPI_DSI - bool + bool "Support MIPI DSI interface" + depends on DM_VIDEO help Support MIPI DSI interface for driving a MIPI compatible device. The MIPI Display Serial Interface (MIPI DSI) defines a high-speed @@ -332,16 +333,18 @@ config VIDEO_LCD_ORISETECH_OTM8009A depends on DM_VIDEO select VIDEO_MIPI_DSI default n - ---help--- - Support for Orise Tech otm8009a 480p dsi 2dl video mode panel. + help + Say Y here if you want to enable support for Orise Technology + otm8009a 480x800 dsi 2dl panel. config VIDEO_LCD_RAYDIUM_RM68200 bool "RM68200 DSI LCD panel support" depends on DM_VIDEO select VIDEO_MIPI_DSI default n - ---help--- - Support for Raydium rm68200 720x1280 dsi 2dl video mode panel. + help + Say Y here if you want to enable support for Raydium RM68200 + 720x1280 DSI video mode panel. config VIDEO_LCD_SSD2828 bool "SSD2828 bridge chip" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index c3d39ede41c6..796eb6c7791b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/ obj-$(CONFIG_DISPLAY) += display-uclass.o obj-$(CONFIG_DM_VIDEO) += backlight-uclass.o +obj-$(CONFIG_DM_VIDEO) += dsi-host-uclass.o obj-$(CONFIG_DM_VIDEO) += panel-uclass.o simple_panel.o obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o obj-$(CONFIG_DM_VIDEO) += video_bmp.o @@ -44,6 +45,7 @@ obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o +obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o obj-$(CONFIG_VIDEO_EFI) += efi.o obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o @@ -54,6 +56,7 @@ obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o +obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o @@ -63,8 +66,6 @@ obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa.o -obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o -obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_display.o obj-y += bridge/ obj-y += sunxi/ diff --git a/drivers/video/dsi-host-uclass.c b/drivers/video/dsi-host-uclass.c new file mode 100644 index 000000000000..1db1f88a1799 --- /dev/null +++ b/drivers/video/dsi-host-uclass.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved + * Author(s): Yannick Fertre for STMicroelectronics. + * + */ + +#include +#include +#include + +int dsi_host_init(struct udevice *dev, + struct mipi_dsi_device *device, + struct display_timing *timings, + unsigned int max_data_lanes, + const struct mipi_dsi_phy_ops *phy_ops) +{ + struct dsi_host_ops *ops = dsi_host_get_ops(dev); + + if (!ops->init) + return -ENOSYS; + + return ops->init(dev, device, timings, max_data_lanes, phy_ops); +} + +int dsi_host_enable(struct udevice *dev) +{ + struct dsi_host_ops *ops = dsi_host_get_ops(dev); + + if (!ops->enable) + return -ENOSYS; + + return ops->enable(dev); +} + +UCLASS_DRIVER(dsi_host) = { + .id = UCLASS_DSI_HOST, + .name = "dsi_host", +}; diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c index fe1e25a3a97d..83d7c7b2c047 100644 --- a/drivers/video/dw_mipi_dsi.c +++ b/drivers/video/dw_mipi_dsi.c @@ -1,25 +1,24 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved * Author(s): Philippe Cornu for STMicroelectronics. * Yannick Fertre for STMicroelectronics. * - * This generic Synopsys DesignWare MIPI DSI host driver is based on the - * Linux Kernel driver from drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c. + * This generic Synopsys DesignWare MIPI DSI host driver is inspired from + * the Linux Kernel driver drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c. */ #include #include +#include #include #include -#include #include #include #include #include #include -#include #include #include @@ -221,11 +220,8 @@ struct dw_mipi_dsi { void __iomem *base; unsigned int lane_mbps; /* per lane */ u32 channel; - u32 lanes; - u32 format; - unsigned long mode_flags; unsigned int max_data_lanes; - const struct dw_mipi_dsi_phy_ops *phy_ops; + const struct mipi_dsi_phy_ops *phy_ops; }; static int dsi_mode_vrefresh(struct display_timing *timings) @@ -286,10 +282,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, return -EINVAL; } - dsi->lanes = device->lanes; dsi->channel = device->channel; - dsi->format = device->format; - dsi->mode_flags = device->mode_flags; return 0; } @@ -444,6 +437,7 @@ static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) { + struct mipi_dsi_device *device = dsi->device; u32 val; /* @@ -453,9 +447,9 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) */ val = ENABLE_LOW_POWER; - if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) val |= VID_MODE_TYPE_BURST; - else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + else if (device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; else val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; @@ -466,6 +460,8 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, unsigned long mode_flags) { + const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + dsi_write(dsi, DSI_PWR_UP, RESET); if (mode_flags & MIPI_DSI_MODE_VIDEO) { @@ -476,10 +472,13 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); } + if (phy_ops->post_set_mode) + phy_ops->post_set_mode(dsi->device, mode_flags); + dsi_write(dsi, DSI_PWR_UP, POWERUP); } -static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) +static void dw_mipi_dsi_init_pll(struct dw_mipi_dsi *dsi) { /* * The maximum permitted escape clock is 20MHz and it is derived from @@ -505,9 +504,10 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, struct display_timing *timings) { + struct mipi_dsi_device *device = dsi->device; u32 val = 0, color = 0; - switch (dsi->format) { + switch (device->format) { case MIPI_DSI_FMT_RGB888: color = DPI_COLOR_CODING_24BIT; break; @@ -522,9 +522,9 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, break; } - if (dsi->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH) + if (device->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH) val |= VSYNC_ACTIVE_LOW; - if (dsi->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH) + if (device->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH) val |= HSYNC_ACTIVE_LOW; dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); @@ -560,6 +560,8 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) { + const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + /* * TODO dw drv improvements * compute high speed transmission counter timeout according @@ -573,6 +575,9 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) */ dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); + + if (phy_ops->post_set_mode) + phy_ops->post_set_mode(dsi->device, 0); } /* Get lane byte clock cycles. */ @@ -662,13 +667,15 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) { + struct mipi_dsi_device *device = dsi->device; + /* * TODO dw drv improvements * stop wait time should be the maximum between host dsi * and panel stop wait times */ dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | - N_LANES(dsi->lanes)); + N_LANES(device->lanes)); } static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) @@ -712,15 +719,16 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, struct display_timing *timings) { - const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + const struct mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + struct mipi_dsi_device *device = dsi->device; int ret; - ret = phy_ops->get_lane_mbps(dsi->device, timings, dsi->lanes, - dsi->format, &dsi->lane_mbps); + ret = phy_ops->get_lane_mbps(dsi->device, timings, device->lanes, + device->format, &dsi->lane_mbps); if (ret) dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n"); - dw_mipi_dsi_init(dsi); + dw_mipi_dsi_init_pll(dsi); dw_mipi_dsi_dpi_config(dsi, timings); dw_mipi_dsi_packet_handler_config(dsi); dw_mipi_dsi_video_mode_config(dsi); @@ -747,62 +755,33 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, dw_mipi_dsi_set_mode(dsi, 0); } -void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device) +static int dw_mipi_dsi_init(struct udevice *dev, + struct mipi_dsi_device *device, + struct display_timing *timings, + unsigned int max_data_lanes, + const struct mipi_dsi_phy_ops *phy_ops) { - struct mipi_dsi_host *host = device->host; - struct dw_mipi_dsi *dsi = host_to_dsi(host); - - /* Switch to video mode for panel-bridge enable & panel enable */ - dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); -} -EXPORT_SYMBOL_GPL(dw_mipi_dsi_bridge_enable); - -int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device) -{ - struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(device->dev); - struct udevice *panel = platdata->panel; - struct display_timing timings; - struct dw_mipi_dsi *dsi; + struct dw_mipi_dsi *dsi = dev_get_priv(dev); struct clk clk; int ret; - dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); + if (!phy_ops->init || !phy_ops->get_lane_mbps) { + dev_err(device->dev, "Phy not properly configured\n"); + return -ENODEV; + } - dsi->phy_ops = platdata->phy_ops; - dsi->max_data_lanes = platdata->max_data_lanes; + dsi->phy_ops = phy_ops; + dsi->max_data_lanes = max_data_lanes; dsi->device = device; dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; device->host = &dsi->dsi_host; - /* TODO Get these settings from panel */ - dsi->lanes = 2; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM; - dsi->base = (void *)dev_read_addr(device->dev); if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) { dev_err(device->dev, "dsi dt register address error\n"); return -EINVAL; } - ret = panel_get_display_timing(panel, &timings); - if (ret) { - ret = fdtdec_decode_display_timing(gd->fdt_blob, - dev_of_offset(panel), - 0, &timings); - if (ret) { - dev_err(dev, "decode display timing error %d\n", ret); - return ret; - } - } - - if (!dsi->phy_ops->init || !dsi->phy_ops->get_lane_mbps) { - dev_err(device->dev, "Phy not properly configured\n"); - return -ENODEV; - } - ret = clk_get_by_name(device->dev, "px_clk", &clk); if (ret) { dev_err(device->dev, "peripheral clock get error %d\n", ret); @@ -810,13 +789,40 @@ int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device) } /* get the pixel clock set by the clock framework */ - timings.pixelclock.typ = clk_get_rate(&clk); + timings->pixelclock.typ = clk_get_rate(&clk); - dw_mipi_dsi_bridge_set(dsi, &timings); + dw_mipi_dsi_bridge_set(dsi, timings); return 0; } -EXPORT_SYMBOL_GPL(dw_mipi_dsi_init_bridge); + +static int dw_mipi_dsi_enable(struct udevice *dev) +{ + struct dw_mipi_dsi *dsi = dev_get_priv(dev); + + /* Switch to video mode for panel-bridge enable & panel enable */ + dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); + + return 0; +} + +struct dsi_host_ops dw_mipi_dsi_ops = { + .init = dw_mipi_dsi_init, + .enable = dw_mipi_dsi_enable, +}; + +static int dw_mipi_dsi_probe(struct udevice *dev) +{ + return 0; +} + +U_BOOT_DRIVER(dw_mipi_dsi) = { + .name = "dw_mipi_dsi", + .id = UCLASS_DSI_HOST, + .probe = dw_mipi_dsi_probe, + .ops = &dw_mipi_dsi_ops, + .priv_auto_alloc_size = sizeof(struct dw_mipi_dsi), +}; MODULE_AUTHOR("Chris Zhong "); MODULE_AUTHOR("Philippe Cornu "); diff --git a/drivers/video/mipi_display.c b/drivers/video/mipi_dsi.c similarity index 94% rename from drivers/video/mipi_display.c rename to drivers/video/mipi_dsi.c index 611ee53bbc25..cdc3ef58ab1a 100644 --- a/drivers/video/mipi_display.c +++ b/drivers/video/mipi_dsi.c @@ -1,8 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * MIPI DSI Bus * * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. - * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved * Andrzej Hajda * * Permission is hereby granted, free of charge, to any person obtaining a @@ -25,8 +26,8 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * - * Mipi_display.c contains a set of dsi helpers. - * This file is based on the drm helper file drivers/gpu/drm/drm_mipi_dsi.c + * Mipi_dsi.c contains a set of dsi helpers. + * This file is inspired from the drm helper file drivers/gpu/drm/drm_mipi_dsi.c * (kernel linux). * */ @@ -36,6 +37,7 @@ #include #include #include +#include /** * DOC: dsi helpers @@ -216,6 +218,46 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, } EXPORT_SYMBOL(mipi_dsi_create_packet); +/** + * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SHUTDOWN_PERIPHERAL, + .tx_buf = (u8 [2]) { 0, 0 }, + .tx_len = 2, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} +EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral); + +/** + * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_TURN_ON_PERIPHERAL, + .tx_buf = (u8 [2]) { 0, 0 }, + .tx_len = 2, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} +EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); + /* * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the * the payload in a long packet transmitted from the peripheral back to the @@ -441,32 +483,6 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, } EXPORT_SYMBOL(mipi_dsi_dcs_read); -/** - * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any - * given pixel format defined by the MIPI DSI - * specification - * @fmt: MIPI DSI pixel format - * - * Returns: The number of bits per pixel of the given pixel format. - */ -int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) -{ - switch (fmt) { - case MIPI_DSI_FMT_RGB888: - case MIPI_DSI_FMT_RGB666: - return 24; - - case MIPI_DSI_FMT_RGB666_PACKED: - return 18; - - case MIPI_DSI_FMT_RGB565: - return 16; - } - - return -EINVAL; -} -EXPORT_SYMBOL(mipi_dsi_pixel_format_to_bpp); - /** * mipi_dsi_dcs_nop() - send DCS nop packet * @dsi: DSI peripheral device @@ -810,8 +826,3 @@ int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, return 0; } EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); - -MODULE_AUTHOR("Andrzej Hajda "); -MODULE_AUTHOR("Yannick Fertre "); -MODULE_DESCRIPTION("MIPI DSI Bus"); -MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c index 41c4bef6349a..89d9cfdbb333 100644 --- a/drivers/video/orisetech_otm8009a.c +++ b/drivers/video/orisetech_otm8009a.c @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved * Author(s): Yannick Fertre for STMicroelectronics. * Philippe Cornu for STMicroelectronics. * - * This otm8009a panel driver is based on the Linux Kernel driver from + * This otm8009a panel driver is inspired from the Linux Kernel driver * drivers/gpu/drm/panel/panel-orisetech-otm8009a.c. */ #include #include #include -#include +#include #include #include #include @@ -60,18 +60,21 @@ struct otm8009a_panel_priv { struct udevice *reg; struct gpio_desc reset; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; }; static const struct display_timing default_timing = { - .pixelclock = {.min = 32729000, .typ = 32729000, .max = 32729000,}, - .hactive = {.min = 480, .typ = 480, .max = 480,}, - .hfront_porch = {.min = 120, .typ = 120, .max = 120,}, - .hback_porch = {.min = 120, .typ = 120, .max = 120,}, - .hsync_len = {.min = 63, .typ = 63, .max = 63,}, - .vactive = {.min = 800, .typ = 800, .max = 800,}, - .vfront_porch = {.min = 12, .typ = 12, .max = 12,}, - .vback_porch = {.min = 12, .typ = 12, .max = 12,}, - .vsync_len = {.min = 12, .typ = 12, .max = 12,}, + .pixelclock.typ = 29700000, + .hactive.typ = 480, + .hfront_porch.typ = 98, + .hback_porch.typ = 98, + .hsync_len.typ = 32, + .vactive.typ = 800, + .vfront_porch.typ = 15, + .vback_porch.typ = 14, + .vsync_len.typ = 10, }; static void otm8009a_dcs_write_buf(struct udevice *dev, const void *data, @@ -84,12 +87,34 @@ static void otm8009a_dcs_write_buf(struct udevice *dev, const void *data, dev_err(dev, "mipi dsi dcs write buffer failed\n"); } +static void otm8009a_dcs_write_buf_hs(struct udevice *dev, const void *data, + size_t len) +{ + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + + /* data will be sent in dsi hs mode (ie. no lpm) */ + device->mode_flags &= ~MIPI_DSI_MODE_LPM; + + if (mipi_dsi_dcs_write_buffer(device, data, len) < 0) + dev_err(dev, "mipi dsi dcs write buffer failed\n"); + + /* restore back the dsi lpm mode */ + device->mode_flags |= MIPI_DSI_MODE_LPM; +} + #define dcs_write_seq(dev, seq...) \ ({ \ static const u8 d[] = { seq }; \ otm8009a_dcs_write_buf(dev, d, ARRAY_SIZE(d)); \ }) +#define dcs_write_seq_hs(dev, seq...) \ +({ \ + static const u8 d[] = { seq }; \ + otm8009a_dcs_write_buf_hs(dev, d, ARRAY_SIZE(d)); \ +}) + #define dcs_write_cmd_at(dev, cmd, seq...) \ ({ \ static const u16 c = cmd; \ @@ -196,11 +221,13 @@ static int otm8009a_init_sequence(struct udevice *dev) /* Default portrait 480x800 rgb24 */ dcs_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0x00); - ret = mipi_dsi_dcs_set_column_address(device, 0, 479); + ret = mipi_dsi_dcs_set_column_address(device, 0, + default_timing.hactive.typ - 1); if (ret) return ret; - ret = mipi_dsi_dcs_set_page_address(device, 0, 799); + ret = mipi_dsi_dcs_set_page_address(device, 0, + default_timing.vactive.typ - 1); if (ret) return ret; @@ -213,6 +240,17 @@ static int otm8009a_init_sequence(struct udevice *dev) /* Disable CABC feature */ dcs_write_seq(dev, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + ret = mipi_dsi_dcs_set_display_on(device); + if (ret) + return ret; + + ret = mipi_dsi_dcs_nop(device); + if (ret) + return ret; + + /* Send Command GRAM memory write (no parameters) */ + dcs_write_seq(dev, MIPI_DCS_WRITE_MEMORY_START); + return 0; } @@ -222,12 +260,6 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev) struct mipi_dsi_device *device = plat->device; int ret; - device->lanes = 2; - device->format = MIPI_DSI_FMT_RGB888; - device->mode_flags = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM; - ret = mipi_dsi_attach(device); if (ret < 0) return ret; @@ -247,18 +279,10 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev) /* Update Brightness Control & Backlight */ dcs_write_seq(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); - ret = mipi_dsi_dcs_set_display_on(device); - if (ret) - return ret; - - ret = mipi_dsi_dcs_nop(device); - if (ret) - return ret; - - /* Send Command GRAM memory write (no parameters) */ - dcs_write_seq(dev, MIPI_DCS_WRITE_MEMORY_START); + /* Update Brightness Control & Backlight */ + dcs_write_seq_hs(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY); - /* need to wait a few time before set the DSI bridge in video mode */ + /* Need to wait a few time before sending the first image */ mdelay(10); return 0; @@ -267,7 +291,17 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev) static int otm8009a_panel_get_display_timing(struct udevice *dev, struct display_timing *timings) { + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + struct otm8009a_panel_priv *priv = dev_get_priv(dev); + memcpy(timings, &default_timing, sizeof(*timings)); + + /* fill characteristics of DSI data link */ + device->lanes = priv->lanes; + device->format = priv->format; + device->mode_flags = priv->mode_flags; + return 0; } @@ -304,18 +338,21 @@ static int otm8009a_panel_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { dev_dbg(dev, "enable regulator '%s'\n", priv->reg->name); ret = regulator_set_enable(priv->reg, true); - if (ret) { - dev_err(dev, "Regulator : '%s' - can't enable\n", - priv->reg->name); + if (ret) return ret; - } } /* reset panel */ dm_gpio_set_value(&priv->reset, true); - mdelay(1); + mdelay(1); /* >50us */ dm_gpio_set_value(&priv->reset, false); - mdelay(10); + mdelay(10); /* >5ms */ + + priv->lanes = 2; + priv->format = MIPI_DSI_FMT_RGB888; + priv->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; return 0; } diff --git a/drivers/video/raydium-rm68200.c b/drivers/video/raydium-rm68200.c index 3347f12eeafa..91555e26edaf 100644 --- a/drivers/video/raydium-rm68200.c +++ b/drivers/video/raydium-rm68200.c @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved * Author(s): Yannick Fertre for STMicroelectronics. * Philippe Cornu for STMicroelectronics. * - * This rm68200 panel driver is based on the Linux Kernel driver from + * This rm68200 panel driver is inspired from the Linux Kernel driver * drivers/gpu/drm/panel/panel-raydium-rm68200.c. */ #include #include #include -#include +#include #include #include #include @@ -73,18 +73,21 @@ struct rm68200_panel_priv { struct udevice *reg; struct udevice *backlight; struct gpio_desc reset; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; }; static const struct display_timing default_timing = { - .pixelclock = {.min = 52582000, .typ = 52582000, .max = 52582000,}, - .hactive = {.min = 720, .typ = 720, .max = 720,}, - .hfront_porch = {.min = 38, .typ = 38, .max = 38,}, - .hback_porch = {.min = 8, .typ = 8, .max = 8,}, - .hsync_len = {.min = 38, .typ = 38, .max = 38,}, - .vactive = {.min = 1280, .typ = 1280, .max = 1280,}, - .vfront_porch = {.min = 12, .typ = 12, .max = 12,}, - .vback_porch = {.min = 4, .typ = 4, .max = 4,}, - .vsync_len = {.min = 12, .typ = 12, .max = 12,}, + .pixelclock.typ = 54000000, + .hactive.typ = 720, + .hfront_porch.typ = 48, + .hback_porch.typ = 48, + .hsync_len.typ = 9, + .vactive.typ = 1280, + .vfront_porch.typ = 12, + .vback_porch.typ = 12, + .vsync_len.typ = 5, }; static void rm68200_dcs_write_buf(struct udevice *dev, const void *data, @@ -226,12 +229,6 @@ static int rm68200_panel_enable_backlight(struct udevice *dev) struct rm68200_panel_priv *priv = dev_get_priv(dev); int ret; - device->lanes = 2; - device->format = MIPI_DSI_FMT_RGB888; - device->mode_flags = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM; - ret = mipi_dsi_attach(device); if (ret < 0) return ret; @@ -260,7 +257,17 @@ static int rm68200_panel_enable_backlight(struct udevice *dev) static int rm68200_panel_get_display_timing(struct udevice *dev, struct display_timing *timings) { + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); + struct mipi_dsi_device *device = plat->device; + struct rm68200_panel_priv *priv = dev_get_priv(dev); + memcpy(timings, &default_timing, sizeof(*timings)); + + /* fill characteristics of DSI data link */ + device->lanes = priv->lanes; + device->format = priv->format; + device->mode_flags = priv->mode_flags; + return 0; } @@ -313,6 +320,12 @@ static int rm68200_panel_probe(struct udevice *dev) dm_gpio_set_value(&priv->reset, false); mdelay(10); + priv->lanes = 2; + priv->format = MIPI_DSI_FMT_RGB888; + priv->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + return 0; } diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index f8f7c8358d44..e1edbedd20f2 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved * Author(s): Philippe Cornu for STMicroelectronics. * Yannick Fertre for STMicroelectronics. * * This MIPI DSI controller driver is based on the Linux Kernel driver from * drivers/gpu/drm/stm/dw_mipi_dsi-stm.c. */ + #include #include #include -#include -#include +#include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -87,6 +89,7 @@ struct stm32_dsi_priv { int lane_min_kbps; int lane_max_kbps; struct udevice *vdd_reg; + struct udevice *dsi_host; }; static inline void dsi_write(struct stm32_dsi_priv *dsi, u32 reg, u32 val) @@ -207,12 +210,14 @@ static int dsi_phy_init(void *priv_data) u32 val; int ret; + debug("Initialize DSI physical layer\n"); + /* Enable the regulator */ dsi_set(dsi, DSI_WRPCR, WRPCR_REGEN | WRPCR_BGREN); ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_RRS, TIMEOUT_US); if (ret) { - dev_err(dev, "!TIMEOUT! waiting REGU\n"); + debug("!TIMEOUT! waiting REGU\n"); return ret; } @@ -221,16 +226,37 @@ static int dsi_phy_init(void *priv_data) ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_PLLLS, TIMEOUT_US); if (ret) { - dev_err(dev, "!TIMEOUT! waiting PLL\n"); + debug("!TIMEOUT! waiting PLL\n"); return ret; } - /* Enable the DSI wrapper */ - dsi_set(dsi, DSI_WCR, WCR_DSIEN); - return 0; } +static void dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags) +{ + struct mipi_dsi_device *device = priv_data; + struct udevice *dev = device->dev; + struct stm32_dsi_priv *dsi = dev_get_priv(dev); + + debug("Set mode %p enable %ld\n", dsi, + mode_flags & MIPI_DSI_MODE_VIDEO); + + if (!dsi) + return; + + /* + * DSI wrapper must be enabled in video mode & disabled in command mode. + * If wrapper is enabled in command mode, the display controller + * register access will hang. + */ + + if (mode_flags & MIPI_DSI_MODE_VIDEO) + dsi_set(dsi, DSI_WCR, WCR_DSIEN); + else + dsi_clear(dsi, DSI_WCR, WCR_DSIEN); +} + static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, u32 lanes, u32 format, unsigned int *lane_mbps) { @@ -242,6 +268,7 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, u32 val; /* Update lane capabilities according to hw version */ + dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; dsi->lane_min_kbps = LANE_MIN_KBPS; dsi->lane_max_kbps = LANE_MAX_KBPS; if (dsi->hw_version == HWVER_131) { @@ -302,28 +329,48 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, return 0; } -static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { +static const struct mipi_dsi_phy_ops dsi_stm_phy_ops = { .init = dsi_phy_init, .get_lane_mbps = dsi_get_lane_mbps, + .post_set_mode = dsi_phy_post_set_mode, }; static int stm32_dsi_attach(struct udevice *dev) { - struct stm32_dsi_priv *dsi = dev_get_priv(dev); - struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(dev); - struct mipi_dsi_device *device = &dsi->device; + struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct mipi_dsi_device *device = &priv->device; + struct mipi_dsi_panel_plat *mplat; + struct display_timing timings; int ret; - platdata->max_data_lanes = 2; - platdata->phy_ops = &dw_mipi_dsi_stm_phy_ops; - - ret = uclass_first_device(UCLASS_PANEL, &platdata->panel); + ret = uclass_first_device(UCLASS_PANEL, &priv->panel); if (ret) { dev_err(dev, "panel device error %d\n", ret); return ret; } - ret = dw_mipi_dsi_init_bridge(device); + mplat = dev_get_platdata(priv->panel); + mplat->device = &priv->device; + + ret = panel_get_display_timing(priv->panel, &timings); + if (ret) { + ret = fdtdec_decode_display_timing(gd->fdt_blob, + dev_of_offset(priv->panel), + 0, &timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host); + if (ret) { + dev_err(dev, "No video dsi host detected %d\n", ret); + return ret; + } + + ret = dsi_host_init(priv->dsi_host, device, &timings, 2, + &dsi_stm_phy_ops); if (ret) { dev_err(dev, "failed to initialize mipi dsi host\n"); return ret; @@ -334,53 +381,62 @@ static int stm32_dsi_attach(struct udevice *dev) static int stm32_dsi_set_backlight(struct udevice *dev, int percent) { - struct dw_mipi_dsi_plat_data *dplat = dev_get_platdata(dev); - struct stm32_dsi_priv *dsi = dev_get_priv(dev); - struct mipi_dsi_device *device = &dsi->device; - struct udevice *panel = dplat->panel; - struct mipi_dsi_panel_plat *mplat; + struct stm32_dsi_priv *priv = dev_get_priv(dev); int ret; - mplat = dev_get_platdata(panel); - mplat->device = device; - - ret = panel_enable_backlight(panel); + ret = panel_enable_backlight(priv->panel); if (ret) { dev_err(dev, "panel %s enable backlight error %d\n", - panel->name, ret); + priv->panel->name, ret); return ret; } - dw_mipi_dsi_bridge_enable(device); + ret = dsi_host_enable(priv->dsi_host); + if (ret) { + dev_err(dev, "failed to enable mipi dsi host\n"); + return ret; + } return 0; } +static int stm32_dsi_bind(struct udevice *dev) +{ + int ret; + + ret = device_bind_driver_to_node(dev, "dw_mipi_dsi", "dsihost", + dev_ofnode(dev), NULL); + if (ret) + return ret; + + return dm_scan_fdt_dev(dev); +} + static int stm32_dsi_probe(struct udevice *dev) { - struct stm32_dsi_priv *dsi = dev_get_priv(dev); - struct mipi_dsi_device *device = &dsi->device; + struct stm32_dsi_priv *priv = dev_get_priv(dev); + struct mipi_dsi_device *device = &priv->device; struct reset_ctl rst; struct clk clk; int ret; device->dev = dev; - dsi->base = (void *)dev_read_addr(dev); - if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) { + priv->base = (void *)dev_read_addr(dev); + if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) { dev_err(dev, "dsi dt register address error\n"); return -EINVAL; } if (IS_ENABLED(CONFIG_DM_REGULATOR)) { ret = device_get_supply_regulator(dev, "phy-dsi-supply", - &dsi->vdd_reg); + &priv->vdd_reg); if (ret && ret != -ENOENT) { dev_err(dev, "Warning: cannot get phy dsi supply\n"); return -ENODEV; } - ret = regulator_set_enable(dsi->vdd_reg, true); + ret = regulator_set_enable(priv->vdd_reg, true); if (ret) return -ENODEV; } @@ -388,49 +444,40 @@ static int stm32_dsi_probe(struct udevice *dev) ret = clk_get_by_name(device->dev, "pclk", &clk); if (ret) { dev_err(dev, "peripheral clock get error %d\n", ret); - regulator_set_enable(dsi->vdd_reg, false); - return -ENODEV; + goto err_reg; } ret = clk_enable(&clk); if (ret) { dev_err(dev, "peripheral clock enable error %d\n", ret); - regulator_set_enable(dsi->vdd_reg, false); - return -ENODEV; + goto err_reg; } ret = clk_get_by_name(dev, "ref", &clk); if (ret) { dev_err(dev, "pll reference clock get error %d\n", ret); - clk_disable(&clk); - regulator_set_enable(dsi->vdd_reg, false); - return ret; + goto err_clk; } - dsi->pllref_clk = (unsigned int)clk_get_rate(&clk); + priv->pllref_clk = (unsigned int)clk_get_rate(&clk); ret = reset_get_by_index(device->dev, 0, &rst); if (ret) { dev_err(dev, "missing dsi hardware reset\n"); - clk_disable(&clk); - regulator_set_enable(dsi->vdd_reg, false); - return -ENODEV; + goto err_clk; } /* Reset */ reset_deassert(&rst); - /* check hardware version */ - dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; - if (dsi->hw_version != HWVER_130 && - dsi->hw_version != HWVER_131) { - dev_err(dev, "bad dsi hardware version\n"); - clk_disable(&clk); - regulator_set_enable(dsi->vdd_reg, false); - return -ENODEV; - } - return 0; +err_clk: + clk_disable(&clk); +err_reg: + if (IS_ENABLED(CONFIG_DM_REGULATOR)) + regulator_set_enable(priv->vdd_reg, false); + + return ret; } struct video_bridge_ops stm32_dsi_ops = { @@ -447,9 +494,8 @@ U_BOOT_DRIVER(stm32_dsi) = { .name = "stm32-display-dsi", .id = UCLASS_VIDEO_BRIDGE, .of_match = stm32_dsi_ids, - .bind = dm_scan_fdt_dev, + .bind = stm32_dsi_bind, .probe = stm32_dsi_probe, .ops = &stm32_dsi_ops, .priv_auto_alloc_size = sizeof(struct stm32_dsi_priv), - .platdata_auto_alloc_size = sizeof(struct dw_mipi_dsi_plat_data), }; diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 8c996b8100d7..59ff692b0b4c 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -4,6 +4,7 @@ * Author(s): Philippe Cornu for STMicroelectronics. * Yannick Fertre for STMicroelectronics. */ + #include #include #include @@ -328,9 +329,7 @@ static int stm32_ltdc_probe(struct udevice *dev) struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_ltdc_priv *priv = dev_get_priv(dev); -#ifdef CONFIG_VIDEO_BRIDGE struct udevice *bridge = NULL; -#endif struct udevice *panel = NULL; struct display_timing timings; struct clk pclk; @@ -390,19 +389,20 @@ static int stm32_ltdc_probe(struct udevice *dev) /* Reset */ reset_deassert(&rst); -#ifdef CONFIG_VIDEO_BRIDGE - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); - if (ret) - debug("No video bridge, or no backlight on bridge\n"); - - if (bridge) { - ret = video_bridge_attach(bridge); - if (ret) { - dev_err(dev, "fail to attach bridge\n"); - return ret; + if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { + ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); + if (ret) + debug("No video bridge, or no backlight on bridge\n"); + + if (bridge) { + ret = video_bridge_attach(bridge); + if (ret) { + dev_err(dev, "fail to attach bridge\n"); + return ret; + } } } -#endif + /* TODO Below parameters are hard-coded for the moment... */ priv->l2bpp = VIDEO_BPP16; priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */ @@ -428,29 +428,21 @@ static int stm32_ltdc_probe(struct udevice *dev) uc_priv->ysize = timings.vactive.typ; uc_priv->bpix = priv->l2bpp; -#ifdef CONFIG_VIDEO_BRIDGE - if (bridge) { - ret = video_bridge_set_backlight(bridge, 80); - if (ret) { - dev_err(dev, "fail to set backlight\n"); - return ret; - } - } else { + if (!bridge) { ret = panel_enable_backlight(panel); if (ret) { dev_err(dev, "panel %s enable backlight error %d\n", panel->name, ret); return ret; } + } else if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { + ret = video_bridge_set_backlight(bridge, 80); + if (ret) { + dev_err(dev, "fail to set backlight\n"); + return ret; + } } -#else - ret = panel_enable_backlight(panel); - if (ret) { - dev_err(dev, "panel %s enable backlight error %d\n", - panel->name, ret); - return ret; - } -#endif + video_set_flush_dcache(dev, true); return 0; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 6193017432e6..5f6216722306 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -35,6 +35,7 @@ enum uclass_id { UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */ UCLASS_DISPLAY, /* Display (e.g. DisplayPort, HDMI) */ + UCLASS_DSI_HOST, /* Dsi host device */ UCLASS_DMA, /* Direct Memory Access */ UCLASS_EFI, /* EFI managed devices */ UCLASS_ETH, /* Ethernet device */ diff --git a/include/dsi_host.h b/include/dsi_host.h new file mode 100644 index 000000000000..9ff226fcc3d6 --- /dev/null +++ b/include/dsi_host.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019 STMicroelectronics - All Rights Reserved + * Author(s): Yannick Fertre for STMicroelectronics. + * + */ + +#ifndef _DSI_HOST_H +#define _DSI_HOST_H + +#include + +struct dsi_host_ops { + /** + * init() - Enable the dsi_host + * + * @dev: dsi host device + * @return 0 if OK, -ve on error + */ + int (*init)(struct udevice *dev, + struct mipi_dsi_device *device, + struct display_timing *timings, + unsigned int max_data_lanes, + const struct mipi_dsi_phy_ops *phy_ops); + + /** + * enable() - Enable the dsi_host + * + * @dev: dsi host device + * @return 0 if OK, -ve on error + */ + int (*enable)(struct udevice *dev); +}; + +#define dsi_host_get_ops(dev) ((struct dsi_host_ops *)(dev)->driver->ops) + +/** + * dsi_host_init + * + * @dev: dsi host device + * @return 0 if OK, -ve on error + */ +int dsi_host_init(struct udevice *dev, + struct mipi_dsi_device *device, + struct display_timing *timings, + unsigned int max_data_lanes, + const struct mipi_dsi_phy_ops *phy_ops); + +/** + * dsi_host_enable + * + * @dev: dsi host device + * @return 0 if OK, -ve on error + */ +int dsi_host_enable(struct udevice *dev); + +#endif diff --git a/include/mipi_display.h b/include/mipi_display.h index 5c3dbbeffe53..19aa65a35546 100644 --- a/include/mipi_display.h +++ b/include/mipi_display.h @@ -4,16 +4,12 @@ * * Copyright (C) 2010 Guennadi Liakhovetski * Copyright (C) 2006 Nokia Corporation - * Copyright (C) 2018 STMicroelectronics - All Rights Reserved - * Author(s): Imre Deak - * Yannick Fertre - * Philippe Cornu + * Author: Imre Deak * * 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. */ - #ifndef MIPI_DISPLAY_H #define MIPI_DISPLAY_H @@ -139,247 +135,4 @@ enum { #define MIPI_DCS_PIXEL_FMT_8BIT 2 #define MIPI_DCS_PIXEL_FMT_3BIT 1 -struct mipi_dsi_host; -struct mipi_dsi_device; - -/* request ACK from peripheral */ -#define MIPI_DSI_MSG_REQ_ACK BIT(0) -/* use Low Power Mode to transmit message */ -#define MIPI_DSI_MSG_USE_LPM BIT(1) - -/** - * struct mipi_dsi_msg - read/write DSI buffer - * @channel: virtual channel id - * @type: payload data type - * @flags: flags controlling this message transmission - * @tx_len: length of @tx_buf - * @tx_buf: data to be written - * @rx_len: length of @rx_buf - * @rx_buf: data to be read, or NULL - */ -struct mipi_dsi_msg { - u8 channel; - u8 type; - u16 flags; - - size_t tx_len; - const void *tx_buf; - - size_t rx_len; - void *rx_buf; -}; - -bool mipi_dsi_packet_format_is_short(u8 type); -bool mipi_dsi_packet_format_is_long(u8 type); - -/** - * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format - * @size: size (in bytes) of the packet - * @header: the four bytes that make up the header (Data ID, Word Count or - * Packet Data, and ECC) - * @payload_length: number of bytes in the payload - * @payload: a pointer to a buffer containing the payload, if any - */ -struct mipi_dsi_packet { - size_t size; - u8 header[4]; - size_t payload_length; - const u8 *payload; -}; - -int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, - const struct mipi_dsi_msg *msg); - -/** - * struct mipi_dsi_host_ops - DSI bus operations - * @attach: attach DSI device to DSI host - * @detach: detach DSI device from DSI host - * @transfer: transmit a DSI packet - * - * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg - * structures. This structure contains information about the type of packet - * being transmitted as well as the transmit and receive buffers. When an - * error is encountered during transmission, this function will return a - * negative error code. On success it shall return the number of bytes - * transmitted for write packets or the number of bytes received for read - * packets. - * - * Note that typically DSI packet transmission is atomic, so the .transfer() - * function will seldomly return anything other than the number of bytes - * contained in the transmit buffer on success. - */ -struct mipi_dsi_host_ops { - int (*attach)(struct mipi_dsi_host *host, - struct mipi_dsi_device *dsi); - int (*detach)(struct mipi_dsi_host *host, - struct mipi_dsi_device *dsi); - ssize_t (*transfer)(struct mipi_dsi_host *host, - const struct mipi_dsi_msg *msg); -}; - -/** - * struct mipi_dsi_host - DSI host device - * @dev: driver model device node for this DSI host - * @ops: DSI host operations - * @list: list management - */ -struct mipi_dsi_host { - struct device *dev; - const struct mipi_dsi_host_ops *ops; - struct list_head list; -}; - -/* DSI mode flags */ - -/* video mode */ -#define MIPI_DSI_MODE_VIDEO BIT(0) -/* video burst mode */ -#define MIPI_DSI_MODE_VIDEO_BURST BIT(1) -/* video pulse mode */ -#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) -/* enable auto vertical count mode */ -#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) -/* enable hsync-end packets in vsync-pulse and v-porch area */ -#define MIPI_DSI_MODE_VIDEO_HSE BIT(4) -/* disable hfront-porch area */ -#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) -/* disable hback-porch area */ -#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) -/* disable hsync-active area */ -#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) -/* flush display FIFO on vsync pulse */ -#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) -/* disable EoT packets in HS mode */ -#define MIPI_DSI_MODE_EOT_PACKET BIT(9) -/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ -#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) -/* transmit data in low power */ -#define MIPI_DSI_MODE_LPM BIT(11) - -enum mipi_dsi_pixel_format { - MIPI_DSI_FMT_RGB888, - MIPI_DSI_FMT_RGB666, - MIPI_DSI_FMT_RGB666_PACKED, - MIPI_DSI_FMT_RGB565, -}; - -#define DSI_DEV_NAME_SIZE 20 - -/** - * struct mipi_dsi_device_info - template for creating a mipi_dsi_device - * @type: DSI peripheral chip type - * @channel: DSI virtual channel assigned to peripheral - * @node: pointer to OF device node or NULL - * - * This is populated and passed to mipi_dsi_device_new to create a new - * DSI device - */ -struct mipi_dsi_device_info { - char type[DSI_DEV_NAME_SIZE]; - u32 channel; - struct device_node *node; -}; - -/** - * struct mipi_dsi_device - DSI peripheral device - * @host: DSI host for this peripheral - * @dev: driver model device node for this peripheral - * @name: DSI peripheral chip type - * @channel: virtual channel assigned to the peripheral - * @format: pixel format for video mode - * @lanes: number of active data lanes - * @mode_flags: DSI operation mode related flags - */ -struct mipi_dsi_device { - struct mipi_dsi_host *host; - struct udevice *dev; - - char name[DSI_DEV_NAME_SIZE]; - unsigned int channel; - unsigned int lanes; - enum mipi_dsi_pixel_format format; - unsigned long mode_flags; -}; - -/** - * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode - * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking - * information only - * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both - * V-Blanking and H-Blanking information - */ -enum mipi_dsi_dcs_tear_mode { - MIPI_DSI_DCS_TEAR_MODE_VBLANK, - MIPI_DSI_DCS_TEAR_MODE_VHBLANK, -}; - -/** - * struct mipi_dsi_panel_plat - DSI panel platform data - * @device: DSI peripheral device - */ -struct mipi_dsi_panel_plat { - struct mipi_dsi_device *device; -}; - -int mipi_dsi_attach(struct mipi_dsi_device *dsi); -int mipi_dsi_detach(struct mipi_dsi_device *dsi); -int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt); - -/* bit compatible with the xrandr RR_ definitions (bits 0-13) - * - * ABI warning: Existing userspace really expects - * the mode flags to match the xrandr definitions. Any - * changes that don't match the xrandr definitions will - * likely need a new client cap or some other mechanism - * to avoid breaking existing userspace. This includes - * allocating new flags in the previously unused bits! - */ -#define MIPI_DSI_FLAG_PHSYNC BIT(0) -#define MIPI_DSI_FLAG_NHSYNC BIT(1) -#define MIPI_DSI_FLAG_PVSYNC BIT(2) -#define MIPI_DSI_FLAG_NVSYNC BIT(3) -#define MIPI_DSI_FLAG_INTERLACE BIT(4) -#define MIPI_DSI_FLAG_DBLSCAN BIT(5) -#define MIPI_DSI_FLAG_CSYNC BIT(6) -#define MIPI_DSI_FLAG_PCSYNC BIT(7) -#define MIPI_DSI_FLAG_NCSYNC BIT(8) -#define MIPI_DSI_FLAG_HSKEW BIT(9) /* hskew provided */ -#define MIPI_DSI_FLAG_BCAST BIT(10) -#define MIPI_DSI_FLAG_PIXMUX BIT(11) -#define MIPI_DSI_FLAG_DBLCLK BIT(12) -#define MIPI_DSI_FLAG_CLKDIV2 BIT(13) - -/* request ACK from peripheral */ -#define MIPI_DSI_MSG_REQ_ACK BIT(0) -/* use Low Power Mode to transmit message */ -#define MIPI_DSI_MSG_USE_LPM BIT(1) - -ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, - const void *data, size_t len); -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, - const void *data, size_t len); -ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, - size_t len); -int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode); -int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format); -int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, - u16 end); -int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, - u16 end); -int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, - enum mipi_dsi_dcs_tear_mode mode); -int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format); -int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); -int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, - u16 brightness); -int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, - u16 *brightness); - #endif diff --git a/include/mipi_dsi.h b/include/mipi_dsi.h new file mode 100644 index 000000000000..b366a2ec7cf8 --- /dev/null +++ b/include/mipi_dsi.h @@ -0,0 +1,467 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Copyright (C) 2018 STMicroelectronics - All Rights Reserved + * Author(s): Andrzej Hajda + * Yannick Fertre + * Philippe Cornu + * + * 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. + */ +#ifndef MIPI_DSI_H +#define MIPI_DSI_H + +#include +#include + +struct mipi_dsi_host; +struct mipi_dsi_device; + +/* request ACK from peripheral */ +#define MIPI_DSI_MSG_REQ_ACK BIT(0) +/* use Low Power Mode to transmit message */ +#define MIPI_DSI_MSG_USE_LPM BIT(1) + +/** + * struct mipi_dsi_msg - read/write DSI buffer + * @channel: virtual channel id + * @type: payload data type + * @flags: flags controlling this message transmission + * @tx_len: length of @tx_buf + * @tx_buf: data to be written + * @rx_len: length of @rx_buf + * @rx_buf: data to be read, or NULL + */ +struct mipi_dsi_msg { + u8 channel; + u8 type; + u16 flags; + + size_t tx_len; + const void *tx_buf; + + size_t rx_len; + void *rx_buf; +}; + +bool mipi_dsi_packet_format_is_short(u8 type); +bool mipi_dsi_packet_format_is_long(u8 type); + +/** + * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format + * @size: size (in bytes) of the packet + * @header: the four bytes that make up the header (Data ID, Word Count or + * Packet Data, and ECC) + * @payload_length: number of bytes in the payload + * @payload: a pointer to a buffer containing the payload, if any + */ +struct mipi_dsi_packet { + size_t size; + u8 header[4]; + size_t payload_length; + const u8 *payload; +}; + +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg); + +/** + * struct mipi_dsi_host_ops - DSI bus operations + * @attach: attach DSI device to DSI host + * @detach: detach DSI device from DSI host + * @transfer: transmit a DSI packet + * + * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg + * structures. This structure contains information about the type of packet + * being transmitted as well as the transmit and receive buffers. When an + * error is encountered during transmission, this function will return a + * negative error code. On success it shall return the number of bytes + * transmitted for write packets or the number of bytes received for read + * packets. + * + * Note that typically DSI packet transmission is atomic, so the .transfer() + * function will seldomly return anything other than the number of bytes + * contained in the transmit buffer on success. + */ +struct mipi_dsi_host_ops { + int (*attach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + int (*detach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + ssize_t (*transfer)(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg); +}; + +/** + * struct mipi_dsi_phy_ops - DSI host physical operations + * @init: initialized host physical part + * @get_lane_mbps: get lane bitrate per lane (mbps) + * @post_set_mode: operation that should after set mode + */ +struct mipi_dsi_phy_ops { + int (*init)(void *priv_data); + int (*get_lane_mbps)(void *priv_data, struct display_timing *timings, + u32 lanes, u32 format, unsigned int *lane_mbps); + void (*post_set_mode)(void *priv_data, unsigned long mode_flags); +}; + +/** + * struct mipi_dsi_host - DSI host device + * @dev: driver model device node for this DSI host + * @ops: DSI host operations + * @list: list management + */ +struct mipi_dsi_host { + struct device *dev; + const struct mipi_dsi_host_ops *ops; + struct list_head list; +}; + +/* DSI mode flags */ + +/* video mode */ +#define MIPI_DSI_MODE_VIDEO BIT(0) +/* video burst mode */ +#define MIPI_DSI_MODE_VIDEO_BURST BIT(1) +/* video pulse mode */ +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) +/* enable auto vertical count mode */ +#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) +/* enable hsync-end packets in vsync-pulse and v-porch area */ +#define MIPI_DSI_MODE_VIDEO_HSE BIT(4) +/* disable hfront-porch area */ +#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) +/* disable hback-porch area */ +#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) +/* disable hsync-active area */ +#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) +/* flush display FIFO on vsync pulse */ +#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) +/* disable EoT packets in HS mode */ +#define MIPI_DSI_MODE_EOT_PACKET BIT(9) +/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ +#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) +/* transmit data in low power */ +#define MIPI_DSI_MODE_LPM BIT(11) + +enum mipi_dsi_pixel_format { + MIPI_DSI_FMT_RGB888, + MIPI_DSI_FMT_RGB666, + MIPI_DSI_FMT_RGB666_PACKED, + MIPI_DSI_FMT_RGB565, +}; + +#define DSI_DEV_NAME_SIZE 20 + +/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: DSI peripheral chip type + * @channel: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node or NULL + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; + u32 channel; + struct device_node *node; +}; + +/** + * struct mipi_dsi_device - DSI peripheral device + * @host: DSI host for this peripheral + * @dev: driver model device node for this peripheral + * @name: DSI peripheral chip type + * @channel: virtual channel assigned to the peripheral + * @format: pixel format for video mode + * @lanes: number of active data lanes + * @mode_flags: DSI operation mode related flags + */ +struct mipi_dsi_device { + struct mipi_dsi_host *host; + struct udevice *dev; + + char name[DSI_DEV_NAME_SIZE]; + unsigned int channel; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; +}; + +/** + * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any + * given pixel format defined by the MIPI DSI + * specification + * @fmt: MIPI DSI pixel format + * + * Returns: The number of bits per pixel of the given pixel format. + */ +static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB888: + case MIPI_DSI_FMT_RGB666: + return 24; + + case MIPI_DSI_FMT_RGB666_PACKED: + return 18; + + case MIPI_DSI_FMT_RGB565: + return 16; + } + + return -EINVAL; +} + +/** + * struct mipi_dsi_panel_plat - DSI panel platform data + * @device: DSI peripheral device + */ +struct mipi_dsi_panel_plat { + struct mipi_dsi_device *device; +}; + +/** + * mipi_dsi_attach - attach a DSI device to its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_attach(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_detach - detach a DSI device from its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_detach(struct mipi_dsi_device *dsi); +int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi); +int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value); + +ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size); +ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, + size_t num_params, void *data, size_t size); + +/** + * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode + * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking + * information only + * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both + * V-Blanking and H-Blanking information + */ +enum mipi_dsi_dcs_tear_mode { + MIPI_DSI_DCS_TEAR_MODE_VBLANK, + MIPI_DSI_DCS_TEAR_MODE_VHBLANK, +}; + +#define MIPI_DSI_DCS_POWER_MODE_DISPLAY BIT(2) +#define MIPI_DSI_DCS_POWER_MODE_NORMAL BIT(3) +#define MIPI_DSI_DCS_POWER_MODE_SLEEP BIT(4) +#define MIPI_DSI_DCS_POWER_MODE_PARTIAL BIT(5) +#define MIPI_DSI_DCS_POWER_MODE_IDLE BIT(6) + +/** + * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload + * @dsi: DSI peripheral device + * @data: buffer containing data to be transmitted + * @len: size of transmission buffer + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len); + +/** + * mipi_dsi_dcs_write() - send DCS write command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer containing the command payload + * @len: command payload length + * + * This function will automatically choose the right data type depending on + * the command payload length. + + * code on failure. + */ +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len); + +/** + * mipi_dsi_dcs_read() - send DCS read request command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer in which to receive data + * @len: size of receive buffer + * + * Return: The number of bytes read or a negative error code on failure. + */ +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len); + +/** + * mipi_dsi_dcs_nop() - send DCS nop packet + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_get_power_mode() - query the display module's current power + * mode + * @dsi: DSI peripheral device + * @mode: return location for the current power mode + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode); + +/** + * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: return location for the pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format); + +/** + * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the + * display module except interface communication + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display + * module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_set_display_on() - start displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_set_column_address() - define the column extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first column of frame memory + * @end: last column of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); +/** + * mipi_dsi_dcs_set_page_address() - define the page extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first page of frame memory + * @end: last page of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); + +/** + * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect + * output signal on the TE signal line + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi); + +/** + * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect + * output signal on the TE signal line. + * @dsi: DSI peripheral device + * @mode: the Tearing Effect Output Line mode + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode); + +/** + * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format); + +/** + * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for + * the Tearing Effect output signal of the display module + * @dsi: DSI peripheral device + * @scanline: scanline to use as trigger + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); + +/** + * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the + * display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, + u16 brightness); + +/** + * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value + * of the display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, + u16 *brightness); + +#endif /* MIPI_DSI_H */ From 1b0ac8992d62772a6e322996a4383733092b5dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= Date: Thu, 24 Oct 2019 14:50:11 +0200 Subject: [PATCH 222/244] video: mipi update panel platform data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new fields "lanes, format & mode_flags" to structure mipi_dsi_panel_plat. Signed-off-by: Yannick Fertré Change-Id: I51ed5d96bc6d4b1a45dd3cae9b1328b4c4d3b52b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149073 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- include/mipi_dsi.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mipi_dsi.h b/include/mipi_dsi.h index b366a2ec7cf8..f76e8d708a10 100644 --- a/include/mipi_dsi.h +++ b/include/mipi_dsi.h @@ -221,9 +221,15 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) /** * struct mipi_dsi_panel_plat - DSI panel platform data * @device: DSI peripheral device + * @lanes: number of active data lanes + * @format: pixel format for video mode + * @mode_flags: DSI operation mode related flags */ struct mipi_dsi_panel_plat { struct mipi_dsi_device *device; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; }; /** From 275062832c0fdd734941dba72bf77107c325a6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= Date: Thu, 17 Oct 2019 09:19:41 +0200 Subject: [PATCH 223/244] video: stm32: stm32_dsi: copy DSI fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copy the DSI data link characteristics from panel platform data to mipi DSI device. Signed-off-by: Yannick Fertré Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/146731 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Philippe CORNU Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Change-Id: I9e64ad6cc828d446ccd9a974ed50d65f9942f1be Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149074 Tested-by: Patrick DELAUNAY --- drivers/video/stm32/stm32_dsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index e1edbedd20f2..8ba6cd4de3ac 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -351,6 +351,9 @@ static int stm32_dsi_attach(struct udevice *dev) mplat = dev_get_platdata(priv->panel); mplat->device = &priv->device; + device->lanes = mplat->lanes; + device->format = mplat->format; + device->mode_flags = mplat->mode_flags; ret = panel_get_display_timing(priv->panel, &timings); if (ret) { From b9cfde9109469123ea4a6a1f7cbc6c4df33280e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= Date: Thu, 17 Oct 2019 09:45:05 +0200 Subject: [PATCH 224/244] video: raydium_rm68200: fill characteristics of DSI data link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill characteristics of DSI data link to platform data instead of mipi device to avoid memory corruption. Signed-off-by: Yannick Fertré Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/146732 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Philippe CORNU Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Change-Id: I932b05998487fdd672b20e98fa55e5e5e1be24b0 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149075 Tested-by: Patrick DELAUNAY --- drivers/video/raydium-rm68200.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/video/raydium-rm68200.c b/drivers/video/raydium-rm68200.c index 91555e26edaf..76b0ed22018f 100644 --- a/drivers/video/raydium-rm68200.c +++ b/drivers/video/raydium-rm68200.c @@ -73,9 +73,6 @@ struct rm68200_panel_priv { struct udevice *reg; struct udevice *backlight; struct gpio_desc reset; - unsigned int lanes; - enum mipi_dsi_pixel_format format; - unsigned long mode_flags; }; static const struct display_timing default_timing = { @@ -257,17 +254,8 @@ static int rm68200_panel_enable_backlight(struct udevice *dev) static int rm68200_panel_get_display_timing(struct udevice *dev, struct display_timing *timings) { - struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); - struct mipi_dsi_device *device = plat->device; - struct rm68200_panel_priv *priv = dev_get_priv(dev); - memcpy(timings, &default_timing, sizeof(*timings)); - /* fill characteristics of DSI data link */ - device->lanes = priv->lanes; - device->format = priv->format; - device->mode_flags = priv->mode_flags; - return 0; } @@ -306,6 +294,7 @@ static int rm68200_panel_ofdata_to_platdata(struct udevice *dev) static int rm68200_panel_probe(struct udevice *dev) { struct rm68200_panel_priv *priv = dev_get_priv(dev); + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); int ret; if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { @@ -320,9 +309,10 @@ static int rm68200_panel_probe(struct udevice *dev) dm_gpio_set_value(&priv->reset, false); mdelay(10); - priv->lanes = 2; - priv->format = MIPI_DSI_FMT_RGB888; - priv->mode_flags = MIPI_DSI_MODE_VIDEO | + /* fill characteristics of DSI data link */ + plat->lanes = 2; + plat->format = MIPI_DSI_FMT_RGB888; + plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; From e87bd559a3d7582a623361345962ab606aa238ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= Date: Thu, 17 Oct 2019 13:41:49 +0200 Subject: [PATCH 225/244] video: orisetech_otm8009a: fill characteristics of DSI data link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill characteristics of DSI data link to platform data instead of mipi device to avoid memory corruption. Signed-off-by: Yannick Fertré Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/146733 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Philippe CORNU Reviewed-by: Patrice CHOTARD Reviewed-by: Patrick DELAUNAY Change-Id: If16ab3eba7e7c3864ee917e042a271310bb91e29 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149076 Tested-by: Patrick DELAUNAY --- drivers/video/orisetech_otm8009a.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c index 89d9cfdbb333..629bf7678f47 100644 --- a/drivers/video/orisetech_otm8009a.c +++ b/drivers/video/orisetech_otm8009a.c @@ -60,9 +60,6 @@ struct otm8009a_panel_priv { struct udevice *reg; struct gpio_desc reset; - unsigned int lanes; - enum mipi_dsi_pixel_format format; - unsigned long mode_flags; }; static const struct display_timing default_timing = { @@ -291,17 +288,8 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev) static int otm8009a_panel_get_display_timing(struct udevice *dev, struct display_timing *timings) { - struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); - struct mipi_dsi_device *device = plat->device; - struct otm8009a_panel_priv *priv = dev_get_priv(dev); - memcpy(timings, &default_timing, sizeof(*timings)); - /* fill characteristics of DSI data link */ - device->lanes = priv->lanes; - device->format = priv->format; - device->mode_flags = priv->mode_flags; - return 0; } @@ -333,6 +321,7 @@ static int otm8009a_panel_ofdata_to_platdata(struct udevice *dev) static int otm8009a_panel_probe(struct udevice *dev) { struct otm8009a_panel_priv *priv = dev_get_priv(dev); + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev); int ret; if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { @@ -348,9 +337,10 @@ static int otm8009a_panel_probe(struct udevice *dev) dm_gpio_set_value(&priv->reset, false); mdelay(10); /* >5ms */ - priv->lanes = 2; - priv->format = MIPI_DSI_FMT_RGB888; - priv->mode_flags = MIPI_DSI_MODE_VIDEO | + /* fill characteristics of DSI data link */ + plat->lanes = 2; + plat->format = MIPI_DSI_FMT_RGB888; + plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; From 11e5838cdb4a967276b3a68d0dafec10389343ed Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 12 Nov 2019 11:22:36 +0100 Subject: [PATCH 226/244] Add config for target STM32MP157C-DK2 Add config for target STM32MP157C-DK2= CONFIG_TARGET_STM32MP157C_DK2 allow to reduce the size of U-Boot when the support of st board dk2 is not needed. Change-Id: Ie3300eb16e734851a3d58bcf4f029c3066165513 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/149503 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- board/st/stm32mp1/Kconfig | 4 ++++ board/st/stm32mp1/stm32mp1.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/board/st/stm32mp1/Kconfig b/board/st/stm32mp1/Kconfig index 92d8f901ff82..6a06e5b87b02 100644 --- a/board/st/stm32mp1/Kconfig +++ b/board/st/stm32mp1/Kconfig @@ -16,4 +16,8 @@ config CMD_STBOARD This compile the stboard command to read and write the board in the OTP. +config TARGET_STM32MP157C_DK2 + bool "support of STMicroelectronics STM32MP157C-DK2 Discovery Board" + default y + endif diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index e09b39f47efe..822b6d77f6c8 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -882,7 +882,8 @@ const char *env_ext4_get_dev_part(void) static __maybe_unused bool board_is_dk2(void) { - if (of_machine_is_compatible("st,stm32mp157c-dk2")) + if (CONFIG_IS_ENABLED(TARGET_STM32MP157C_DK2) && + of_machine_is_compatible("st,stm32mp157c-dk2")) return true; return false; From f21da5ab66ba00070483213cce854ef453cbf754 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Nov 2019 09:08:27 +0100 Subject: [PATCH 227/244] stm32mp1: add bsec driver in SPL Add the bsec driver in SPL, as it is needed by SOC part number detection. Signed-off-by: Patrick Delaunay Change-Id: I7a042a9ffbb5c2668034eddf5ace91271bb53c5f Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151662 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157-u-boot.dtsi | 2 +- arch/arm/mach-stm32mp/Makefile | 3 +-- arch/arm/mach-stm32mp/bsec.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 98cf1aa6575a..1bea6c34492f 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -47,7 +47,7 @@ }; &bsec { - u-boot,dm-pre-proper; + u-boot,dm-pre-reloc; }; &clk_csi { diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 9158a20e3f54..13e7773df8d2 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -6,6 +6,7 @@ obj-y += cpu.o obj-y += dram_init.o obj-y += syscon.o +obj-y += bsec.o ifdef CONFIG_SPL_BUILD obj-y += spl.o @@ -13,8 +14,6 @@ obj-$(CONFIG_STM32MP1_RESET_HALT_WORKAROUND) += stm32mp1_helper_dbg.o else obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/ obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o - -obj-y += bsec.o obj-$(CONFIG_SYSRESET) += cmd_poweroff.o obj-$(CONFIG_ARMV7_PSCI) += psci.o endif diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c index 52563780e07e..fa7f39f6909a 100644 --- a/arch/arm/mach-stm32mp/bsec.c +++ b/arch/arm/mach-stm32mp/bsec.c @@ -436,7 +436,7 @@ static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) return 0; } -#ifndef CONFIG_STM32MP1_TRUSTED +#if !defined(CONFIG_STM32MP1_TRUSTED) && !defined(CONFIG_SPL_BUILD) static int stm32mp_bsec_probe(struct udevice *dev) { int otp; @@ -463,7 +463,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 +#if !defined(CONFIG_STM32MP1_TRUSTED) && !defined(CONFIG_SPL_BUILD) .probe = stm32mp_bsec_probe, #endif }; From 67d6c2455236bd0571a1b05889d7877dcf109f93 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Nov 2019 13:53:01 +0100 Subject: [PATCH 228/244] stm32mp1: spl: display error in board_init_f Update board_init_f and try to display error message when console is available. Signed-off-by: Patrick Delaunay Change-Id: I41a641a07fd12da45b392920fc3407e608926396 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151663 Reviewed-by: CITOOLS --- arch/arm/mach-stm32mp/spl.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 6c8744f8dc34..c0474e0954fe 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -88,39 +88,38 @@ void spl_display_print(void) void board_init_f(ulong dummy) { struct udevice *dev; - int ret; + int ret, clk, reset, pinctrl; arch_cpu_init(); ret = spl_early_init(); if (ret) { - debug("spl_early_init() failed: %d\n", ret); + debug("%s: spl_early_init() failed: %d\n", __func__, ret); hang(); } - ret = uclass_get_device(UCLASS_CLK, 0, &dev); - if (ret) { - debug("Clock init failed: %d\n", ret); - return; - } + clk = uclass_get_device(UCLASS_CLK, 0, &dev); + if (clk) + debug("%s: Clock init failed: %d\n", __func__, clk); - ret = uclass_get_device(UCLASS_RESET, 0, &dev); - if (ret) { - debug("Reset init failed: %d\n", ret); - return; - } + reset = uclass_get_device(UCLASS_RESET, 0, &dev); + if (reset) + debug("%s: Reset init failed: %d\n", __func__, reset); - ret = uclass_get_device(UCLASS_PINCTRL, 0, &dev); - if (ret) { - debug("%s: Cannot find pinctrl device\n", __func__); - return; - } + pinctrl = uclass_get_device(UCLASS_PINCTRL, 0, &dev); + if (pinctrl) + debug("%s: Cannot find pinctrl device: %d\n", + __func__, pinctrl); /* enable console uart printing */ preloader_console_init(); watchdog_start(); + if (clk || reset || pinctrl) + printf("%s: probe failed clk=%d reset=%d pinctrl=%d\n", + __func__, clk, reset, pinctrl); + ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { printf("DRAM init failed: %d\n", ret); From 022dea8d36c2861717737f8d27dcb4455652361c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 28 Nov 2019 19:38:58 +0100 Subject: [PATCH 229/244] stm32mp1: clk: configure pll1 with OPP The PLL1 node (st,pll1) is optional in device tree, the max supported frequency define in OPP node is used when the node is absent. Change-Id: Iaff7f49da0cc8a01050b402be816b4c5c739fe56 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151664 Reviewed-by: CITOOLS Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- arch/arm/dts/stm32mp157-u-boot.dtsi | 10 + arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 7 - arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi | 7 - .../clock/st,stm32mp1.txt | 4 + drivers/clk/clk_stm32mp1.c | 279 ++++++++++++++++-- 5 files changed, 267 insertions(+), 40 deletions(-) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index 1bea6c34492f..1c1a7cc4c751 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -70,6 +70,16 @@ u-boot,dm-pre-reloc; }; +&cpu0_opp_table { + u-boot,dm-spl; + opp-650000000 { + u-boot,dm-spl; + }; + opp-800000000 { + u-boot,dm-spl; + }; +}; + &gpioa { u-boot,dm-pre-reloc; }; diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi index 757df241051b..7bc2b7f71f2c 100644 --- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi @@ -121,13 +121,6 @@ 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) >; diff --git a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi index 5ab4eeb183f1..898155ff65c7 100644 --- a/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-ed1-u-boot.dtsi @@ -119,13 +119,6 @@ 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) >; diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt index ec1d703f34ec..a70331801b1b 100644 --- a/doc/device-tree-bindings/clock/st,stm32mp1.txt +++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt @@ -84,6 +84,10 @@ Optional Properties: are listed with associated index 0 to 3 (st,pll@0 to st,pll@3). PLLx is off when the associated node is absent. + For PLL1, when the node is absent, the frequency of the OPP node is used + to compute the PLL setting (see compatible "operating-points-v2" in + opp/opp.txt for details). + Here are the available properties for each PLL node: - cfg: The parameters for PLL configuration in the following order: diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 2d7b185f9fd2..787eb4be2c82 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -650,8 +650,18 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { }; #ifdef STM32MP1_CLOCK_TREE_INIT + /* define characteristic of PLL according type */ +#define DIVM_MIN 0 +#define DIVM_MAX 63 #define DIVN_MIN 24 +#define DIVP_MIN 0 +#define DIVP_MAX 127 +#define FRAC_MAX 8192 + +#define PLL1600_VCO_MIN 800000000 +#define PLL1600_VCO_MAX 1600000000 + static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { [PLL_800] = { .refclk_min = 4, @@ -1206,6 +1216,206 @@ static ulong stm32mp1_clk_get_rate(struct clk *clk) } #ifdef STM32MP1_CLOCK_TREE_INIT + +bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type) +{ + unsigned int id; + + switch (opp_id) { + case 1: + case 2: + id = opp_id; + break; + default: + id = 1; /* default value */ + break; + } + + switch (cpu_type) { + case CPU_STM32MP157Fxx: + case CPU_STM32MP157Dxx: + case CPU_STM32MP153Fxx: + case CPU_STM32MP153Dxx: + case CPU_STM32MP151Fxx: + case CPU_STM32MP151Dxx: + return true; + default: + return id == 1; + } +} + +/* + * gets OPP parameters (frequency in KHz and voltage in mV) from + * an OPP table subnode. Platform HW support capabilities are also checked. + * Returns 0 on success and a negative FDT error code on failure. + */ +static int stm32mp1_get_opp(u32 cpu_type, ofnode subnode, + u32 *freq_khz, u32 *voltage_mv) +{ + u32 opp_hw; + u64 read_freq_64; + u32 read_voltage_32; + + *freq_khz = 0; + *voltage_mv = 0; + + opp_hw = ofnode_read_u32_default(subnode, "opp-supported-hw", 0); + if (opp_hw) + if (!stm32mp1_supports_opp(opp_hw, cpu_type)) + return -FDT_ERR_BADVALUE; + + read_freq_64 = ofnode_read_u64_default(subnode, "opp-hz", 0) / + 1000ULL; + read_voltage_32 = ofnode_read_u32_default(subnode, "opp-microvolt", 0) / + 1000U; + + if (!read_voltage_32 || !read_freq_64) + return -FDT_ERR_NOTFOUND; + + /* Frequency value expressed in KHz must fit on 32 bits */ + if (read_freq_64 > U32_MAX) + return -FDT_ERR_BADVALUE; + + /* Millivolt value must fit on 16 bits */ + if (read_voltage_32 > U16_MAX) + return -FDT_ERR_BADVALUE; + + *freq_khz = (u32)read_freq_64; + *voltage_mv = read_voltage_32; + + return 0; +} + +/* + * parses OPP table in DT and finds the parameters for the + * highest frequency supported by the HW platform. + * Returns 0 on success and a negative FDT error code on failure. + */ +int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz) +{ + ofnode node, subnode; + int ret; + u32 freq = 0U, voltage = 0U; + u32 cpu_type = get_cpu_type(); + + node = ofnode_by_compatible(ofnode_null(), "operating-points-v2"); + if (!ofnode_valid(node)) + return -FDT_ERR_NOTFOUND; + + ofnode_for_each_subnode(subnode, node) { + unsigned int read_freq; + unsigned int read_voltage; + + ret = stm32mp1_get_opp(cpu_type, subnode, + &read_freq, &read_voltage); + if (ret) + continue; + + if (read_freq > freq) { + freq = read_freq; + voltage = read_voltage; + } + } + + if (!freq || !voltage) + return -FDT_ERR_NOTFOUND; + + *freq_hz = (u64)1000U * freq; + + return 0; +} + +static int stm32mp1_pll1_opp(struct stm32mp1_clk_priv *priv, int clksrc, + u32 *pllcfg, u32 *fracv) +{ + u32 post_divm; + u32 input_freq; + u64 output_freq; + u64 freq; + u64 vco; + u32 divm, divn, divp, frac; + int i, ret; + u32 diff; + u32 best_diff = U32_MAX; + + /* PLL1 is 1600 */ + const u32 DIVN_MAX = stm32mp1_pll[PLL_1600].divn_max; + const u32 POST_DIVM_MIN = stm32mp1_pll[PLL_1600].refclk_min * 1000000U; + const u32 POST_DIVM_MAX = stm32mp1_pll[PLL_1600].refclk_max * 1000000U; + + ret = stm32mp1_get_max_opp_freq(priv, &output_freq); + if (ret) + return ret; + + switch (clksrc) { + case CLK_PLL12_HSI: + input_freq = stm32mp1_clk_get_fixed(priv, _HSI); + break; + case CLK_PLL12_HSE: + input_freq = stm32mp1_clk_get_fixed(priv, _HSE); + break; + default: + return -EINTR; + } + + /* Following parameters have always the same value */ + pllcfg[PLLCFG_Q] = 0; + pllcfg[PLLCFG_R] = 0; + pllcfg[PLLCFG_O] = PQR(1, 0, 0); + + for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) { + post_divm = (u32)(input_freq / (divm + 1)); + if (post_divm < POST_DIVM_MIN || post_divm > POST_DIVM_MAX) + continue; + + for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) { + freq = output_freq * (divm + 1) * (divp + 1); + divn = (u32)((freq / input_freq) - 1); + if (divn < DIVN_MIN || divn > DIVN_MAX) + continue; + + frac = (u32)(((freq * FRAC_MAX) / input_freq) - + ((divn + 1) * FRAC_MAX)); + /* 2 loops to refine the fractional part */ + for (i = 2; i != 0; i--) { + if (frac > FRAC_MAX) + break; + + vco = (post_divm * (divn + 1)) + + ((post_divm * (u64)frac) / + FRAC_MAX); + if (vco < (PLL1600_VCO_MIN / 2) || + vco > (PLL1600_VCO_MAX / 2)) { + frac++; + continue; + } + freq = vco / (divp + 1); + if (output_freq < freq) + diff = (u32)(freq - output_freq); + else + diff = (u32)(output_freq - freq); + if (diff < best_diff) { + pllcfg[PLLCFG_M] = divm; + pllcfg[PLLCFG_N] = divn; + pllcfg[PLLCFG_P] = divp; + *fracv = frac; + + if (diff == 0) + return 0; + + best_diff = diff; + } + frac++; + } + } + } + + if (best_diff == U32_MAX) + return -1; + + return 0; +} + static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset, u32 mask_on) { @@ -1678,7 +1888,10 @@ static int stm32mp1_clktree(struct udevice *dev) unsigned int clksrc[CLKSRC_NB]; unsigned int clkdiv[CLKDIV_NB]; unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; - ofnode plloff[_PLL_NB]; + unsigned int pllfracv[_PLL_NB]; + unsigned int pllcsg[_PLL_NB][PLLCSG_NB]; + bool pllcfg_valid[_PLL_NB]; + bool pllcsg_set[_PLL_NB]; int ret; int i, len; int lse_css = 0; @@ -1700,16 +1913,41 @@ static int stm32mp1_clktree(struct udevice *dev) /* check mandatory field in each pll */ for (i = 0; i < _PLL_NB; i++) { char name[12]; + ofnode node; sprintf(name, "st,pll@%d", i); - plloff[i] = dev_read_subnode(dev, name); - if (!ofnode_valid(plloff[i])) - continue; - ret = ofnode_read_u32_array(plloff[i], "cfg", - pllcfg[i], PLLCFG_NB); - if (ret < 0) { - debug("field cfg invalid: error %d\n", ret); - return -FDT_ERR_NOTFOUND; + node = dev_read_subnode(dev, name); + pllcfg_valid[i] = ofnode_valid(node); + pllcsg_set[i] = false; + if (pllcfg_valid[i]) { + debug("DT for PLL %d @ %s\n", i, name); + ret = ofnode_read_u32_array(node, "cfg", + pllcfg[i], PLLCFG_NB); + if (ret < 0) { + debug("field cfg invalid: error %d\n", ret); + return -FDT_ERR_NOTFOUND; + } + pllfracv[i] = ofnode_read_u32_default(node, "frac", 0); + + ret = ofnode_read_u32_array(node, "csg", pllcsg[i], + PLLCSG_NB); + if (!ret) { + pllcsg_set[i] = true; + } else if (ret != -FDT_ERR_NOTFOUND) { + debug("invalid csg node for pll@%d res=%d\n", + i, ret); + return ret; + } + } else if (i == _PLL1) { + /* use OPP for PLL1 for A7 CPU */ + debug("DT for PLL %d with OPP\n", i); + ret = stm32mp1_pll1_opp(priv, + clksrc[CLKSRC_PLL12], + pllcfg[i], + &pllfracv[i]); + if (ret) + return ret; + pllcfg_valid[i] = true; } } @@ -1794,29 +2032,18 @@ static int stm32mp1_clktree(struct udevice *dev) /* configure and start PLLs */ debug("configure PLLs\n"); for (i = 0; i < _PLL_NB; i++) { - u32 fracv; - u32 csg[PLLCSG_NB]; - - debug("configure PLL %d @ %d\n", i, - ofnode_to_offset(plloff[i])); - if (!ofnode_valid(plloff[i])) + if (!pllcfg_valid[i]) continue; - - fracv = ofnode_read_u32_default(plloff[i], "frac", 0); - pll_config(priv, i, pllcfg[i], fracv); - ret = ofnode_read_u32_array(plloff[i], "csg", csg, PLLCSG_NB); - if (!ret) { - pll_csg(priv, i, csg); - } else if (ret != -FDT_ERR_NOTFOUND) { - debug("invalid csg node for pll@%d res=%d\n", i, ret); - return ret; - } + debug("configure PLL %d\n", i); + pll_config(priv, i, pllcfg[i], pllfracv[i]); + if (pllcsg_set[i]) + pll_csg(priv, i, pllcsg[i]); pll_start(priv, i); } /* wait and start PLLs ouptut when ready */ for (i = 0; i < _PLL_NB; i++) { - if (!ofnode_valid(plloff[i])) + if (!pllcfg_valid[i]) continue; debug("output PLL %d\n", i); pll_output(priv, i, pllcfg[i][PLLCFG_O]); From ed513fa81653e6086af33a30805b6414905e4883 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 2 Dec 2019 10:18:32 +0100 Subject: [PATCH 230/244] stm32mp1: update vddcore if needed Update the vddcore with information of OPP when needed. VDDCORE is provided by BUCK1 of STMPIC1 Change-Id: I845d08dcbe270a6b9339cdca96d25b1f4ce0e13e Signed-off-by: Patrick Delaunay Change-Id: Ia3b4a5043eb1e152baecea5fabd0e1673135ac06 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/151665 Reviewed-by: CITOOLS --- .../arm/mach-stm32mp/include/mach/sys_proto.h | 4 +++ arch/arm/mach-stm32mp/spl.c | 16 ++++++--- board/st/stm32mp1/board.c | 34 +++++++++++++++++++ drivers/clk/clk_stm32mp1.c | 5 +++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h index 731a53e46c79..0ede1e75cd18 100644 --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h @@ -39,3 +39,7 @@ u32 get_cpu_package(void); u32 get_bootmode(void); /* start IWDG watchdog */ int watchdog_start(void); + +/* board power management : configure vddcore according OPP */ +void board_vddcore_init(u32 voltage_mv); +int board_vddcore_set(void); diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index c0474e0954fe..74b56f9df20a 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -85,10 +85,15 @@ void spl_display_print(void) } #endif +__weak int board_vddcore_set(void) +{ + return 0; +} + void board_init_f(ulong dummy) { struct udevice *dev; - int ret, clk, reset, pinctrl; + int ret, clk, reset, pinctrl, power; arch_cpu_init(); @@ -116,9 +121,12 @@ void board_init_f(ulong dummy) watchdog_start(); - if (clk || reset || pinctrl) - printf("%s: probe failed clk=%d reset=%d pinctrl=%d\n", - __func__, clk, reset, pinctrl); + /* change vddcore if needed after clock tree init */ + power = board_vddcore_set(); + + if (clk || reset || pinctrl || power) + printf("%s: probe failed clk=%d reset=%d pinctrl=%d power=%d\n", + __func__, clk, reset, pinctrl, power); ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c index 4e35d36c76dd..3e38aefad3e8 100644 --- a/board/st/stm32mp1/board.c +++ b/board/st/stm32mp1/board.c @@ -38,6 +38,40 @@ void board_debug_uart_init(void) #endif #ifdef CONFIG_PMIC_STPMIC1 +u32 opp_voltage_mv; + +void board_vddcore_init(u32 voltage_mv) +{ + opp_voltage_mv = voltage_mv; +} + +int board_vddcore_set(void) +{ + struct udevice *dev; + int ret; + u32 value; + + if (!opp_voltage_mv) + return 0; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmic1), &dev); + if (ret) + return ret; + + /* VDDCORE= STMPCI1 BUCK1 ramp=+25mV, 5 => 725mV, 36 => 1500mV */ + value = ((opp_voltage_mv - 725) / 25) + 5; + if (value < 5) + value = 5; + if (value > 36) + value = 36; + + return pmic_clrsetbits(dev, + STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK1), + STPMIC1_BUCK_VOUT_MASK, + STPMIC1_BUCK_VOUT(value)); +} + int board_ddr_power_init(enum ddr_type ddr_type) { struct udevice *dev; diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 787eb4be2c82..a6503e45869c 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -1244,6 +1244,10 @@ bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type) } } +__weak void board_vddcore_init(u32 voltage_mv) +{ +} + /* * gets OPP parameters (frequency in KHz and voltage in mV) from * an OPP table subnode. Platform HW support capabilities are also checked. @@ -1321,6 +1325,7 @@ int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz) return -FDT_ERR_NOTFOUND; *freq_hz = (u64)1000U * freq; + board_vddcore_init(voltage); return 0; } From cbe462a12333fc573010a8afca5f67569da84f05 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 17 Dec 2019 09:53:46 +0100 Subject: [PATCH 231/244] stm32mp1: update MAC address provisioning Add Prerequisite: check if MAC address is not yet provisioned. and add Warning for second provisioning. Signed-off-by: Patrick Delaunay Change-Id: Ida7462afcb326e0761d6bbb355b3a9a8e96fb25b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/153325 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- board/st/stm32mp1/README | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index b710602634d1..782b9d18a9e0 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -305,7 +305,20 @@ Mac id storage and retrieval in stm32mp otp : To program a MAC address on virgin OTP words above, you can use the fuse command on bank 0 to access to internal OTP: - example to set mac address "12:34:56:78:9a:bc" + Prerequisite: check if a MAC address isn't yet programmed in OTP + + 1- check OTP: their value must be equal to 0 + + STM32MP> fuse sense 0 57 2 + Sensing bank 0: + Word 0x00000039: 00000000 00000000 + + 2- check environment variable + + STM32MP> env print ethaddr + ## Error: "ethaddr" not defined + + Example to set mac address "12:34:56:78:9a:bc" 1- Write OTP STM32MP> fuse prog -y 0 57 0x78563412 0x0000bc9a @@ -319,9 +332,13 @@ on bank 0 to access to internal OTP: ### Setting environment from OTP MAC address = "12:34:56:78:9a:bc" 4 check env update - STM32MP> print ethaddr + STM32MP> env print ethaddr ethaddr=12:34:56:78:9a:bc +warning:: This MAC address provisioning can't be executed twice on the same + board as the OTP are protected. It is already done for the board + provided by STMicroelectronics. + 10. Coprocessor firmware ======================== From 2e43485f809ae6b54a574e07b26fc58df5ea49b1 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Wed, 18 Dec 2019 11:49:08 +0100 Subject: [PATCH 232/244] video: check hardware version of DSI Check the hardware version of DSI. Versions 1.30 & 1.31 are only supported. Rename the parameter priv by dsi into all functions. Signed-off-by: Yannick Fertre Change-Id: I2dfe8dcedc96e193ae35e0048bddafc39b13903f Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/153674 Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- drivers/video/stm32/stm32_dsi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index 8ba6cd4de3ac..c7967e51a6ca 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -268,7 +268,6 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, u32 val; /* Update lane capabilities according to hw version */ - dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; dsi->lane_min_kbps = LANE_MIN_KBPS; dsi->lane_max_kbps = LANE_MAX_KBPS; if (dsi->hw_version == HWVER_131) { @@ -473,6 +472,17 @@ static int stm32_dsi_probe(struct udevice *dev) /* Reset */ reset_deassert(&rst); + /* check hardware version */ + priv->hw_version = dsi_read(priv, DSI_VERSION) & VERSION; + if (priv->hw_version != HWVER_130 && + priv->hw_version != HWVER_131) { + dev_err(dev, "bad dsi hardware version\n"); + clk_disable(&clk); + if (IS_ENABLED(CONFIG_DM_REGULATOR)) + regulator_set_enable(priv->vdd_reg, false); + return -ENODEV; + } + return 0; err_clk: clk_disable(&clk); From 8028962d9fcbb539c62133b551b972717af132c6 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Thu, 19 Dec 2019 09:45:10 +0100 Subject: [PATCH 233/244] video: stm32: stm32_dsi: don't enable regulator if no dt entry Regulator phy_dsi is not mandatory and its related device tree entry could be then not defined. This patch checks the dt entry before enabling the regulator preventing error when not present. Signed-off-by: Yannick Fertre Change-Id: Ibf022e279ae4bcb6627a7ace19b8279833554eb1 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/153675 Reviewed-by: Philippe CORNU Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY Tested-by: Patrick DELAUNAY --- drivers/video/stm32/stm32_dsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index c7967e51a6ca..022ae96a7152 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -438,9 +438,11 @@ static int stm32_dsi_probe(struct udevice *dev) return -ENODEV; } - ret = regulator_set_enable(priv->vdd_reg, true); - if (ret) - return -ENODEV; + if (ret != -ENOENT) { + ret = regulator_set_enable(priv->vdd_reg, true); + if (ret) + return ret; + } } ret = clk_get_by_name(device->dev, "pclk", &clk); From fd915f073fe23fea3eb509dbc26ac9da1893692a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 4 Sep 2019 17:08:30 +0200 Subject: [PATCH 234/244] Prepare v2018.11-stm32mp-r4 Signed-off-by: Patrick Delaunay Change-Id: Iec3c340613a9cf693fb1264e13749b3e7c077472 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 61d804cee422..4c72fc129327 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r3.2 +EXTRAVERSION = -stm32mp-r4 NAME = # *DOCUMENTATION* From 9ad9213d1eb5cfdabc59226d8381c853c1612c44 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 1 Oct 2019 11:27:07 +0200 Subject: [PATCH 235/244] ram: stm32mp1: display result for software read DQS gating Display result information for software read DQS gating, the tuning 0 which be used by CubeMX DDR tuning tools. Signed-off-by: Patrick Delaunay Change-Id: I7aa349c91deffa4a6f096fbadfa22b01844a7c4d Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/158877 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index b928ac2d5166..2508284d9d62 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1348,15 +1348,17 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]); pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n"); - set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]); - set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]); } } else { /* if intermitant, restore defaut values */ pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n"); - set_r0dgsl_delay(phy, byte, 0); - set_r0dgps_delay(phy, byte, 2); + dqs_gate_values[byte][0] = 0; + dqs_gate_values[byte][1] = 2; } + set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]); + set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]); + printf("Byte %d, R0DGSL = %d, R0DGPS = %d\n", + byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]); /* return 0 if intermittent or if both left_bound * and right_bound are not found From a03ab0db022f332eaa52fd85782db3e80d40ab7b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 Feb 2020 16:48:24 +0100 Subject: [PATCH 236/244] Prepare v2018.11-stm32mp-r4.1 Signed-off-by: Patrick Delaunay Change-Id: I362c2b9cd2d7a1dbd9a6365eeb3f59f470dfd639 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4c72fc129327..7f944516c7c1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r4 +EXTRAVERSION = -stm32mp-r4.1 NAME = # *DOCUMENTATION* From c02d4956a05367bddaa46aef6c239f8dfff5b35f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 5 Feb 2020 13:31:25 +0100 Subject: [PATCH 237/244] stm32mp1: ram: tuning: add timeout for polling BISTGSR.BDDONE Avoid to block the tuning procedure on BIST error (not finished BIST procedure) by adding a 1000us timeout on the polling of BISTGSR.BDDONE executed to detect the end of BIST. The normal duration of the BIST test is around 5us. This patch also cleanup comments. Signed-off-by: Patrick Delaunay Change-Id: If03eb32f9863bed008f5367b47116f667bb85099 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/156979 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 45 ++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 2508284d9d62..598dff3258b5 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "stm32mp1_ddr_regs.h" #include "stm32mp1_ddr.h" @@ -355,6 +356,8 @@ static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, bool result = true; /* BIST_SUCCESS */ u32 cnt = 0; u32 error = 0; + u32 val; + int ret; bist->test_result = true; @@ -383,27 +386,29 @@ static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, 0x00000001); /* Write BISTRR.BINST = 3?b001; */ - /* Wait for a number of CTL clocks before reading BIST register*/ - /* Wait 300 ctl_clk cycles; ... IS it really needed?? */ - /* Perform BIST Instruction Stop*/ - /* Write BISTRR.BINST = 3?b010;*/ - - /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */ - while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE)) - ; - - /*Check if received correct number of words*/ - /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */ - if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) == - readl(&phy->bistwcr)) { - /*Determine if there is a data comparison error*/ - /* if (Read BISTGSR.BDXERR = 1?b0) */ - if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR) - result = false; /* BIST_FAIL; */ - else - result = true; /* BIST_SUCCESS; */ - } else { + /* poll on BISTGSR.BDONE and wait max 1000 us */ + ret = readl_poll_timeout(&phy->bistgsr, val, + val & DDRPHYC_BISTGSR_BDDONE, 1000); + + if (ret < 0) { + printf("warning: BIST timeout\n"); result = false; /* BIST_FAIL; */ + /*Perform BIST Stop */ + clrsetbits_le32(&phy->bistrr, 0x00000007, 0x00000002); + } else { + /*Check if received correct number of words*/ + /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */ + if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) + == readl(&phy->bistwcr)) { + /*Determine if there is a data comparison error*/ + /* if (Read BISTGSR.BDXERR = 1?b0) */ + if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR) + result = false; /* BIST_FAIL; */ + else + result = true; /* BIST_SUCCESS; */ + } else { + result = false; /* BIST_FAIL; */ + } } /* loop while success */ From 6b96656fb293db6b785ac0aab4aefb7601222268 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 17 Feb 2020 17:25:47 +0100 Subject: [PATCH 238/244] ram: stm32mp1: tuning: deactivate derating during BIST test The derating (timing parameter derating using MR4 read value) can't be activated during BIST test, as the MR4 read answer will be not understood by BIST (BISTGSR.BDONE bit stay at 0, BISTWCSR.DXWCNT = 0x206 instead of BISTWCR.BWCNT = 0x200). This patch only impacts the tuning on LPDDR2/LPDDR3, if derateen.derate_enable = 1. Signed-off-by: Patrick Delaunay Change-Id: I2f3d97c071fc1de6dae7e15ee0bbc1df0f16fd9a Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/158386 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 598dff3258b5..773798810494 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1454,11 +1454,16 @@ static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = read_dqs_gating(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } @@ -1469,11 +1474,16 @@ static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = bit_deskew(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } @@ -1484,11 +1494,16 @@ static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl, { u32 rfshctl3 = readl(&ctl->rfshctl3); u32 pwrctl = readl(&ctl->pwrctl); + u32 derateen = readl(&ctl->derateen); enum test_result res; + writel(0x0, &ctl->derateen); stm32mp1_refresh_disable(ctl); + res = eye_training(ctl, phy, string); + stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl); + writel(derateen, &ctl->derateen); return res; } From c5ddca8dbebecbc29dca9825240668a4d5f246e7 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 17 Feb 2020 18:46:15 +0100 Subject: [PATCH 239/244] stm32mp1: ram: tuning: update BIST config Update the BIST config to compute the real use mask for the real bank, row and col of the used DDR. The values are get from addrmap register value. Signed-off-by: Patrick Delaunay Change-Id: Id09f75f6aa43a345f0eccb009481c6423933358b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/158527 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- drivers/ram/stm32mp1/stm32mp1_tuning.c | 151 +++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 9 deletions(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 773798810494..914062a4c0b3 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "stm32mp1_ddr_regs.h" @@ -81,6 +82,133 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl) return nb_bytes; } +static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl) +{ + /* Count bank address bits */ + u8 bits = 0; + u32 reg, val; + + reg = readl(&ctl->addrmap1); + /* addrmap1.addrmap_bank_b1 */ + val = (reg & GENMASK(5, 0)) >> 0; + if (val <= 31) + bits++; + /* addrmap1.addrmap_bank_b2 */ + val = (reg & GENMASK(13, 8)) >> 8; + if (val <= 31) + bits++; + /* addrmap1.addrmap_bank_b3 */ + val = (reg & GENMASK(21, 16)) >> 16; + if (val <= 31) + bits++; + + return bits; +} + +static u8 get_nb_col(struct stm32mp1_ddrctl *ctl) +{ + u8 bits; + u32 reg, val; + + /* Count column address bits, start at 2 for b0 and b1 (fixed) */ + bits = 2; + + reg = readl(&ctl->addrmap2); + /* addrmap2.addrmap_col_b2 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b3 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b4 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap2.addrmap_col_b5 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + reg = readl(&ctl->addrmap3); + /* addrmap3.addrmap_col_b6 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b7 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b8 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap3.addrmap_col_b9 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + reg = readl(&ctl->addrmap4); + /* addrmap4.addrmap_col_b10 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap4.addrmap_col_b11 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + + return bits; +} + +static u8 get_nb_row(struct stm32mp1_ddrctl *ctl) +{ + /* Count row address bits */ + u8 bits = 0; + u32 reg, val; + + reg = readl(&ctl->addrmap5); + /* addrmap5.addrmap_row_b0 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 11) + bits++; + /* addrmap5.addrmap_row_b1 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 11) + bits++; + /* addrmap5.addrmap_row_b2_10 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 11) + bits += 9; + else + printf("warning: addrmap5.addrmap_row_b2_10 not supported\n"); + /* addrmap5.addrmap_row_b11 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 11) + bits++; + + reg = readl(&ctl->addrmap6); + /* addrmap6.addrmap_row_b12 */ + val = (reg & GENMASK(3, 0)) >> 0; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b13 */ + val = (reg & GENMASK(11, 8)) >> 8; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b14 */ + val = (reg & GENMASK(19, 16)) >> 16; + if (val <= 7) + bits++; + /* addrmap6.addrmap_row_b15 */ + val = (reg & GENMASK(27, 24)) >> 24; + if (val <= 7) + bits++; + + return bits; +} + static void itm_soft_reset(struct stm32mp1_ddrphy *phy) { stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); @@ -279,8 +407,13 @@ static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, } /* Basic BIST configuration for data lane tests. */ -static void config_BIST(struct stm32mp1_ddrphy *phy) +static void config_BIST(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy) { + u8 nb_bank = get_nb_bank(ctl); + u8 nb_row = get_nb_row(ctl); + u8 nb_col = get_nb_col(ctl); + /* Selects the SDRAM bank address to be used during BIST. */ u32 bbank = 0; /* Selects the SDRAM row address to be used during BIST. */ @@ -300,18 +433,20 @@ static void config_BIST(struct stm32mp1_ddrphy *phy) * must be 0 with single rank */ u32 brank = 0; + /* Specifies the maximum SDRAM bank address to be used during * BIST before the address & increments to the next rank. */ - u32 bmbank = 1; + u32 bmbank = (1 << nb_bank) - 1; /* Specifies the maximum SDRAM row address to be used during * BIST before the address & increments to the next bank. */ - u32 bmrow = 0x7FFF; /* To check */ + u32 bmrow = (1 << nb_row) - 1; /* Specifies the maximum SDRAM column address to be used during * BIST before the address & increments to the next row. */ - u32 bmcol = 0x3FF; /* To check */ + u32 bmcol = (1 << nb_col) - 1; + u32 bmode_conf = 0x00000001; /* DRam mode */ u32 bdxen_conf = 0x00000001; /* BIST on Data byte */ u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */ @@ -333,8 +468,6 @@ static void config_BIST(struct stm32mp1_ddrphy *phy) writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0); writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1); - - /* To check this line : */ writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2); } @@ -539,7 +672,7 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* Config the BIST block */ - config_BIST(phy); + config_BIST(ctl, phy); pr_debug("BIST Config done.\n"); /* Train each byte */ @@ -978,7 +1111,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* Config the BIST block */ - config_BIST(phy); + config_BIST(ctl, phy); for (byte = 0; byte < nb_bytes; byte++) { if (ctrlc()) { @@ -1400,7 +1533,7 @@ static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); /* config the bist block */ - config_BIST(phy); + config_BIST(ctl, phy); for (byte = 0; byte < nb_bytes; byte++) { if (ctrlc()) { From c423e7af2ec6c48159827deb82812d091278f7ec Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 12 Feb 2020 11:02:08 +0100 Subject: [PATCH 240/244] ddr: stm32mp1_ddr: fix self refresh disable during DQS training DDRCTRL_PWRCTL.SELFREF_EN needs to be reset before DQS training step, not to enter in self refresh mode during the execution of this phase. Depending on settings, it can be set after the DQS training. Signed-off-by: Patrick Delaunay Change-Id: I0f31274f26e4299269ef3c7d5a581d2abe96aad2 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/157796 --- drivers/ram/stm32mp1/stm32mp1_ddr.c | 5 ++++- drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index c87882deed2d..d32d53bc81c1 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -826,7 +826,8 @@ void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) start_sw_done(ctl); /* quasi-dynamic register update*/ setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); - clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); + clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN | + DDRCTRL_PWRCTL_SELFREF_EN); clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); wait_sw_done_ack(ctl); } @@ -839,6 +840,8 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); + if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN)) + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); wait_sw_done_ack(ctl); } diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h index 9d33186b3a25..afd93c518eb5 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h @@ -260,6 +260,7 @@ struct stm32mp1_ddrphy { #define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0) +#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) From 6238f677b2b1aaba9048a487ca83fdc7bf5b6705 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 3 Mar 2020 09:40:01 +0100 Subject: [PATCH 241/244] stm32mp1: Fix warning display when 1.5A power supply is used On DK1/2 board, when a 1.5A power supply is detected, a warning message is displayed. In this message, "1.5mA" is displayed instead of "1.5A". Signed-off-by: Patrice Chotard Change-Id: I27624bb6ba6af81e6f3524bcc904a0c9608ae5cb Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/159744 Tested-by: Patrick DELAUNAY Reviewed-by: CITOOLS Reviewed-by: CIBUILD Reviewed-by: Patrick DELAUNAY --- board/st/stm32mp1/stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 822b6d77f6c8..fbbe7d8ee189 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -642,7 +642,7 @@ static int board_check_usb_power(void) if (max_uV > USB_WARNING_LOW_THRESHOLD_UV && max_uV <= USB_START_LOW_THRESHOLD_UV && min_uV <= USB_LOW_THRESHOLD_UV) { - pr_err("* WARNING 1.5mA power supply detected *\n"); + pr_err("* WARNING 1.5A power supply detected *\n"); nb_blink = 3; } From e155e37720074744fece9bfce67f1963b214ba1c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 9 Mar 2020 15:29:11 +0100 Subject: [PATCH 242/244] dts: stm32mp1: alignment with v4.19-stm32mp-r3.1 Device tree alignment with Linux kernel v4.19-stm32mp-r3.1 - ARM: dts: stm32: reduce temperature critical threshold on stm32mp157c - ARM: dts: stm32: adjust USB OTG gadget fifo sizes in stm32mp157c Signed-off-by: Patrick Delaunay Change-Id: I6fba2fde4ea4b2e35a9e5825f2376c5393d65c33 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/160508 Reviewed-by: CITOOLS --- arch/arm/dts/stm32mp157c.dtsi | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index d56e0f98475c..bd0ab3b8cbf3 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -156,7 +156,11 @@ trips { cpu-crit { - temperature = <120000>; + /* + * 120 degrees threshold can be set + * for product limited to 650Mhz + */ + temperature = <100000>; hysteresis = <0>; type = "critical"; }; @@ -1288,9 +1292,9 @@ interrupts-extended = <&intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, <&exti 44 1>; interrupt-names = "event", "wakeup"; - g-rx-fifo-size = <256>; + g-rx-fifo-size = <512>; g-np-tx-fifo-size = <32>; - g-tx-fifo-size = <128 128 64 64 64 64 32 32>; + g-tx-fifo-size = <256 16 16 16 16 16 16 16>; dr_mode = "otg"; usb33d-supply = <&usb33>; power-domains = <&pd_core>; From d8e0454068eee1d1c33da4aff37525e846dac847 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 25 Feb 2020 15:57:29 +0100 Subject: [PATCH 243/244] Prepare v2018.11-stm32mp-r4.2 Signed-off-by: Patrick Delaunay Change-Id: Iadeb39fc18d29c455edf0c7177a1179320a074e0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7f944516c7c1..074c33d8055a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r4.1 +EXTRAVERSION = -stm32mp-r4.2 NAME = # *DOCUMENTATION* From 41862c1b2601f68839ae03e864b371b3e1b2162d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 8 Apr 2020 13:56:09 +0200 Subject: [PATCH 244/244] CONTRIBUTING: add contributing guide to STMicroelectronics/u-boot repository Add contributing guide to STMicroelectronics/u-boot repository. Signed-off-by: Bernard Puel Signed-off-by: Patrick Delaunay Change-Id: Ia32afcbd025f24949fb27c7fe4db2133a47dcf5b Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/163160 Reviewed-by: CITOOLS Reviewed-by: CIBUILD --- CONTRIBUTING.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..3d1bacd78a54 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing guide + +This document serves as a checklist before contributing to this repository. It includes links to read up on if topics are unclear to you. + +This guide mainly focuses on the proper use of Git. + +## 1. Issues + +STM32MPU projects do not activate "Github issues" feature for the time being. If you need to report an issue or question about this project deliverables, you can report them using [ ST Support Center ](https://my.st.com/ols#/ols/newrequest) or [ ST Community MPU Forum ](https://community.st.com/s/topic/0TO0X0000003u2AWAQ/stm32-mpus). + +## 2. Pull Requests + +STMicrolectronics is happy to receive contributions from the community, based on an initial Contributor License Agreement (CLA) procedure. + +* If you are an individual writing original source code and you are sure **you own the intellectual property**, then you need to sign an Individual CLA (https://cla.st.com). +* If you work for a company that wants also to allow you to contribute with your work, your company needs to provide a Corporate CLA (https://cla.st.com) mentioning your GitHub account name. +* If you are not sure that a CLA (Individual or Corporate) has been signed for your GitHub account you can check here (https://cla.st.com). + +Please note that: +* The Corporate CLA will always take precedence over the Individual CLA. +* One CLA submission is sufficient, for any project proposed by STMicroelectronics. + +__How to proceed__ + +* We recommend to fork the project in your GitHub account to further develop your contribution. Please use the latest commit version. +* Please, submit one Pull Request for one new feature or proposal. This will ease the analysis and final merge if accepted. + +__Note__ + +Merge will not be done directly in GitHub but it will need first to follow internal integration process before public deliver in a standard release. The Pull request will stay open until it is merged and delivered.