From 032589bd75dc6ee5bd5944f28ef7a6cd0e08b9ea Mon Sep 17 00:00:00 2001 From: Priouzeau Christophe Date: Mon, 3 Feb 2020 15:03:57 +0100 Subject: [PATCH] LINUX-STM32MP: update to v2.0.0 (v5.4-stm32mp-r1) Change-Id: I30e1aa3ee0f28b3dc27e5899956719b8fe7b43a4 --- recipes-kernel/linux/linux-stm32mp.inc | 23 +- .../0001-ARM-stm32mp1-r3-MACHINE.patch | 82 - .../4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch | 1100 -- .../0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch | 39 - .../4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch | 1548 -- .../4.19.94/0007-ARM-stm32mp1-r3-DRM.patch | 2414 --- .../4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch | 203 - .../0009-ARM-stm32mp1-r3-HWSPINLOCK.patch | 249 - .../0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch | 1500 -- .../4.19.94/0011-ARM-stm32mp1-r3-IIO.patch | 6486 -------- ...12-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch | 1166 -- .../4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch | 3559 ----- .../4.19.94/0014-ARM-stm32mp1-r3-MFD.patch | 1792 --- .../0015-ARM-stm32mp1-r3-MMC-MTD.patch | 5193 ------- .../4.19.94/0016-ARM-stm32mp1-r3-NET.patch | 496 - .../4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch | 377 - ...0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch | 5533 ------- .../0020-ARM-stm32mp1-r3-REGULATOR.patch | 1232 -- ...M-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch | 4019 ----- .../4.19.94/0022-ARM-stm32mp1-r3-RTC.patch | 276 - .../4.19.94/0023-ARM-stm32mp1-r3-SOC.patch | 658 - .../4.19.94/0024-ARM-stm32mp1-r3-SPI.patch | 1608 -- .../0025-ARM-stm32mp1-r3-THERMAL.patch | 689 - .../0026-ARM-stm32mp1-r3-TTY-USB.patch | 3889 ----- .../0027-ARM-stm32mp1-r3-WATCHDOG.patch | 361 - .../4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch | 2806 ---- .../4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch | 253 - .../0030-ARM-stm32mp1-r3-DEVICETREE.patch | 9021 ----------- .../5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch | 58 + .../0002-ARM-stm32mp1-r1-CPUFREQ.patch} | 74 +- .../5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch | 1233 ++ ...0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch | 231 + .../5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch | 1542 ++ .../5.4.31/0006-ARM-stm32mp1-r1-DMA.patch} | 1241 +- .../5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch | 1314 ++ .../0008-ARM-stm32mp1-r1-HWSPINLOCK.patch | 253 + ...0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch | 3427 +++++ ...stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch | 2728 ++++ ...1-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch | 471 + ...12-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch | 1556 ++ .../5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch | 716 + .../0014-ARM-stm32mp1-r1-MMC-NAND.patch | 1187 ++ .../5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch | 2124 +++ .../5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch | 2943 ++++ ...tm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch | 2670 ++++ .../5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch | 679 + .../5.4.31/0019-ARM-stm32mp1-r1-MISC.patch | 213 + .../0020-ARM-stm32mp1-r1-DEVICETREE.patch | 12460 ++++++++++++++++ .../5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch} | 455 +- .../5.4.31/0022-ARM-stm32mp1-r1-POWER.patch | 24 + .../5.4.31/0023-ARM-stm32mp1-r1-PERF.patch} | 31 +- .../{4.19 => 5.4}/fragment-03-systemd.config | 0 .../{4.19 => 5.4}/fragment-04-optee.config | 0 .../{4.19 => 5.4}/fragment-05-modules.config | 6 + .../5.4/fragment-06-signature.config | 10 + .../linux/linux-stm32mp/README.HOW_TO.txt | 183 +- recipes-kernel/linux/linux-stm32mp_4.19.bb | 95 - recipes-kernel/linux/linux-stm32mp_5.4.bb | 89 + 58 files changed, 37036 insertions(+), 57549 deletions(-) delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0016-ARM-stm32mp1-r3-NET.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch rename recipes-kernel/linux/linux-stm32mp/{4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch => 5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch} (67%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch rename recipes-kernel/linux/linux-stm32mp/{4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch => 5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch} (72%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch rename recipes-kernel/linux/linux-stm32mp/{4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch => 5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch} (86%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch rename recipes-kernel/linux/linux-stm32mp/{4.19/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch => 5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch} (96%) rename recipes-kernel/linux/linux-stm32mp/{4.19 => 5.4}/fragment-03-systemd.config (100%) rename recipes-kernel/linux/linux-stm32mp/{4.19 => 5.4}/fragment-04-optee.config (100%) rename recipes-kernel/linux/linux-stm32mp/{4.19 => 5.4}/fragment-05-modules.config (81%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/fragment-06-signature.config delete mode 100644 recipes-kernel/linux/linux-stm32mp_4.19.bb create mode 100644 recipes-kernel/linux/linux-stm32mp_5.4.bb diff --git a/recipes-kernel/linux/linux-stm32mp.inc b/recipes-kernel/linux/linux-stm32mp.inc index a920819..20ef807 100644 --- a/recipes-kernel/linux/linux-stm32mp.inc +++ b/recipes-kernel/linux/linux-stm32mp.inc @@ -2,7 +2,7 @@ COMPATIBLE_MACHINE = "(stm32mpcommon)" inherit kernel -DEPENDS += "openssl-native util-linux-native" +DEPENDS += "openssl-native util-linux-native libyaml-native" B = "${WORKDIR}/build" # Configure build dir for externalsrc class usage through devtool @@ -14,6 +14,21 @@ FILESEXTRAPATHS_prepend := "${THISDIR}:" # ------------------------------------------------------------- # Do not deploy kernel module with specfic tarball MODULE_TARBALL_DEPLOY = "0" +do_deploy[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}/kernel" + +#--------------------------------------------------------------- +# Module kernel signature +KERNEL_SIGN_ENABLE ?= "0" +EXTRA_OEMAKE += "${@oe.utils.ifelse(d.getVar('KERNEL_SIGN_ENABLE') == '1', 'INSTALL_MOD_STRIP=1','')}" + +# +# Force task order for link creation +# +python () { + d.appendVarFlag("do_unpack", "postfuncs", " do_symlink_kernsrc") +} +do_symlink_kernsrc[noexec] = "1" + # --------------------------------------------------------------------- # Defconfig @@ -65,6 +80,11 @@ do_configure_prepend() { do_install_append() { # Install KERNEL_IMAGETYPE for kernel-imagebootfs package install -m 0644 ${KERNEL_OUTPUT_DIR}/${KERNEL_IMAGETYPE} ${D}/${KERNEL_IMAGEDEST} + + if ${@bb.utils.contains('MACHINE_FEATURES','gpu','true','false',d)}; then + # when ACCEPT_EULA are filled + echo "blacklist etnaviv" > ${D}/${sysconfdir}/modprobe.d/blacklist.conf + fi } # --------------------------------------------------------------------- @@ -79,3 +99,4 @@ PACKAGES =+ "${KERNEL_PACKAGE_NAME}-headers ${KERNEL_PACKAGE_NAME}-imagebootfs" FILES_${KERNEL_PACKAGE_NAME}-headers = "${exec_prefix}/src/linux*" FILES_${KERNEL_PACKAGE_NAME}-image += "boot/ ${KERNEL_IMAGEDEST}" FILES_${KERNEL_PACKAGE_NAME}-imagebootfs = "boot/*.dtb boot/${KERNEL_IMAGETYPE}" +FILES_${KERNEL_PACKAGE_NAME}-modules += "${sysconfdir}/modprobe.d" diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch deleted file mode 100644 index 2177a44..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 72d1b59c3ca272dd153ebd350ef9e403dac3db59 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:38 +0100 -Subject: [PATCH 01/31] ARM stm32mp1 r3 MACHINE - ---- - arch/arm/mach-integrator/integrator_cp.c | 2 -- - arch/arm/mach-stm32/Kconfig | 5 +---- - arch/arm/mach-versatile/versatile_dt.c | 4 ---- - 3 files changed, 1 insertion(+), 10 deletions(-) - -diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c -index 772a7cf..976ded5 100644 ---- a/arch/arm/mach-integrator/integrator_cp.c -+++ b/arch/arm/mach-integrator/integrator_cp.c -@@ -80,8 +80,6 @@ static unsigned int mmc_status(struct device *dev) - static struct mmci_platform_data mmc_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -- .gpio_wp = -1, -- .gpio_cd = -1, - }; - - static u64 notrace intcp_read_sched_clock(void) -diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig -index 713c068..651bdf4 100644 ---- a/arch/arm/mach-stm32/Kconfig -+++ b/arch/arm/mach-stm32/Kconfig -@@ -4,6 +4,7 @@ menuconfig ARCH_STM32 - select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 - select ARM_GIC if ARCH_MULTI_V7 - select ARM_PSCI if ARCH_MULTI_V7 -+ select ARM_AMBA - select ARCH_HAS_RESET_CONTROLLER - select CLKSRC_STM32 - select PINCTRL -@@ -18,22 +19,18 @@ if ARM_SINGLE_ARMV7M - - config MACH_STM32F429 - bool "STMicroelectronics STM32F429" -- select ARM_AMBA - default y - - config MACH_STM32F469 - bool "STMicroelectronics STM32F469" -- select ARM_AMBA - default y - - config MACH_STM32F746 - bool "STMicroelectronics STM32F746" -- select ARM_AMBA - default y - - config MACH_STM32F769 - bool "STMicroelectronics STM32F769" -- select ARM_AMBA - default y - - config MACH_STM32H743 -diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c -index 3c8d39c..e9d6068 100644 ---- a/arch/arm/mach-versatile/versatile_dt.c -+++ b/arch/arm/mach-versatile/versatile_dt.c -@@ -89,15 +89,11 @@ unsigned int mmc_status(struct device *dev) - static struct mmci_platform_data mmc0_plat_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -- .gpio_wp = -1, -- .gpio_cd = -1, - }; - - static struct mmci_platform_data mmc1_plat_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -- .gpio_wp = -1, -- .gpio_cd = -1, - }; - - /* --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch deleted file mode 100644 index 2d56ee2..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch +++ /dev/null @@ -1,1100 +0,0 @@ -From ba1e344b74257a65d21b7b82f99df31dcf3f5a7c Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:38 +0100 -Subject: [PATCH 03/31] ARM stm32mp1 r3 CRYPTO - ---- - crypto/testmgr.c | 7 + - drivers/crypto/stm32/Kconfig | 1 + - drivers/crypto/stm32/Makefile | 2 +- - drivers/crypto/stm32/stm32-crc32.c | 441 +++++++++++++++++++++++++++++++++++++ - drivers/crypto/stm32/stm32-cryp.c | 72 ++++-- - drivers/crypto/stm32/stm32-hash.c | 6 +- - drivers/crypto/stm32/stm32_crc32.c | 387 -------------------------------- - 7 files changed, 502 insertions(+), 414 deletions(-) - create mode 100644 drivers/crypto/stm32/stm32-crc32.c - delete mode 100644 drivers/crypto/stm32/stm32_crc32.c - -diff --git a/crypto/testmgr.c b/crypto/testmgr.c -index 13cb2ea..35a4ac5 100644 ---- a/crypto/testmgr.c -+++ b/crypto/testmgr.c -@@ -1918,6 +1918,13 @@ static int alg_test_crc32c(const struct alg_test_desc *desc, - shash->tfm = tfm; - shash->flags = 0; - -+ err = crypto_shash_init(shash); -+ if (err) { -+ printk(KERN_ERR "alg: crc32c: init failed for " -+ "%s: %d\n", driver, err); -+ break; -+ } -+ - *ctx = le32_to_cpu(420553207); - err = crypto_shash_final(shash, (u8 *)&val); - if (err) { -diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig -index 63aa78c..4491e21 100644 ---- a/drivers/crypto/stm32/Kconfig -+++ b/drivers/crypto/stm32/Kconfig -@@ -24,6 +24,7 @@ config CRYPTO_DEV_STM32_CRYP - depends on ARCH_STM32 - select CRYPTO_HASH - select CRYPTO_ENGINE -+ select CRYPTO_DES - help - This enables support for the CRYP (AES/DES/TDES) hw accelerator which - can be found on STMicroelectronics STM32 SOC. -diff --git a/drivers/crypto/stm32/Makefile b/drivers/crypto/stm32/Makefile -index 53d1bb9..23ce3bc 100644 ---- a/drivers/crypto/stm32/Makefile -+++ b/drivers/crypto/stm32/Makefile -@@ -1,3 +1,3 @@ --obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32_crc32.o -+obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32-crc32.o - obj-$(CONFIG_CRYPTO_DEV_STM32_HASH) += stm32-hash.o - obj-$(CONFIG_CRYPTO_DEV_STM32_CRYP) += stm32-cryp.o -diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c -new file mode 100644 -index 0000000..2597710 ---- /dev/null -+++ b/drivers/crypto/stm32/stm32-crc32.c -@@ -0,0 +1,441 @@ -+/* -+ * Copyright (C) STMicroelectronics SA 2017 -+ * Author: Fabien Dessenne -+ * License terms: GNU General Public License (GPL), version 2 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#define DRIVER_NAME "stm32-crc32" -+#define CHKSUM_DIGEST_SIZE 4 -+#define CHKSUM_BLOCK_SIZE 1 -+ -+/* Registers */ -+#define CRC_DR 0x00000000 -+#define CRC_CR 0x00000008 -+#define CRC_INIT 0x00000010 -+#define CRC_POL 0x00000014 -+ -+/* Registers values */ -+#define CRC_CR_RESET BIT(0) -+#define CRC_CR_REV_IN_W (BIT(6) | BIT(5)) -+#define CRC_CR_REV_IN_B BIT(5) -+#define CRC_CR_REV_OUT BIT(7) -+#define CRC32C_INIT_DEFAULT 0xFFFFFFFF -+ -+#define CRC_AUTOSUSPEND_DELAY 50 -+ -+struct stm32_crc { -+ struct list_head list; -+ struct device *dev; -+ void __iomem *regs; -+ struct clk *clk; -+ u8 pending_data[sizeof(u32)]; -+ size_t nb_pending_bytes; -+}; -+ -+struct stm32_crc_list { -+ struct list_head dev_list; -+ spinlock_t lock; /* protect dev_list */ -+}; -+ -+static struct stm32_crc_list crc_list = { -+ .dev_list = LIST_HEAD_INIT(crc_list.dev_list), -+ .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock), -+}; -+ -+struct stm32_crc_ctx { -+ u32 key; -+ u32 poly; -+}; -+ -+struct stm32_crc_desc_ctx { -+ u32 partial; /* crc32c: partial in first 4 bytes of that struct */ -+ struct stm32_crc *crc; -+}; -+ -+struct stm32_crc_algs_info { -+ struct shash_alg algs[2]; -+ unsigned int registered; -+}; -+ -+static int stm32_crc32_cra_init(struct crypto_tfm *tfm) -+{ -+ struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); -+ -+ mctx->key = 0; -+ mctx->poly = CRC32_POLY_LE; -+ return 0; -+} -+ -+static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) -+{ -+ struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); -+ -+ mctx->key = CRC32C_INIT_DEFAULT; -+ mctx->poly = CRC32C_POLY_LE; -+ return 0; -+} -+ -+static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, -+ unsigned int keylen) -+{ -+ struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm); -+ -+ if (keylen != sizeof(u32)) { -+ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); -+ return -EINVAL; -+ } -+ -+ mctx->key = get_unaligned_le32(key); -+ return 0; -+} -+ -+static struct stm32_crc *stm32_crc_find_dev(struct stm32_crc_desc_ctx *ctx) -+{ -+ struct stm32_crc *crc; -+ -+ spin_lock_bh(&crc_list.lock); -+ crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); -+ list_move_tail(&crc->list, &crc_list.dev_list); -+ ctx->crc = crc; -+ spin_unlock_bh(&crc_list.lock); -+ -+ return crc; -+} -+ -+static int stm32_crc_init(struct shash_desc *desc) -+{ -+ struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -+ struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); -+ -+ if (!stm32_crc_find_dev(ctx)) -+ return -ENODEV; -+ -+ pm_runtime_get_sync(ctx->crc->dev); -+ -+ /* Reset, set key, poly and configure in bit reverse mode */ -+ writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); -+ writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); -+ writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_W | CRC_CR_REV_OUT, -+ ctx->crc->regs + CRC_CR); -+ -+ /* Store partial result */ -+ ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); -+ ctx->crc->nb_pending_bytes = 0; -+ -+ pm_runtime_mark_last_busy(ctx->crc->dev); -+ pm_runtime_put_autosuspend(ctx->crc->dev); -+ -+ return 0; -+} -+ -+static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, -+ unsigned int length) -+{ -+ struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -+ struct stm32_crc *crc = ctx->crc; -+ u32 *d32; -+ unsigned int i; -+ -+ pm_runtime_get_sync(crc->dev); -+ -+ if (unlikely(crc->nb_pending_bytes)) { -+ while (crc->nb_pending_bytes != sizeof(u32) && length) { -+ /* Fill in pending data */ -+ crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -+ length--; -+ } -+ -+ if (crc->nb_pending_bytes == sizeof(u32)) { -+ /* Process completed pending data */ -+ writel_relaxed(*(u32 *)crc->pending_data, -+ crc->regs + CRC_DR); -+ crc->nb_pending_bytes = 0; -+ } -+ } -+ -+ d32 = (u32 *)d8; -+ for (i = 0; i < length >> 2; i++) -+ /* Process 32 bits data */ -+ writel_relaxed(*(d32++), crc->regs + CRC_DR); -+ -+ /* Store partial result */ -+ ctx->partial = readl_relaxed(crc->regs + CRC_DR); -+ -+ pm_runtime_mark_last_busy(crc->dev); -+ pm_runtime_put_autosuspend(crc->dev); -+ -+ /* Check for pending data (non 32 bits) */ -+ length &= 3; -+ if (likely(!length)) -+ return 0; -+ -+ if ((crc->nb_pending_bytes + length) >= sizeof(u32)) { -+ /* Shall not happen */ -+ dev_err(crc->dev, "Pending data overflow\n"); -+ return -EINVAL; -+ } -+ -+ d8 = (const u8 *)d32; -+ for (i = 0; i < length; i++) -+ /* Store pending data */ -+ crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -+ -+ return 0; -+} -+ -+static int stm32_crc_final(struct shash_desc *desc, u8 *out) -+{ -+ struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -+ struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); -+ struct stm32_crc *crc = ctx->crc; -+ unsigned int i = 0; -+ -+ if (unlikely(crc->nb_pending_bytes)) { -+ pm_runtime_get_sync(crc->dev); -+ /* Process pending data */ -+ writel_relaxed(CRC_CR_REV_IN_B | CRC_CR_REV_OUT, -+ ctx->crc->regs + CRC_CR); -+ while (i != crc->nb_pending_bytes) { -+ writeb_relaxed(crc->pending_data[i++], -+ crc->regs + CRC_DR); -+ } -+ -+ crc->nb_pending_bytes = 0; -+ ctx->partial = readl_relaxed(crc->regs + CRC_DR); -+ -+ pm_runtime_mark_last_busy(crc->dev); -+ pm_runtime_put_autosuspend(crc->dev); -+ } -+ -+ /* Send computed CRC */ -+ put_unaligned_le32(mctx->poly == CRC32C_POLY_LE ? -+ ~ctx->partial : ctx->partial, out); -+ -+ return 0; -+} -+ -+static int stm32_crc_finup(struct shash_desc *desc, const u8 *data, -+ unsigned int length, u8 *out) -+{ -+ return stm32_crc_update(desc, data, length) ?: -+ stm32_crc_final(desc, out); -+} -+ -+static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, -+ unsigned int length, u8 *out) -+{ -+ return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); -+} -+ -+static struct stm32_crc_algs_info crc_algs[] = { -+ { -+ .algs = { -+ /* CRC-32 */ -+ { -+ .setkey = stm32_crc_setkey, -+ .init = stm32_crc_init, -+ .update = stm32_crc_update, -+ .final = stm32_crc_final, -+ .finup = stm32_crc_finup, -+ .digest = stm32_crc_digest, -+ .descsize = -+ sizeof(struct stm32_crc_desc_ctx), -+ .digestsize = CHKSUM_DIGEST_SIZE, -+ .base = { -+ .cra_name = "crc32", -+ .cra_driver_name = DRIVER_NAME, -+ .cra_priority = 200, -+ .cra_flags = -+ CRYPTO_ALG_OPTIONAL_KEY, -+ .cra_blocksize = -+ CHKSUM_BLOCK_SIZE, -+ .cra_alignmask = 3, -+ .cra_ctxsize = -+ sizeof(struct stm32_crc_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = -+ stm32_crc32_cra_init, -+ } -+ }, -+ /* CRC-32Castagnoli */ -+ { -+ .setkey = stm32_crc_setkey, -+ .init = stm32_crc_init, -+ .update = stm32_crc_update, -+ .final = stm32_crc_final, -+ .finup = stm32_crc_finup, -+ .digest = stm32_crc_digest, -+ .descsize = -+ sizeof(struct stm32_crc_desc_ctx), -+ .digestsize = CHKSUM_DIGEST_SIZE, -+ .base = { -+ .cra_name = "crc32c", -+ .cra_driver_name = DRIVER_NAME, -+ .cra_priority = 200, -+ .cra_flags = -+ CRYPTO_ALG_OPTIONAL_KEY, -+ .cra_blocksize = -+ CHKSUM_BLOCK_SIZE, -+ .cra_alignmask = 3, -+ .cra_ctxsize = -+ sizeof(struct stm32_crc_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = -+ stm32_crc32c_cra_init, -+ } -+ } -+ } -+ } -+}; -+ -+static int stm32_crc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct stm32_crc *crc; -+ struct resource *res; -+ int ret; -+ -+ crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); -+ if (!crc) -+ return -ENOMEM; -+ -+ crc->dev = dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ crc->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(crc->regs)) { -+ dev_err(dev, "Cannot map CRC IO\n"); -+ return PTR_ERR(crc->regs); -+ } -+ -+ crc->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(crc->clk)) { -+ dev_err(dev, "Could not get clock\n"); -+ return PTR_ERR(crc->clk); -+ } -+ -+ ret = clk_prepare_enable(crc->clk); -+ if (ret) { -+ dev_err(crc->dev, "Failed to enable clock\n"); -+ return ret; -+ } -+ -+ pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY); -+ pm_runtime_use_autosuspend(dev); -+ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ -+ platform_set_drvdata(pdev, crc); -+ -+ spin_lock(&crc_list.lock); -+ list_add(&crc->list, &crc_list.dev_list); -+ spin_unlock(&crc_list.lock); -+ -+ if (!crc_algs->registered) { -+ ret = crypto_register_shashes(crc_algs->algs, -+ ARRAY_SIZE(crc_algs->algs)); -+ -+ if (ret) { -+ dev_err(dev, "Failed to register\n"); -+ clk_disable_unprepare(crc->clk); -+ return ret; -+ } -+ } -+ -+ crc_algs->registered++; -+ dev_info(dev, "Initialized\n"); -+ pm_runtime_put_sync(dev); -+ -+ return 0; -+} -+ -+static int stm32_crc_remove(struct platform_device *pdev) -+{ -+ struct stm32_crc *crc = platform_get_drvdata(pdev); -+ int ret = pm_runtime_get_sync(crc->dev); -+ -+ if (ret < 0) -+ return ret; -+ -+ spin_lock(&crc_list.lock); -+ list_del(&crc->list); -+ spin_unlock(&crc_list.lock); -+ -+ if (!--crc_algs->registered) -+ crypto_unregister_shashes(crc_algs->algs, -+ ARRAY_SIZE(crc_algs->algs)); -+ -+ pm_runtime_disable(crc->dev); -+ pm_runtime_put_noidle(crc->dev); -+ clk_disable_unprepare(crc->clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int stm32_crc_runtime_suspend(struct device *dev) -+{ -+ struct stm32_crc *crc = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(crc->clk); -+ -+ return 0; -+} -+ -+static int stm32_crc_runtime_resume(struct device *dev) -+{ -+ struct stm32_crc *crc = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_prepare_enable(crc->clk); -+ if (ret) { -+ dev_err(crc->dev, "Failed to prepare_enable clock\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static const struct dev_pm_ops stm32_crc_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, -+ stm32_crc_runtime_resume, NULL) -+}; -+ -+static const struct of_device_id stm32_dt_ids[] = { -+ { .compatible = "st,stm32f7-crc", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_dt_ids); -+ -+static struct platform_driver stm32_crc_driver = { -+ .probe = stm32_crc_probe, -+ .remove = stm32_crc_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .pm = &stm32_crc_pm_ops, -+ .of_match_table = stm32_dt_ids, -+ }, -+}; -+ -+module_platform_driver(stm32_crc_driver); -+ -+MODULE_AUTHOR("Fabien Dessenne "); -+MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c -index 23b0b7b..cd8c439 100644 ---- a/drivers/crypto/stm32/stm32-cryp.c -+++ b/drivers/crypto/stm32/stm32-cryp.c -@@ -137,7 +137,6 @@ struct stm32_cryp { - - struct crypto_engine *engine; - -- struct mutex lock; /* protects req / areq */ - struct ablkcipher_request *req; - struct aead_request *areq; - -@@ -394,6 +393,23 @@ static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, u32 *iv) - } - } - -+static void stm32_cryp_get_iv(struct stm32_cryp *cryp) -+{ -+ struct ablkcipher_request *req = cryp->req; -+ u32 *tmp = req->info; -+ -+ if (!tmp) -+ return; -+ -+ *tmp++ = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0LR)); -+ *tmp++ = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0RR)); -+ -+ if (is_aes(cryp)) { -+ *tmp++ = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1LR)); -+ *tmp++ = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1RR)); -+ } -+} -+ - static void stm32_cryp_hw_write_key(struct stm32_cryp *c) - { - unsigned int i; -@@ -623,6 +639,9 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) - /* Phase 4 : output tag */ - err = stm32_cryp_read_auth_tag(cryp); - -+ if (!err && (!(is_gcm(cryp) || is_ccm(cryp)))) -+ stm32_cryp_get_iv(cryp); -+ - if (cryp->sgs_copied) { - void *buf_in, *buf_out; - int pages, len; -@@ -645,18 +664,13 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) - pm_runtime_mark_last_busy(cryp->dev); - pm_runtime_put_autosuspend(cryp->dev); - -- if (is_gcm(cryp) || is_ccm(cryp)) { -+ if (is_gcm(cryp) || is_ccm(cryp)) - crypto_finalize_aead_request(cryp->engine, cryp->areq, err); -- cryp->areq = NULL; -- } else { -+ else - crypto_finalize_ablkcipher_request(cryp->engine, cryp->req, - err); -- cryp->req = NULL; -- } - - memset(cryp->ctx->key, 0, cryp->ctx->keylen); -- -- mutex_unlock(&cryp->lock); - } - - static int stm32_cryp_cpu_start(struct stm32_cryp *cryp) -@@ -753,19 +767,37 @@ static int stm32_cryp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - static int stm32_cryp_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) - { -+ u32 tmp[DES_EXPKEY_WORDS]; -+ - if (keylen != DES_KEY_SIZE) - return -EINVAL; -- else -- return stm32_cryp_setkey(tfm, key, keylen); -+ -+ if ((crypto_ablkcipher_get_flags(tfm) & -+ CRYPTO_TFM_REQ_WEAK_KEY) && -+ unlikely(!des_ekey(tmp, key))) { -+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); -+ return -EINVAL; -+ } -+ -+ return stm32_cryp_setkey(tfm, key, keylen); - } - - static int stm32_cryp_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) - { -+ u32 tmp[DES_EXPKEY_WORDS]; -+ - if (keylen != (3 * DES_KEY_SIZE)) - return -EINVAL; -- else -- return stm32_cryp_setkey(tfm, key, keylen); -+ -+ if ((crypto_ablkcipher_get_flags(tfm) & -+ CRYPTO_TFM_REQ_WEAK_KEY) && -+ unlikely(!des_ekey(tmp, key))) { -+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); -+ return -EINVAL; -+ } -+ -+ return stm32_cryp_setkey(tfm, key, keylen); - } - - static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, -@@ -917,8 +949,6 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, - if (!cryp) - return -ENODEV; - -- mutex_lock(&cryp->lock); -- - rctx = req ? ablkcipher_request_ctx(req) : aead_request_ctx(areq); - rctx->mode &= FLG_MODE_MASK; - -@@ -930,6 +960,7 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, - - if (req) { - cryp->req = req; -+ cryp->areq = NULL; - cryp->total_in = req->nbytes; - cryp->total_out = cryp->total_in; - } else { -@@ -955,6 +986,7 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, - * <---------- total_out -----------------> - */ - cryp->areq = areq; -+ cryp->req = NULL; - cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq)); - cryp->total_in = areq->assoclen + areq->cryptlen; - if (is_encrypt(cryp)) -@@ -976,19 +1008,19 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, - if (cryp->in_sg_len < 0) { - dev_err(cryp->dev, "Cannot get in_sg_len\n"); - ret = cryp->in_sg_len; -- goto out; -+ return ret; - } - - cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); - if (cryp->out_sg_len < 0) { - dev_err(cryp->dev, "Cannot get out_sg_len\n"); - ret = cryp->out_sg_len; -- goto out; -+ return ret; - } - - ret = stm32_cryp_copy_sgs(cryp); - if (ret) -- goto out; -+ return ret; - - scatterwalk_start(&cryp->in_walk, cryp->in_sg); - scatterwalk_start(&cryp->out_walk, cryp->out_sg); -@@ -1000,10 +1032,6 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, - } - - ret = stm32_cryp_hw_init(cryp); --out: -- if (ret) -- mutex_unlock(&cryp->lock); -- - return ret; - } - -@@ -1943,8 +1971,6 @@ static int stm32_cryp_probe(struct platform_device *pdev) - - cryp->dev = dev; - -- mutex_init(&cryp->lock); -- - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cryp->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(cryp->regs)) -diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c -index 641b110..990bbbf 100644 ---- a/drivers/crypto/stm32/stm32-hash.c -+++ b/drivers/crypto/stm32/stm32-hash.c -@@ -463,8 +463,8 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev, - - dma_async_issue_pending(hdev->dma_lch); - -- if (!wait_for_completion_interruptible_timeout(&hdev->dma_completion, -- msecs_to_jiffies(100))) -+ if (!wait_for_completion_timeout(&hdev->dma_completion, -+ msecs_to_jiffies(100))) - err = -ETIMEDOUT; - - if (dma_async_is_tx_complete(hdev->dma_lch, cookie, -@@ -977,7 +977,7 @@ static int stm32_hash_export(struct ahash_request *req, void *out) - - pm_runtime_get_sync(hdev->dev); - -- while (!(stm32_hash_read(hdev, HASH_SR) & HASH_SR_DATA_INPUT_READY)) -+ while ((stm32_hash_read(hdev, HASH_SR) & HASH_SR_BUSY)) - cpu_relax(); - - rctx->hw_context = kmalloc_array(3 + HASH_CSR_REGISTER_NUMBER, -diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32_crc32.c -deleted file mode 100644 -index 29d2095..0000000 ---- a/drivers/crypto/stm32/stm32_crc32.c -+++ /dev/null -@@ -1,387 +0,0 @@ --/* -- * Copyright (C) STMicroelectronics SA 2017 -- * Author: Fabien Dessenne -- * License terms: GNU General Public License (GPL), version 2 -- */ -- --#include --#include --#include --#include --#include --#include --#include -- --#include -- --#include -- --#define DRIVER_NAME "stm32-crc32" --#define CHKSUM_DIGEST_SIZE 4 --#define CHKSUM_BLOCK_SIZE 1 -- --/* Registers */ --#define CRC_DR 0x00000000 --#define CRC_CR 0x00000008 --#define CRC_INIT 0x00000010 --#define CRC_POL 0x00000014 -- --/* Registers values */ --#define CRC_CR_RESET BIT(0) --#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5)) --#define CRC_INIT_DEFAULT 0xFFFFFFFF -- --#define CRC_AUTOSUSPEND_DELAY 50 -- --struct stm32_crc { -- struct list_head list; -- struct device *dev; -- void __iomem *regs; -- struct clk *clk; -- u8 pending_data[sizeof(u32)]; -- size_t nb_pending_bytes; --}; -- --struct stm32_crc_list { -- struct list_head dev_list; -- spinlock_t lock; /* protect dev_list */ --}; -- --static struct stm32_crc_list crc_list = { -- .dev_list = LIST_HEAD_INIT(crc_list.dev_list), -- .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock), --}; -- --struct stm32_crc_ctx { -- u32 key; -- u32 poly; --}; -- --struct stm32_crc_desc_ctx { -- u32 partial; /* crc32c: partial in first 4 bytes of that struct */ -- struct stm32_crc *crc; --}; -- --static int stm32_crc32_cra_init(struct crypto_tfm *tfm) --{ -- struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); -- -- mctx->key = CRC_INIT_DEFAULT; -- mctx->poly = CRC32_POLY_LE; -- return 0; --} -- --static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) --{ -- struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); -- -- mctx->key = CRC_INIT_DEFAULT; -- mctx->poly = CRC32C_POLY_LE; -- return 0; --} -- --static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, -- unsigned int keylen) --{ -- struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm); -- -- if (keylen != sizeof(u32)) { -- crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); -- return -EINVAL; -- } -- -- mctx->key = get_unaligned_le32(key); -- return 0; --} -- --static int stm32_crc_init(struct shash_desc *desc) --{ -- struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -- struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); -- struct stm32_crc *crc; -- -- spin_lock_bh(&crc_list.lock); -- list_for_each_entry(crc, &crc_list.dev_list, list) { -- ctx->crc = crc; -- break; -- } -- spin_unlock_bh(&crc_list.lock); -- -- pm_runtime_get_sync(ctx->crc->dev); -- -- /* Reset, set key, poly and configure in bit reverse mode */ -- writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); -- writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); -- writel_relaxed(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR); -- -- /* Store partial result */ -- ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); -- ctx->crc->nb_pending_bytes = 0; -- -- pm_runtime_mark_last_busy(ctx->crc->dev); -- pm_runtime_put_autosuspend(ctx->crc->dev); -- -- return 0; --} -- --static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, -- unsigned int length) --{ -- struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -- struct stm32_crc *crc = ctx->crc; -- u32 *d32; -- unsigned int i; -- -- pm_runtime_get_sync(crc->dev); -- -- if (unlikely(crc->nb_pending_bytes)) { -- while (crc->nb_pending_bytes != sizeof(u32) && length) { -- /* Fill in pending data */ -- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -- length--; -- } -- -- if (crc->nb_pending_bytes == sizeof(u32)) { -- /* Process completed pending data */ -- writel_relaxed(*(u32 *)crc->pending_data, -- crc->regs + CRC_DR); -- crc->nb_pending_bytes = 0; -- } -- } -- -- d32 = (u32 *)d8; -- for (i = 0; i < length >> 2; i++) -- /* Process 32 bits data */ -- writel_relaxed(*(d32++), crc->regs + CRC_DR); -- -- /* Store partial result */ -- ctx->partial = readl_relaxed(crc->regs + CRC_DR); -- -- pm_runtime_mark_last_busy(crc->dev); -- pm_runtime_put_autosuspend(crc->dev); -- -- /* Check for pending data (non 32 bits) */ -- length &= 3; -- if (likely(!length)) -- return 0; -- -- if ((crc->nb_pending_bytes + length) >= sizeof(u32)) { -- /* Shall not happen */ -- dev_err(crc->dev, "Pending data overflow\n"); -- return -EINVAL; -- } -- -- d8 = (const u8 *)d32; -- for (i = 0; i < length; i++) -- /* Store pending data */ -- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -- -- return 0; --} -- --static int stm32_crc_final(struct shash_desc *desc, u8 *out) --{ -- struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -- struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); -- -- /* Send computed CRC */ -- put_unaligned_le32(mctx->poly == CRC32C_POLY_LE ? -- ~ctx->partial : ctx->partial, out); -- -- return 0; --} -- --static int stm32_crc_finup(struct shash_desc *desc, const u8 *data, -- unsigned int length, u8 *out) --{ -- return stm32_crc_update(desc, data, length) ?: -- stm32_crc_final(desc, out); --} -- --static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, -- unsigned int length, u8 *out) --{ -- return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); --} -- --static struct shash_alg algs[] = { -- /* CRC-32 */ -- { -- .setkey = stm32_crc_setkey, -- .init = stm32_crc_init, -- .update = stm32_crc_update, -- .final = stm32_crc_final, -- .finup = stm32_crc_finup, -- .digest = stm32_crc_digest, -- .descsize = sizeof(struct stm32_crc_desc_ctx), -- .digestsize = CHKSUM_DIGEST_SIZE, -- .base = { -- .cra_name = "crc32", -- .cra_driver_name = DRIVER_NAME, -- .cra_priority = 200, -- .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, -- .cra_blocksize = CHKSUM_BLOCK_SIZE, -- .cra_alignmask = 3, -- .cra_ctxsize = sizeof(struct stm32_crc_ctx), -- .cra_module = THIS_MODULE, -- .cra_init = stm32_crc32_cra_init, -- } -- }, -- /* CRC-32Castagnoli */ -- { -- .setkey = stm32_crc_setkey, -- .init = stm32_crc_init, -- .update = stm32_crc_update, -- .final = stm32_crc_final, -- .finup = stm32_crc_finup, -- .digest = stm32_crc_digest, -- .descsize = sizeof(struct stm32_crc_desc_ctx), -- .digestsize = CHKSUM_DIGEST_SIZE, -- .base = { -- .cra_name = "crc32c", -- .cra_driver_name = DRIVER_NAME, -- .cra_priority = 200, -- .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, -- .cra_blocksize = CHKSUM_BLOCK_SIZE, -- .cra_alignmask = 3, -- .cra_ctxsize = sizeof(struct stm32_crc_ctx), -- .cra_module = THIS_MODULE, -- .cra_init = stm32_crc32c_cra_init, -- } -- } --}; -- --static int stm32_crc_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct stm32_crc *crc; -- struct resource *res; -- int ret; -- -- crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); -- if (!crc) -- return -ENOMEM; -- -- crc->dev = dev; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- crc->regs = devm_ioremap_resource(dev, res); -- if (IS_ERR(crc->regs)) { -- dev_err(dev, "Cannot map CRC IO\n"); -- return PTR_ERR(crc->regs); -- } -- -- crc->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(crc->clk)) { -- dev_err(dev, "Could not get clock\n"); -- return PTR_ERR(crc->clk); -- } -- -- ret = clk_prepare_enable(crc->clk); -- if (ret) { -- dev_err(crc->dev, "Failed to enable clock\n"); -- return ret; -- } -- -- pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY); -- pm_runtime_use_autosuspend(dev); -- -- pm_runtime_get_noresume(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -- -- platform_set_drvdata(pdev, crc); -- -- spin_lock(&crc_list.lock); -- list_add(&crc->list, &crc_list.dev_list); -- spin_unlock(&crc_list.lock); -- -- ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); -- if (ret) { -- dev_err(dev, "Failed to register\n"); -- clk_disable_unprepare(crc->clk); -- return ret; -- } -- -- dev_info(dev, "Initialized\n"); -- -- pm_runtime_put_sync(dev); -- -- return 0; --} -- --static int stm32_crc_remove(struct platform_device *pdev) --{ -- struct stm32_crc *crc = platform_get_drvdata(pdev); -- int ret = pm_runtime_get_sync(crc->dev); -- -- if (ret < 0) -- return ret; -- -- spin_lock(&crc_list.lock); -- list_del(&crc->list); -- spin_unlock(&crc_list.lock); -- -- crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); -- -- pm_runtime_disable(crc->dev); -- pm_runtime_put_noidle(crc->dev); -- -- clk_disable_unprepare(crc->clk); -- -- return 0; --} -- --#ifdef CONFIG_PM --static int stm32_crc_runtime_suspend(struct device *dev) --{ -- struct stm32_crc *crc = dev_get_drvdata(dev); -- -- clk_disable_unprepare(crc->clk); -- -- return 0; --} -- --static int stm32_crc_runtime_resume(struct device *dev) --{ -- struct stm32_crc *crc = dev_get_drvdata(dev); -- int ret; -- -- ret = clk_prepare_enable(crc->clk); -- if (ret) { -- dev_err(crc->dev, "Failed to prepare_enable clock\n"); -- return ret; -- } -- -- return 0; --} --#endif -- --static const struct dev_pm_ops stm32_crc_pm_ops = { -- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -- pm_runtime_force_resume) -- SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, -- stm32_crc_runtime_resume, NULL) --}; -- --static const struct of_device_id stm32_dt_ids[] = { -- { .compatible = "st,stm32f7-crc", }, -- {}, --}; --MODULE_DEVICE_TABLE(of, stm32_dt_ids); -- --static struct platform_driver stm32_crc_driver = { -- .probe = stm32_crc_probe, -- .remove = stm32_crc_remove, -- .driver = { -- .name = DRIVER_NAME, -- .pm = &stm32_crc_pm_ops, -- .of_match_table = stm32_dt_ids, -- }, --}; -- --module_platform_driver(stm32_crc_driver); -- --MODULE_AUTHOR("Fabien Dessenne "); --MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver"); --MODULE_LICENSE("GPL"); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch deleted file mode 100644 index b0243e9..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch +++ /dev/null @@ -1,39 +0,0 @@ -From bcd539392e9bc23b9b47250eacf84907dd993089 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:39 +0100 -Subject: [PATCH 04/31] ARM stm32mp1 r3 BLUETOOTH CHAR - ---- - drivers/bluetooth/hci_bcm.c | 3 ++- - drivers/char/hw_random/stm32-rng.c | 1 + - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c -index 59e5fc5..c553235 100644 ---- a/drivers/bluetooth/hci_bcm.c -+++ b/drivers/bluetooth/hci_bcm.c -@@ -1324,7 +1324,8 @@ static int bcm_serdev_probe(struct serdev_device *serdev) - if (!bcmdev->shutdown) { - dev_warn(&serdev->dev, - "No reset resource, using default baud rate\n"); -- bcmdev->oper_speed = bcmdev->init_speed; -+ if (!bcmdev->oper_speed) -+ bcmdev->oper_speed = bcmdev->init_speed; - } - - err = bcm_gpio_set_power(bcmdev, false); -diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c -index 37b338a..0ef5b6a 100644 ---- a/drivers/char/hw_random/stm32-rng.c -+++ b/drivers/char/hw_random/stm32-rng.c -@@ -161,6 +161,7 @@ static int stm32_rng_probe(struct platform_device *ofdev) - #endif - priv->rng.read = stm32_rng_read, - priv->rng.priv = (unsigned long) dev; -+ priv->rng.quality = 900; - - pm_runtime_set_autosuspend_delay(dev, 100); - pm_runtime_use_autosuspend(dev); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch deleted file mode 100644 index ab87092..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch +++ /dev/null @@ -1,1548 +0,0 @@ -From 035fdb208f6ba7b3c84fddbb476ab7be33866cb4 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 20 Jan 2020 18:07:02 +0100 -Subject: [PATCH 05/31] ARM stm32mp1 r3 CLOCK - ---- - drivers/clk/clk-stm32mp1.c | 1124 +++++++++++++++++++++++++++-- - drivers/clk/clk.c | 6 + - include/dt-bindings/clock/stm32mp1-clks.h | 3 - - include/linux/clk-provider.h | 1 + - 4 files changed, 1061 insertions(+), 73 deletions(-) - -diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index bf3b6a4..95ed875 100644 ---- a/drivers/clk/clk-stm32mp1.c -+++ b/drivers/clk/clk-stm32mp1.c -@@ -5,15 +5,22 @@ - * Author: Gabriel Fernandez for STMicroelectronics. - */ - -+#include - #include - #include - #include - #include -+#include - #include -+#include -+#include - #include - #include -+#include -+#include - #include - #include -+#include - - #include - -@@ -45,6 +52,7 @@ static DEFINE_SPINLOCK(rlock); - #define RCC_AHB5ENSETR 0x210 - #define RCC_AHB6ENSETR 0x218 - #define RCC_AHB6LPENSETR 0x318 -+#define RCC_MLAHBENSETR 0xA38 - #define RCC_RCK12SELR 0x28 - #define RCC_RCK3SELR 0x820 - #define RCC_RCK4SELR 0x824 -@@ -101,6 +109,10 @@ static DEFINE_SPINLOCK(rlock); - #define RCC_TIMG2PRER 0x82C - #define RCC_RTCDIVR 0x44 - #define RCC_DBGCFGR 0x80C -+#define RCC_SREQSETR 0x104 -+#define RCC_SREQCLRR 0x108 -+#define RCC_CIER 0x414 -+#define RCC_CIFR 0x418 - - #define RCC_CLR 0x4 - -@@ -356,17 +368,20 @@ struct stm32_gate_cfg { - struct gate_cfg *gate; - struct stm32_mgate *mgate; - const struct clk_ops *ops; -+ const struct clk_ops *ops_sec; - }; - - struct stm32_div_cfg { - struct div_cfg *div; - const struct clk_ops *ops; -+ const struct clk_ops *ops_sec; - }; - - struct stm32_mux_cfg { - struct mux_cfg *mux; - struct stm32_mmux *mmux; - const struct clk_ops *ops; -+ const struct clk_ops *ops_sec; - }; - - /* STM32 Composite clock */ -@@ -376,6 +391,11 @@ struct stm32_composite_cfg { - const struct stm32_mux_cfg *mux; - }; - -+static inline int _is_soc_secured(void __iomem *base) -+{ -+ return readl_relaxed(base) & 0x1; -+} -+ - static struct clk_hw * - _clk_hw_register_gate(struct device *dev, - struct clk_hw_onecell_data *clk_data, -@@ -592,6 +612,9 @@ clk_stm32_register_gate_ops(struct device *dev, - if (cfg->ops) - init.ops = cfg->ops; - -+ if (cfg->ops_sec && _is_soc_secured(base)) -+ init.ops = cfg->ops_sec; -+ - hw = _get_stm32_gate(base, cfg, lock); - if (IS_ERR(hw)) - return ERR_PTR(-ENOMEM); -@@ -630,6 +653,9 @@ clk_stm32_register_composite(struct device *dev, - - if (cfg->mux->ops) - mux_ops = cfg->mux->ops; -+ -+ if (cfg->mux->ops_sec && _is_soc_secured(base)) -+ mux_ops = cfg->mux->ops_sec; - } - } - -@@ -641,6 +667,9 @@ clk_stm32_register_composite(struct device *dev, - - if (cfg->div->ops) - div_ops = cfg->div->ops; -+ -+ if (cfg->div->ops_sec && _is_soc_secured(base)) -+ div_ops = cfg->div->ops_sec; - } - } - -@@ -652,6 +681,9 @@ clk_stm32_register_composite(struct device *dev, - - if (cfg->gate->ops) - gate_ops = cfg->gate->ops; -+ -+ if (cfg->gate->ops_sec && _is_soc_secured(base)) -+ gate_ops = cfg->gate->ops_sec; - } - } - -@@ -714,7 +746,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) - - for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) - if (clk_mmux->mmux->hws[n] != hw) -- clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); -+ clk_hw_set_parent(clk_mmux->mmux->hws[n], hwp); - - return 0; - } -@@ -867,6 +899,7 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, - const char *parent_name, - void __iomem *reg, - unsigned long flags, -+ const struct clk_ops *ops, - spinlock_t *lock) - { - struct stm32_pll_obj *element; -@@ -879,7 +912,7 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, - return ERR_PTR(-ENOMEM); - - init.name = name; -- init.ops = &pll_ops; -+ init.ops = ops; - init.flags = flags; - init.parent_names = &parent_name; - init.num_parents = 1; -@@ -1033,6 +1066,8 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, - - struct stm32_pll_cfg { - u32 offset; -+ const struct clk_ops *ops; -+ const struct clk_ops *ops_sec; - }; - - static struct clk_hw *_clk_register_pll(struct device *dev, -@@ -1043,7 +1078,8 @@ static struct clk_hw *_clk_register_pll(struct device *dev, - struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; - - return clk_register_pll(dev, cfg->name, cfg->parent_name, -- base + stm_pll_cfg->offset, cfg->flags, lock); -+ base + stm_pll_cfg->offset, cfg->flags, -+ stm_pll_cfg->ops, lock); - } - - struct stm32_cktim_cfg { -@@ -1161,6 +1197,7 @@ _clk_stm32_register_composite(struct device *dev, - .flags = _flags,\ - .cfg = &(struct stm32_pll_cfg) {\ - .offset = _offset,\ -+ .ops = &pll_ops\ - },\ - .func = _clk_register_pll,\ - } -@@ -1193,7 +1230,8 @@ _clk_stm32_register_composite(struct device *dev, - .func = _clk_stm32_register_gate,\ - } - --#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ -+#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops,\ -+ _ops_sec)\ - (&(struct stm32_gate_cfg) {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ -@@ -1202,6 +1240,7 @@ _clk_stm32_register_composite(struct device *dev, - },\ - .mgate = _mgate,\ - .ops = _ops,\ -+ .ops_sec = _ops_sec,\ - }) - - #define _STM32_MGATE(_mgate)\ -@@ -1209,11 +1248,11 @@ _clk_stm32_register_composite(struct device *dev, - - #define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ -- NULL, NULL)\ -+ NULL, NULL, NULL)\ - - #define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ -- NULL, &mp1_gate_clk_ops)\ -+ NULL, &mp1_gate_clk_ops, NULL)\ - - #define _MGATE_MP1(_mgate)\ - .gate = &per_gate_cfg[_mgate] -@@ -1227,7 +1266,7 @@ _clk_stm32_register_composite(struct device *dev, - _STM32_MGATE(_mgate)) - - #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ -- _div_flags, _div_table, _ops)\ -+ _div_flags, _div_table, _ops, _ops_sec)\ - .div = &(struct stm32_div_cfg) {\ - &(struct div_cfg) {\ - .reg_off = _div_offset,\ -@@ -1237,13 +1276,14 @@ _clk_stm32_register_composite(struct device *dev, - .table = _div_table,\ - },\ - .ops = _ops,\ -+ .ops_sec = _ops_sec,\ - } - - #define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ - _STM32_DIV(_div_offset, _div_shift, _div_width,\ -- _div_flags, _div_table, NULL)\ -+ _div_flags, _div_table, NULL, NULL)\ - --#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ -+#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops, _ops_sec)\ - .mux = &(struct stm32_mux_cfg) {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ -@@ -1254,10 +1294,11 @@ _clk_stm32_register_composite(struct device *dev, - },\ - .mmux = _mmux,\ - .ops = _ops,\ -+ .ops_sec = _ops_sec,\ - } - - #define _MUX(_offset, _shift, _width, _mux_flags)\ -- _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ -+ _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL, NULL) - - #define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] - -@@ -1292,6 +1333,581 @@ _clk_stm32_register_composite(struct device *dev, - _MMUX(_mmux),\ - _NO_DIV) - -+/* -+ * -+ * Security management -+ * -+ */ -+ -+#define STM32_SVC_RCC 0x82001000 -+#define STM32_WRITE 0x1 -+#define STM32_SET_BITS 0x2 -+#define STM32_CLR_BITS 0x3 -+ -+#define STM32_SMC_RCC_OPP 0x82001009 -+#define STM32_SMC_RCC_OPP_SET 0 -+#define STM32_SMC_RCC_OPP_ROUND 1 -+ -+#define SMC(class, op, address, val)\ -+ ({\ -+ struct arm_smccc_res res;\ -+ arm_smccc_smc(class, op, address, val,\ -+ 0, 0, 0, 0, &res);\ -+ }) -+ -+static u32 stm32_clk_writel_secure(u32 value, void __iomem *reg) -+{ -+ struct arm_smccc_res res; -+ u32 address; -+ -+ address = offset_in_page(reg); -+ -+ arm_smccc_smc(STM32_SVC_RCC, STM32_WRITE, address, value, 0, 0, 0, -+ 0, &res); -+ -+ if (res.a0) -+ pr_warn("%s: Failed to write in secure mode at 0x%x (err = %ld)\n" -+ , __func__ -+ , address -+ , res.a0); -+ -+ return res.a0; -+} -+ -+static u32 stm32_clk_bit_secure(u32 cmd, u32 value, void __iomem *reg) -+{ -+ struct arm_smccc_res res; -+ u32 address; -+ -+ address = offset_in_page(reg); -+ -+ arm_smccc_smc(STM32_SVC_RCC, cmd, address, value, 0, 0, 0, -+ 0, &res); -+ -+ if (res.a0) -+ pr_warn("%s: Failed to write in secure mode at 0x%x (err = %ld)\n" -+ , __func__ -+ , address -+ , res.a0); -+ -+ return res.a0; -+} -+ -+static void clk_sgate_endisable(struct clk_hw *hw, int enable) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ unsigned long flags = 0; -+ u32 cmd; -+ -+ spin_lock_irqsave(gate->lock, flags); -+ -+ if (enable) -+ cmd = STM32_SET_BITS; -+ else -+ cmd = STM32_CLR_BITS; -+ -+ stm32_clk_bit_secure(cmd, BIT(gate->bit_idx), gate->reg); -+ -+ spin_unlock_irqrestore(gate->lock, flags); -+} -+ -+static int clk_sgate_enable(struct clk_hw *hw) -+{ -+ clk_sgate_endisable(hw, 1); -+ -+ return 0; -+} -+ -+static void clk_sgate_disable(struct clk_hw *hw) -+{ -+ clk_sgate_endisable(hw, 0); -+} -+ -+static const struct clk_ops clk_sgate_ops = { -+ .enable = clk_sgate_enable, -+ .disable = clk_sgate_disable, -+ .is_enabled = clk_gate_is_enabled, -+}; -+ -+static u8 clk_smux_get_parent(struct clk_hw *hw) -+{ -+ return clk_mux_ops.get_parent(hw); -+} -+ -+static int clk_smux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ u32 val; -+ unsigned long flags = 0; -+ -+ if (mux->table) { -+ index = mux->table[index]; -+ } else { -+ if (mux->flags & CLK_MUX_INDEX_BIT) -+ index = 1 << index; -+ -+ if (mux->flags & CLK_MUX_INDEX_ONE) -+ index++; -+ } -+ -+ spin_lock_irqsave(mux->lock, flags); -+ -+ val = clk_readl(mux->reg); -+ val &= ~(mux->mask << mux->shift); -+ val |= index << mux->shift; -+ -+ stm32_clk_writel_secure(val, mux->reg); -+ -+ spin_unlock_irqrestore(mux->lock, flags); -+ -+ return 0; -+} -+ -+static const struct clk_ops clk_smux_ops = { -+ .get_parent = clk_smux_get_parent, -+ .set_parent = clk_smux_set_parent, -+ .determine_rate = __clk_mux_determine_rate, -+}; -+ -+static struct clk_hw *clk_hw_register_smux(struct device *dev, -+ const char *name, -+ const char * const *parent_names, -+ u8 num_parents, -+ unsigned long flags, -+ void __iomem *reg, u8 shift, -+ u8 width, -+ u8 clk_mux_flags, -+ spinlock_t *lock) -+{ -+ u32 mask = BIT(width) - 1; -+ struct clk_mux *mux; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ /* allocate the mux */ -+ mux = kzalloc(sizeof(*mux), GFP_KERNEL); -+ if (!mux) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ -+ init.ops = &clk_smux_ops; -+ -+ init.flags = flags | CLK_IS_BASIC; -+ init.parent_names = parent_names; -+ init.num_parents = num_parents; -+ -+ /* struct clk_mux assignments */ -+ mux->reg = reg; -+ mux->shift = shift; -+ mux->mask = mask; -+ mux->flags = clk_mux_flags; -+ mux->lock = lock; -+ mux->table = NULL; -+ mux->hw.init = &init; -+ -+ hw = &mux->hw; -+ ret = clk_hw_register(dev, hw); -+ if (ret) { -+ kfree(mux); -+ hw = ERR_PTR(ret); -+ } -+ -+ return hw; -+} -+ -+static struct clk_hw * -+__clk_hw_register_mux(struct device *dev, -+ struct clk_hw_onecell_data *clk_data, -+ void __iomem *base, spinlock_t *lock, -+ const struct clock_config *cfg) -+{ -+ struct mux_cfg *mux_cfg = cfg->cfg; -+ -+ if (!_is_soc_secured(base)) -+ return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, -+ cfg->num_parents, cfg->flags, -+ mux_cfg->reg_off + base, -+ mux_cfg->shift, -+ mux_cfg->width, mux_cfg->mux_flags, -+ lock); -+ else -+ return clk_hw_register_smux(dev, cfg->name, -+ cfg->parent_names, -+ cfg->num_parents, cfg->flags, -+ mux_cfg->reg_off + base, -+ mux_cfg->shift, -+ mux_cfg->width, -+ mux_cfg->mux_flags, -+ lock); -+} -+ -+struct clk_div_secure { -+ struct clk_divider div; -+ u8 secure; -+}; -+ -+#define to_clk_div_secure(_hw) container_of(_hw, struct clk_div_secure, div) -+ -+static unsigned long clk_sdivider_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return clk_divider_ops.recalc_rate(hw, parent_rate); -+} -+ -+static long clk_sdivider_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ return clk_divider_ops.round_rate(hw, rate, prate); -+} -+ -+#define div_mask(width) ((1 << (width)) - 1) -+ -+static int clk_sdivider_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct clk_divider *divider = to_clk_divider(hw); -+ int value; -+ unsigned long flags = 0; -+ u32 val; -+ -+ value = divider_get_val(rate, parent_rate, divider->table, -+ divider->width, divider->flags); -+ -+ if (value < 0) -+ return value; -+ -+ spin_lock_irqsave(divider->lock, flags); -+ -+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { -+ val = div_mask(divider->width) << (divider->shift + 16); -+ } else { -+ val = clk_readl(divider->reg); -+ val &= ~(div_mask(divider->width) << divider->shift); -+ } -+ val |= (u32)value << divider->shift; -+ -+ stm32_clk_writel_secure(val, divider->reg); -+ -+ spin_unlock_irqrestore(divider->lock, flags); -+ -+ return 0; -+} -+ -+static const struct clk_ops clk_sdivider_ops = { -+ .recalc_rate = clk_sdivider_recalc_rate, -+ .round_rate = clk_sdivider_round_rate, -+ .set_rate = clk_sdivider_set_rate, -+}; -+ -+static const struct clk_ops clk_sdivider_pll1_p_ops = { -+ .recalc_rate = clk_sdivider_recalc_rate, -+}; -+ -+static struct clk_hw * -+clk_hw_register_sdivider_table(struct device *dev, const char *name, -+ const char *parent_name, -+ unsigned long flags, -+ void __iomem *reg, -+ u8 shift, u8 width, -+ u8 clk_divider_flags, -+ const struct clk_div_table *table, -+ spinlock_t *lock) -+{ -+ struct clk_divider *div; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ /* allocate the divider */ -+ div = kzalloc(sizeof(*div), GFP_KERNEL); -+ if (!div) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) -+ init.ops = &clk_divider_ro_ops; -+ else -+ init.ops = &clk_sdivider_ops; -+ -+ init.flags = flags | CLK_IS_BASIC; -+ init.parent_names = (parent_name ? &parent_name : NULL); -+ init.num_parents = (parent_name ? 1 : 0); -+ -+ /* struct clk_divider assignments */ -+ div->reg = reg; -+ div->shift = shift; -+ div->width = width; -+ div->flags = clk_divider_flags; -+ div->lock = lock; -+ div->hw.init = &init; -+ div->table = table; -+ -+ /* register the clock */ -+ hw = &div->hw; -+ -+ ret = clk_hw_register(dev, hw); -+ if (ret) { -+ kfree(div); -+ hw = ERR_PTR(ret); -+ } -+ -+ return hw; -+} -+ -+static struct clk_hw * -+__clk_hw_register_divider_table(struct device *dev, -+ struct clk_hw_onecell_data *clk_data, -+ void __iomem *base, spinlock_t *lock, -+ const struct clock_config *cfg) -+{ -+ struct div_cfg *div_cfg = cfg->cfg; -+ -+ if (!_is_soc_secured(base)) -+ return clk_hw_register_divider_table(dev, cfg->name, -+ cfg->parent_name, -+ cfg->flags, -+ div_cfg->reg_off + base, -+ div_cfg->shift, -+ div_cfg->width, -+ div_cfg->div_flags, -+ div_cfg->table, -+ lock); -+ else -+ return clk_hw_register_sdivider_table(dev, cfg->name, -+ cfg->parent_name, -+ cfg->flags, -+ div_cfg->reg_off + base, -+ div_cfg->shift, -+ div_cfg->width, -+ div_cfg->div_flags, -+ div_cfg->table, -+ lock); -+} -+ -+static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct arm_smccc_res res; -+ -+ arm_smccc_smc(STM32_SMC_RCC_OPP, STM32_SMC_RCC_OPP_ROUND, rate, 0, 0, 0, -+ 0, 0, &res); -+ -+ return res.a1; -+} -+ -+static int pll1_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ SMC(STM32_SMC_RCC_OPP, STM32_SMC_RCC_OPP_SET, rate, 0); -+ -+ return 0; -+} -+ -+static const struct clk_ops pll1_ops = { -+ .enable = pll_enable, -+ .disable = pll_disable, -+ .recalc_rate = pll_recalc_rate, -+ .round_rate = clk_pll1_round_rate, -+ .set_rate = pll1_set_rate, -+ .is_enabled = pll_is_enabled, -+}; -+ -+static struct clk_hw *_clk_sregister_pll(struct device *dev, -+ struct clk_hw_onecell_data *clk_data, -+ void __iomem *base, spinlock_t *lock, -+ const struct clock_config *cfg) -+{ -+ struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; -+ -+ if (!_is_soc_secured(base)) -+ return clk_register_pll(dev, cfg->name, cfg->parent_name, -+ base + stm_pll_cfg->offset, cfg->flags, -+ stm_pll_cfg->ops, lock); -+ else -+ return clk_register_pll(dev, cfg->name, cfg->parent_name, -+ base + stm_pll_cfg->offset, cfg->flags, -+ stm_pll_cfg->ops_sec, lock); -+} -+ -+#define PLL_1(_id, _name, _parent, _flags, _offset)\ -+{\ -+ .id = _id,\ -+ .name = _name,\ -+ .parent_name = _parent,\ -+ .flags = _flags,\ -+ .cfg = &(struct stm32_pll_cfg) {\ -+ .offset = _offset,\ -+ .ops = &pll_ops,\ -+ .ops_sec = &pll1_ops,\ -+ },\ -+ .func = _clk_sregister_pll,\ -+} -+ -+static int mp1_sgate_clk_enable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(gate->lock, flags); -+ -+ stm32_clk_bit_secure(STM32_SET_BITS, BIT(gate->bit_idx), -+ gate->reg); -+ -+ spin_unlock_irqrestore(gate->lock, flags); -+ -+ return 0; -+} -+ -+static void mp1_sgate_clk_disable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(gate->lock, flags); -+ -+ stm32_clk_bit_secure(STM32_SET_BITS, BIT(gate->bit_idx), -+ gate->reg + RCC_CLR); -+ -+ spin_unlock_irqrestore(gate->lock, flags); -+} -+ -+static const struct clk_ops mp1_sgate_clk_ops = { -+ .enable = mp1_sgate_clk_enable, -+ .disable = mp1_sgate_clk_disable, -+ .is_enabled = clk_gate_is_enabled, -+}; -+ -+static int mp1_s_mgate_clk_enable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); -+ -+ clk_mgate->mgate->flag |= clk_mgate->mask; -+ -+ mp1_sgate_clk_enable(hw); -+ -+ return 0; -+} -+ -+static void mp1_s_mgate_clk_disable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); -+ -+ clk_mgate->mgate->flag &= ~clk_mgate->mask; -+ -+ if (clk_mgate->mgate->flag == 0) -+ mp1_sgate_clk_disable(hw); -+} -+ -+static const struct clk_ops mp1_s_mgate_clk_ops = { -+ .enable = mp1_s_mgate_clk_enable, -+ .disable = mp1_s_mgate_clk_disable, -+ .is_enabled = clk_gate_is_enabled, -+ -+}; -+ -+static u8 clk_s_mmux_get_parent(struct clk_hw *hw) -+{ -+ return clk_smux_ops.get_parent(hw); -+} -+ -+static int clk_s_mmux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); -+ struct clk_hw *hwp; -+ int ret, n; -+ -+ ret = clk_smux_ops.set_parent(hw, index); -+ if (ret) -+ return ret; -+ -+ hwp = clk_hw_get_parent(hw); -+ -+ for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) -+ if (clk_mmux->mmux->hws[n] != hw) -+ clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); -+ -+ return 0; -+} -+ -+static const struct clk_ops clk_s_mmux_ops = { -+ .get_parent = clk_s_mmux_get_parent, -+ .set_parent = clk_s_mmux_set_parent, -+ .determine_rate = __clk_mux_determine_rate, -+}; -+ -+#define SMUX(_id, _name, _parents, _flags,\ -+ _offset, _shift, _width, _mux_flags)\ -+{\ -+ .id = _id,\ -+ .name = _name,\ -+ .parent_names = _parents,\ -+ .num_parents = ARRAY_SIZE(_parents),\ -+ .flags = _flags,\ -+ .cfg = &(struct mux_cfg) {\ -+ .reg_off = _offset,\ -+ .shift = _shift,\ -+ .width = _width,\ -+ .mux_flags = _mux_flags,\ -+ },\ -+ .func = __clk_hw_register_mux,\ -+} -+ -+#define SDIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ -+ _div_flags, _div_table)\ -+{\ -+ .id = _id,\ -+ .name = _name,\ -+ .parent_name = _parent,\ -+ .flags = _flags,\ -+ .cfg = &(struct div_cfg) {\ -+ .reg_off = _offset,\ -+ .shift = _shift,\ -+ .width = _width,\ -+ .div_flags = _div_flags,\ -+ .table = _div_table,\ -+ },\ -+ .func = __clk_hw_register_divider_table,\ -+} -+ -+#define SDIV(_id, _name, _parent, _flags, _offset, _shift, _width,\ -+ _div_flags)\ -+ SDIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ -+ _div_flags, NULL) -+ -+#define _S_GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ -+ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ -+ NULL, NULL, &clk_sgate_ops) -+ -+#define SGATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ -+ STM32_GATE(_id, _name, _parent, _flags,\ -+ _S_GATE(_offset, _bit_idx, _gate_flags)) -+ -+#define _S_GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ -+ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ -+ NULL, &mp1_gate_clk_ops, &mp1_sgate_clk_ops) -+ -+#define SGATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ -+ STM32_GATE(_id, _name, _parent, _flags,\ -+ _S_GATE_MP1(_offset, _bit_idx, _gate_flags)) -+ -+#define _S_DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ -+ _STM32_DIV(_div_offset, _div_shift, _div_width,\ -+ _div_flags, _div_table, NULL, &clk_sdivider_ops) -+ -+#define _S_MUX(_offset, _shift, _width, _mux_flags)\ -+ _STM32_MUX(_offset, _shift, _width, _mux_flags,\ -+ NULL, NULL, &clk_smux_ops) -+ -+#define _S_PLL1_P_DIV(_div_offset, _div_shift, _div_width, _div_flags,\ -+ _div_table)\ -+ _STM32_DIV(_div_offset, _div_shift, _div_width,\ -+ _div_flags, _div_table, NULL, &clk_sdivider_pll1_p_ops) -+ - enum { - G_SAI1, - G_SAI2, -@@ -1402,6 +2018,7 @@ enum { - G_CRYP1, - G_HASH1, - G_BKPSRAM, -+ G_DDRPERFM, - - G_LAST - }; -@@ -1409,7 +2026,7 @@ enum { - static struct stm32_mgate mp1_mgate[G_LAST]; - - #define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -- _mgate, _ops)\ -+ _mgate, _ops, _ops_sec)\ - [_id] = {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ -@@ -1418,15 +2035,24 @@ static struct stm32_mgate mp1_mgate[G_LAST]; - },\ - .mgate = _mgate,\ - .ops = _ops,\ -+ .ops_sec = _ops_sec,\ - } - - #define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -- NULL, &mp1_gate_clk_ops) -+ NULL, &mp1_gate_clk_ops, NULL) -+ -+#define K_GATE_S(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ -+ _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -+ NULL, &mp1_gate_clk_ops, &mp1_sgate_clk_ops) - - #define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -- &mp1_mgate[_id], &mp1_mgate_clk_ops) -+ &mp1_mgate[_id], &mp1_mgate_clk_ops, NULL) -+ -+#define K_MGATE_S(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ -+ _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ -+ &mp1_mgate[_id], &mp1_mgate_clk_ops, &mp1_s_mgate_clk_ops) - - /* Peripheral gates */ - static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { -@@ -1488,20 +2114,21 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), - K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), - K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), -+ K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), - K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), - K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), - -- K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), -- K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), -- K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), -- K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), -- K_GATE(G_TZC2, RCC_APB5ENSETR, 12, 0), -- K_GATE(G_TZC1, RCC_APB5ENSETR, 11, 0), -- K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), -- K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), -- K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), -- K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), -- K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), -+ K_GATE_S(G_STGEN, RCC_APB5ENSETR, 20, 0), -+ K_GATE_S(G_BSEC, RCC_APB5ENSETR, 16, 0), -+ K_GATE_S(G_IWDG1, RCC_APB5ENSETR, 15, 0), -+ K_GATE_S(G_TZPC, RCC_APB5ENSETR, 13, 0), -+ K_GATE_S(G_TZC2, RCC_APB5ENSETR, 12, 0), -+ K_GATE_S(G_TZC1, RCC_APB5ENSETR, 11, 0), -+ K_GATE_S(G_RTCAPB, RCC_APB5ENSETR, 8, 0), -+ K_MGATE_S(G_USART1, RCC_APB5ENSETR, 4, 0), -+ K_MGATE_S(G_I2C6, RCC_APB5ENSETR, 3, 0), -+ K_MGATE_S(G_I2C4, RCC_APB5ENSETR, 2, 0), -+ K_MGATE_S(G_SPI6, RCC_APB5ENSETR, 0, 0), - - K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), - K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), -@@ -1530,11 +2157,11 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), - K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), - -- K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), -- K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), -- K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), -- K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), -- K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), -+ K_GATE_S(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), -+ K_MGATE_S(G_RNG1, RCC_AHB5ENSETR, 6, 0), -+ K_GATE_S(G_HASH1, RCC_AHB5ENSETR, 5, 0), -+ K_GATE_S(G_CRYP1, RCC_AHB5ENSETR, 4, 0), -+ K_GATE_S(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), - - K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), - K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), -@@ -1542,12 +2169,15 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), - K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), - K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), -+ - K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), - K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), - K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), - K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), -+ - K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), - K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), -+ - K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), - }; - -@@ -1592,7 +2222,7 @@ enum { - - static struct stm32_mmux ker_mux[M_LAST]; - --#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ -+#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops, _ops_sec)\ - [_id] = {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ -@@ -1603,15 +2233,24 @@ static struct stm32_mmux ker_mux[M_LAST]; - },\ - .mmux = _mmux,\ - .ops = _ops,\ -+ .ops_sec = _ops_sec,\ - } - - #define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ -- NULL, NULL) -+ NULL, NULL, NULL) -+ -+#define K_MUX_S(_id, _offset, _shift, _width, _mux_flags)\ -+ _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ -+ NULL, NULL, &clk_smux_ops) - - #define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ -- &ker_mux[_id], &clk_mmux_ops) -+ &ker_mux[_id], &clk_mmux_ops, NULL) -+ -+#define K_MMUX_S(_id, _offset, _shift, _width, _mux_flags)\ -+ _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ -+ &ker_mux[_id], &clk_mmux_ops, &clk_s_mmux_ops) - - static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - /* Kernel multi mux */ -@@ -1627,7 +2266,7 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), - K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), - K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), -- K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), -+ K_MMUX_S(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), - - /* Kernel simple mux */ - K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), -@@ -1648,10 +2287,10 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), - K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), - K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), -- K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), -- K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), -- K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), -- K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), -+ K_MUX_S(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), -+ K_MUX_S(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), -+ K_MUX_S(M_USART1, RCC_UART1CKSELR, 0, 3, 0), -+ K_MUX_S(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), - }; - - static const struct clock_config stm32mp1_clock_cfg[] = { -@@ -1660,11 +2299,12 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), - - /* External / Internal Oscillators */ -- GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), -- GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0), -- GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), -- GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), -- GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), -+ SGATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), -+ SGATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, -+ RCC_OCENSETR, 4, 0), -+ SGATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), -+ SGATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), -+ SGATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), - - FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), - -@@ -1679,31 +2319,31 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - 0, 2, CLK_MUX_READ_ONLY), - - /* PLLs */ -- PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), -+ PLL_1(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), - PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), - PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), - PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), - - /* ODF */ -- COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, -- _GATE(RCC_PLL1CR, 4, 0), -+ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), CLK_SET_RATE_PARENT, -+ _S_GATE(RCC_PLL1CR, 4, 0), - _NO_MUX, -- _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), -+ _S_PLL1_P_DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, -- _GATE(RCC_PLL2CR, 4, 0), -+ _S_GATE(RCC_PLL2CR, 4, 0), - _NO_MUX, -- _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), -+ _S_DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, -- _GATE(RCC_PLL2CR, 5, 0), -+ _S_GATE(RCC_PLL2CR, 5, 0), - _NO_MUX, -- _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), -+ _S_DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, -- _GATE(RCC_PLL2CR, 6, 0), -+ _S_GATE(RCC_PLL2CR, 6, 0), - _NO_MUX, -- _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), -+ _S_DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), - - COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 4, 0), -@@ -1739,20 +2379,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, - RCC_CPERCKSELR, 0, 2, 0), - -- MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | -- CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), -+ SMUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | -+ CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, -+ RCC_MPCKSELR, 0, 2, 0), - - COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, -- _MUX(RCC_ASSCKSELR, 0, 2, 0), -- _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), -+ _S_MUX(RCC_ASSCKSELR, 0, 2, 0), -+ _S_DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), - - COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, -- _MUX(RCC_MSSCKSELR, 0, 2, 0), -- _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), -+ _S_MUX(RCC_MSSCKSELR, 0, 2, 0), -+ _S_DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), - - DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), -@@ -1897,6 +2538,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), - PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), - PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), -+ PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), - - /* Kernel clocks */ - KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), -@@ -1907,7 +2549,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), - KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), - KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), -- KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), -+ KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), - KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), - KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), - KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), -@@ -1957,16 +2599,15 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - CLK_SET_RATE_NO_REPARENT, - _NO_GATE, - _MMUX(M_ETHCK), -- _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), -+ _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), - - /* RTC clock */ -- DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, -- CLK_DIVIDER_ALLOW_ZERO), -+ SDIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0), - - COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_PARENT, -- _GATE(RCC_BDCR, 20, 0), -- _MUX(RCC_BDCR, 16, 2, 0), -+ _S_GATE(RCC_BDCR, 20, 0), -+ _S_MUX(RCC_BDCR, 16, 2, 0), - _NO_DIV), - - /* MCO clocks */ -@@ -2084,21 +2725,364 @@ static int stm32_rcc_init(struct device_node *np, - return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); - } - -+static void __iomem *rcc_base; -+ -+static int stm32_rcc_init_pwr(struct device_node *np); -+ - static void stm32mp1_rcc_init(struct device_node *np) - { -- void __iomem *base; -- -- base = of_iomap(np, 0); -- if (!base) { -+ rcc_base = of_iomap(np, 0); -+ if (!rcc_base) { - pr_err("%s: unable to map resource", np->name); - of_node_put(np); - return; - } - -- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { -- iounmap(base); -+ if (stm32_rcc_init(np, rcc_base, stm32mp1_match_data)) { -+ iounmap(rcc_base); - of_node_put(np); -+ return; - } -+ -+ stm32_rcc_init_pwr(np); - } - - CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); -+ -+/* -+ * RCC POWER -+ * -+ */ -+ -+struct reg { -+ u32 address; -+ u32 val; -+}; -+ -+/* This table lists the IPs for which CSLEEP is enabled */ -+static const struct reg lp_table[] = { -+ { 0xB04, 0x00000000 }, /* APB1 */ -+ { 0xB0C, 0x00000000 }, /* APB2 */ -+ { 0xB14, 0x00000800 }, /* APB3 */ -+ { 0x304, 0x00000000 }, /* APB4 */ -+ { 0xB1C, 0x00000000 }, /* AHB2 */ -+ { 0xB24, 0x00000000 }, /* AHB3 */ -+ { 0xB2C, 0x00000000 }, /* AHB4 */ -+ { 0x31C, 0x00000000 }, /* AHB6 */ -+ { 0xB34, 0x00000000 }, /* AXIM */ -+ { 0xB3C, 0x00000000 }, /* MLAHB */ -+}; -+ -+struct sreg { -+ u32 address; -+ u32 secured; -+ u32 val; -+ u8 setclr; -+}; -+ -+#define SREG(_addr, _setclr, _sec) { \ -+ .address = _addr,\ -+ .setclr = _setclr,\ -+ .secured = _sec,\ -+ .val = 0,\ -+} -+ -+static struct sreg clock_gating[] = { -+ SREG(RCC_APB1ENSETR, 1, 0), -+ SREG(RCC_APB2ENSETR, 1, 0), -+ SREG(RCC_APB3ENSETR, 1, 0), -+ SREG(RCC_APB4ENSETR, 1, 0), -+ SREG(RCC_APB5ENSETR, 1, 1), -+ SREG(RCC_AHB5ENSETR, 1, 1), -+ SREG(RCC_AHB6ENSETR, 1, 0), -+ SREG(RCC_AHB2ENSETR, 1, 0), -+ SREG(RCC_AHB3ENSETR, 1, 0), -+ SREG(RCC_AHB4ENSETR, 1, 0), -+ SREG(RCC_MLAHBENSETR, 1, 0), -+ SREG(RCC_MCO1CFGR, 0, 0), -+ SREG(RCC_MCO2CFGR, 0, 0), -+ SREG(RCC_PLL4CFGR2, 0, 0), -+}; -+ -+struct smux { -+ u32 clk_id; -+ u32 mux_id; -+ struct clk_hw *hw; -+}; -+ -+#define KER_SRC(_clk_id, _mux_id)\ -+{\ -+ .clk_id = _clk_id,\ -+ .mux_id = _mux_id,\ -+} -+ -+struct smux _mux_kernel[M_LAST] = { -+ KER_SRC(SDMMC1_K, M_SDMMC12), -+ KER_SRC(SDMMC3_K, M_SDMMC3), -+ KER_SRC(FMC_K, M_FMC), -+ KER_SRC(QSPI_K, M_QSPI), -+ KER_SRC(RNG1_K, M_RNG1), -+ KER_SRC(RNG2_K, M_RNG2), -+ KER_SRC(USBPHY_K, M_USBPHY), -+ KER_SRC(USBO_K, M_USBO), -+ KER_SRC(STGEN_K, M_STGEN), -+ KER_SRC(SPDIF_K, M_SPDIF), -+ KER_SRC(SPI1_K, M_SPI1), -+ KER_SRC(SPI2_K, M_SPI23), -+ KER_SRC(SPI4_K, M_SPI45), -+ KER_SRC(SPI6_K, M_SPI6), -+ KER_SRC(CEC_K, M_CEC), -+ KER_SRC(I2C1_K, M_I2C12), -+ KER_SRC(I2C3_K, M_I2C35), -+ KER_SRC(I2C4_K, M_I2C46), -+ KER_SRC(LPTIM1_K, M_LPTIM1), -+ KER_SRC(LPTIM2_K, M_LPTIM23), -+ KER_SRC(LPTIM4_K, M_LPTIM45), -+ KER_SRC(USART1_K, M_USART1), -+ KER_SRC(USART2_K, M_UART24), -+ KER_SRC(USART3_K, M_UART35), -+ KER_SRC(USART6_K, M_USART6), -+ KER_SRC(UART7_K, M_UART78), -+ KER_SRC(SAI1_K, M_SAI1), -+ KER_SRC(SAI2_K, M_SAI2), -+ KER_SRC(SAI3_K, M_SAI3), -+ KER_SRC(SAI4_K, M_SAI4), -+ KER_SRC(DSI_K, M_DSI), -+ KER_SRC(FDCAN_K, M_FDCAN), -+ KER_SRC(ADC12_K, M_ADC12), -+ KER_SRC(ETHCK_K, M_ETHCK), -+ KER_SRC(CK_PER, M_CKPER), -+}; -+ -+static struct sreg pll_clock[] = { -+ SREG(RCC_PLL3CR, 0, 0), -+ SREG(RCC_PLL4CR, 0, 0), -+}; -+ -+static struct sreg mcu_source[] = { -+ SREG(RCC_MCUDIVR, 0, 0), -+ SREG(RCC_MSSCKSELR, 0, 0), -+}; -+ -+#define RCC_IRQ_FLAGS_MASK 0x110F1F -+#define RCC_STOP_MASK (BIT(0) | BIT(1)) -+#define RCC_RSTSR 0x408 -+#define PWR_MPUCR 0x10 -+#define PLL_EN (BIT(0)) -+#define STOP_FLAG (BIT(5)) -+#define SBF (BIT(11)) -+#define SBF_MPU (BIT(12)) -+ -+static irqreturn_t stm32mp1_rcc_irq_handler(int irq, void *sdata) -+{ -+ pr_info("RCC generic interrupt received\n"); -+ -+ /* clear interrupt flag */ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); -+ -+ return IRQ_HANDLED; -+} -+ -+static void stm32mp1_backup_sreg(struct sreg *sreg, int size) -+{ -+ int i; -+ -+ for (i = 0; i < size; i++) -+ sreg[i].val = readl_relaxed(rcc_base + sreg[i].address); -+} -+ -+static void stm32mp1_restore_sreg(struct sreg *sreg, int size) -+{ -+ int i; -+ u32 val, address, reg; -+ int soc_secured; -+ -+ soc_secured = _is_soc_secured(rcc_base); -+ -+ for (i = 0; i < size; i++) { -+ val = sreg[i].val; -+ address = sreg[i].address; -+ -+ reg = readl_relaxed(rcc_base + address); -+ if (reg == val) -+ continue; -+ -+ if (soc_secured && sreg[i].secured) { -+ SMC(STM32_SVC_RCC, STM32_WRITE, address, val); -+ if (sreg[i].setclr) -+ SMC(STM32_SVC_RCC, STM32_WRITE, -+ address + RCC_CLR, ~val); -+ } else { -+ writel_relaxed(val, rcc_base + address); -+ if (sreg[i].setclr) -+ writel_relaxed(~val, -+ rcc_base + address + RCC_CLR); -+ } -+ } -+} -+ -+static void stm32mp1_restore_pll(struct sreg *sreg, int size) -+{ -+ int i; -+ u32 val; -+ void __iomem *address; -+ -+ for (i = 0; i < size; i++) { -+ val = sreg[i].val; -+ address = sreg[i].address + rcc_base; -+ -+ /* if pll was off turn it on before */ -+ if ((readl_relaxed(address) & PLL_EN) == 0) { -+ writel_relaxed(PLL_EN, address); -+ while ((readl_relaxed(address) & PLL_RDY) == 0) -+ ; -+ } -+ -+ /* 2sd step: restore odf */ -+ writel_relaxed(val, address); -+ } -+} -+ -+static void stm32mp1_backup_mux(struct device_node *np, -+ struct smux *smux, int size) -+{ -+ int i; -+ struct of_phandle_args clkspec; -+ -+ clkspec.np = np; -+ clkspec.args_count = 1; -+ -+ for (i = 0; i < size; i++) { -+ clkspec.args[0] = smux[i].clk_id; -+ smux[i].hw = __clk_get_hw(of_clk_get_from_provider(&clkspec)); -+ } -+} -+ -+static void stm32mp1_restore_mux(struct smux *smux, int size) -+{ -+ int i; -+ struct clk_hw *hw, *hwp1, *hwp2; -+ struct mux_cfg *mux; -+ u8 idx; -+ -+ /* These MUX are glitch free. -+ * Then we have to restore mux thru clock framework -+ * to be sure that CLK_OPS_PARENT_ENABLE will be exploited -+ */ -+ for (i = 0; i < M_LAST; i++) { -+ /* get parent strored in clock framework */ -+ hw = smux[i].hw; -+ hwp1 = clk_hw_get_parent(hw); -+ -+ /* Get parent corresponding to mux register */ -+ mux = ker_mux_cfg[smux[i].mux_id].mux; -+ idx = readl_relaxed(rcc_base + mux->reg_off) >> mux->shift; -+ idx &= (BIT(mux->width) - 1); -+ hwp2 = clk_hw_get_parent_by_index(hw, idx); -+ -+ /* check if parent from mux & clock framework are differents */ -+ if (hwp1 != hwp2) { -+ /* update first clock framework with the true parent */ -+ clk_set_parent(hw->clk, hwp2->clk); -+ -+ /* Restore now new parent */ -+ clk_set_parent(hw->clk, hwp1->clk); -+ } -+ } -+} -+ -+#define RCC_BIT_HSI 0 -+#define RCC_BIT_CSI 4 -+#define RCC_BIT_HSE 8 -+ -+#define RCC_CK_OSC_MASK (BIT(RCC_BIT_HSE) | BIT(RCC_BIT_CSI) | BIT(RCC_BIT_HSI)) -+ -+#define RCC_CK_XXX_KER_MASK (RCC_CK_OSC_MASK << 1) -+ -+static int stm32mp1_clk_suspend(void) -+{ -+ u32 reg; -+ -+ /* Save pll regs */ -+ stm32mp1_backup_sreg(pll_clock, ARRAY_SIZE(pll_clock)); -+ -+ /* Save mcu source */ -+ stm32mp1_backup_sreg(mcu_source, ARRAY_SIZE(mcu_source)); -+ -+ /* Save clock gating regs */ -+ stm32mp1_backup_sreg(clock_gating, ARRAY_SIZE(clock_gating)); -+ -+ /* Enable ck_xxx_ker clocks if ck_xxx was on */ -+ reg = readl_relaxed(rcc_base + RCC_OCENSETR) & RCC_CK_OSC_MASK; -+ writel_relaxed(reg << 1, rcc_base + RCC_OCENSETR); -+ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_RSTSR, 0); -+ -+ return 0; -+} -+ -+static void stm32mp1_clk_resume(void) -+{ -+ -+ /* Restore pll */ -+ stm32mp1_restore_pll(pll_clock, ARRAY_SIZE(pll_clock)); -+ -+ /* Restore mcu source */ -+ stm32mp1_restore_sreg(mcu_source, ARRAY_SIZE(mcu_source)); -+ -+ stm32mp1_restore_sreg(clock_gating, ARRAY_SIZE(clock_gating)); -+ -+ stm32mp1_restore_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel)); -+ -+ /* Disable ck_xxx_ker clocks */ -+ stm32_clk_bit_secure(STM32_SET_BITS, RCC_CK_XXX_KER_MASK, -+ rcc_base + RCC_OCENSETR + RCC_CLR); -+} -+ -+static struct syscore_ops stm32mp1_clk_ops = { -+ .suspend = stm32mp1_clk_suspend, -+ .resume = stm32mp1_clk_resume, -+}; -+ -+static struct irqaction rcc_irq = { -+ .name = "rcc irq", -+ .flags = IRQF_ONESHOT, -+ .handler = stm32mp1_rcc_irq_handler, -+}; -+ -+static int stm32_rcc_init_pwr(struct device_node *np) -+{ -+ int irq; -+ int ret; -+ int i; -+ -+ /* register generic irq */ -+ irq = of_irq_get(np, 0); -+ if (irq <= 0) { -+ pr_err("%s: failed to get RCC generic IRQ\n", __func__); -+ return irq ? irq : -ENXIO; -+ } -+ -+ ret = setup_irq(irq, &rcc_irq); -+ if (ret) { -+ pr_err("%s: failed to register generic IRQ\n", __func__); -+ return ret; -+ } -+ -+ -+ /* Configure LPEN static table */ -+ for (i = 0; i < ARRAY_SIZE(lp_table); i++) -+ writel_relaxed(lp_table[i].val, rcc_base + lp_table[i].address); -+ -+ /* cleanup RCC flags */ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); -+ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_SREQCLRR, RCC_STOP_MASK); -+ -+ /* Prepare kernel clock source backup */ -+ stm32mp1_backup_mux(np, _mux_kernel, ARRAY_SIZE(_mux_kernel)); -+ -+ register_syscore_ops(&stm32mp1_clk_ops); -+ -+ return 0; -+} -diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index 5413ffa..4290d9e 100644 ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -2268,6 +2268,12 @@ static int clk_core_set_parent_nolock(struct clk_core *core, - return ret; - } - -+int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *parent) -+{ -+ return clk_core_set_parent_nolock(hw->core, parent->core); -+} -+EXPORT_SYMBOL_GPL(clk_hw_set_parent); -+ - /** - * clk_set_parent - switch the parent of a mux clk - * @clk: the mux clk whose input we are switching -diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h -index 90ec780..4cdaf13 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/linux/clk-provider.h b/include/linux/clk-provider.h -index d1b6d2c..ec4c906 100644 ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -778,6 +778,7 @@ unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); - struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); - struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, - unsigned int index); -+int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent); - unsigned int __clk_get_enable_count(struct clk *clk); - unsigned long clk_hw_get_rate(const struct clk_hw *hw); - unsigned long __clk_get_flags(struct clk *clk); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch deleted file mode 100644 index 79ba076..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch +++ /dev/null @@ -1,2414 +0,0 @@ -From e2fff57ea5561d1fef1ca923bffe34985ebf3e8c Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:39 +0100 -Subject: [PATCH 07/31] ARM stm32mp1 r3 DRM - ---- - drivers/gpu/drm/bridge/Kconfig | 1 + - drivers/gpu/drm/bridge/sii902x.c | 840 +++++++++++++++++++++-- - drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 102 ++- - drivers/gpu/drm/drm_gem.c | 6 - - drivers/gpu/drm/drm_modes.c | 19 +- - drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 78 ++- - drivers/gpu/drm/panel/panel-raydium-rm68200.c | 20 +- - drivers/gpu/drm/stm/drv.c | 76 +- - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 114 ++- - drivers/gpu/drm/stm/ltdc.c | 282 ++++++-- - drivers/gpu/drm/stm/ltdc.h | 7 + - include/drm/bridge/dw_mipi_dsi.h | 1 + - include/uapi/drm/drm_mode.h | 6 + - 13 files changed, 1352 insertions(+), 200 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig -index 7a3e5a8..7695fdf 100644 ---- a/drivers/gpu/drm/bridge/Kconfig -+++ b/drivers/gpu/drm/bridge/Kconfig -@@ -96,6 +96,7 @@ config DRM_SII902X - depends on OF - select DRM_KMS_HELPER - select REGMAP_I2C -+ select SND_SOC_HDMI_CODEC if SND_SOC - ---help--- - Silicon Image sii902x bridge chip driver. - -diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index 0cc6dbb..b41dd44 100644 ---- a/drivers/gpu/drm/bridge/sii902x.c -+++ b/drivers/gpu/drm/bridge/sii902x.c -@@ -1,4 +1,6 @@ - /* -+ * Copyright (C) 2018 Renesas Electronics -+ * - * Copyright (C) 2016 Atmel - * Bo Shen - * -@@ -20,16 +22,22 @@ - * GNU General Public License for more details. - */ - -+#include - #include -+#include - #include - #include -+#include - #include -+#include - - #include - #include - #include - #include - -+#include -+ - #define SII902X_TPI_VIDEO_DATA 0x0 - - #define SII902X_TPI_PIXEL_REPETITION 0x8 -@@ -71,23 +79,229 @@ - #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) - #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) - -+#define SII902X_I2S_MAP 0x1f -+#define SII902X_I2S_MAP_SWITCH BIT(7) -+#define SII902X_I2S_MAP_SD_MSK GENMASK(5, 4) -+#define SII902X_I2S_MAP_SD(v) \ -+ FIELD_PREP(SII902X_I2S_MAP_SD_MSK, v) -+#define SII902X_I2S_MAP_DS BIT(3) -+#define SII902X_I2S_MAP_SWAP BIT(2) -+#define SII902X_I2S_MAP_FIFO_MSK GENMASK(1, 0) -+#define SII902X_I2S_MAP_FIFO(v) \ -+ FIELD_PREP(SII902X_I2S_MAP_FIFO_MSK, v) -+ -+#define SII902X_I2S_CONF 0x20 -+#define SII902X_I2S_CONF_SCK_STROBING BIT(7) -+#define SII902X_I2S_CONF_MCLK_RATIO_MSK GENMASK(6, 4) -+#define SII902X_I2S_CONF_WS_STROBING BIT(3) -+#define SII902X_I2S_CONF_JUSTIFY BIT(2) -+#define SII902X_I2S_CONF_LSB_DIR BIT(1) -+#define SII902X_I2S_CONF_NO_OFFSET BIT(0) -+ -+#define SII902X_I2S_CS0 0x21 -+ -+#define SII902X_I2S_CS1 0x22 -+ -+#define SII902X_I2S_CS2 0x23 -+#define SII902X_I2S_CS2_SRC_MSK GENMASK(3, 0) -+#define SII902X_I2S_CS2_CHAN_MSK GENMASK(7, 4) -+ -+#define SII902X_I2S_CS3 0x24 -+#define SII902X_I2S_CS3_FS_MSK GENMASK(3, 0) -+#define SII902X_I2S_CS3_FS(v) \ -+ FIELD_PREP(SII902X_I2S_CS3_FS_MSK, v) -+#define SII902X_I2S_CS3_ACC_MSK GENMASK(7, 4) -+ -+#define SII902X_I2S_CS4 0x25 -+#define SII902X_I2S_CS4_WL_MSK GENMASK(3, 0) -+#define SII902X_I2S_CS4_WL(v) \ -+ FIELD_PREP(SII902X_I2S_CS4_WL_MSK, v) -+ -+#define SII902X_AIF 0x26 -+#define SII902X_AIF_FMT_MSK GENMASK(7, 6) -+#define SII902X_AIF_FMT(v) \ -+ FIELD_PREP(SII902X_AIF_FMT_MSK, v) -+#define SII902X_AIF_LAYOUT BIT(5) -+#define SII902X_AIF_MUTE BIT(4) -+#define SII902X_AIF_CODING_MSK GENMASK(3, 0) -+#define SII902X_AIF_CODING(v) \ -+ FIELD_PREP(SII902X_AIF_CODING_MSK, v) -+ -+#define SII902X_I2S_AUD_FMT 0x27 -+#define SII902X_I2S_AUD_FMT_SZ_MSK GENMASK(7, 6) -+#define SII902X_I2S_AUD_FMT_SZ(v) \ -+ FIELD_PREP(SII902X_I2S_AUD_FMT_SZ_MSK, v) -+#define SII902X_I2S_AUD_FMT_FS_MSK GENMASK(5, 3) -+#define SII902X_I2S_AUD_FMT_FS(v) \ -+ FIELD_PREP(SII902X_I2S_AUD_FMT_FS_MSK, v) -+#define SII902X_I2S_AUD_FMT_FS_HBR BIT(2) -+ - #define SII902X_INT_ENABLE 0x3c - #define SII902X_INT_STATUS 0x3d - #define SII902X_HOTPLUG_EVENT BIT(0) - #define SII902X_PLUGGED_STATUS BIT(2) - -+#define SII902X_PLL_R1 0x82 -+#define SII902X_PLL_R1_TCLKSEL_MSK GENMASK(6, 5) -+#define SII902X_PLL_R1_TCLKSEL(v) \ -+ FIELD_PREP(SII902X_PLL_R1_TCLKSEL_MSK, v) -+#define SII902X_PLL_R2 0x83 -+#define SII902X_PLL_R2_CLKMUTLCTL_MSK GENMASK(5, 4) -+#define SII902X_PLL_R2_CLKMUTLCTL(v) \ -+ FIELD_PREP(SII902X_PLL_R2_CLKMUTLCTL_MSK, v) -+#define SII902X_PLL_R3 0x84 -+#define SII902X_PLL_R3_ACLKCNT_MSK GENMASK(5, 4) -+#define SII902X_PLL_R3_ACLKCNT(v) \ -+ FIELD_PREP(SII902X_PLL_R3_ACLKCNT_MSK, v) -+#define SII902X_PLL_R3_HLFCLKEN BIT(1) -+ -+#define SII902X_INDEXED_REG_PAGE 0xbc -+#define SII902X_INDEXED_REG_IDX 0xbd -+#define SII902X_INDEXED_REG_ACCESS 0xbe -+ -+#define SII902X_OTHER_IF 0xbf -+#define SII902X_OTHER_IF_SEL_MSK GENMASK(2, 0) -+#define SII902X_OTHER_IF_SEL(v) \ -+ FIELD_PREP(SII902X_OTHER_IF_SEL_MSK, v) -+#define SII902X_OTHER_IF_REPEAT BIT(6) -+#define SII902X_OTHER_IF_ENABLE BIT(7) -+ - #define SII902X_REG_TPI_RQB 0xc7 - - #define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500 - -+#define SII902X_IF_AUDIO 2 -+ -+/* CEC device */ -+#define SII902X_CEC_I2C_ADDR 0x30 -+ -+#define SII902X_CEC_SETUP 0x8e -+ -+enum sii902x_i2s_map_sd { -+ SII902X_I2S_MAP_SD0, -+ SII902X_I2S_MAP_SD1, -+ SII902X_I2S_MAP_SD2, -+ SII902X_I2S_MAP_SD3, -+}; -+ -+enum sii902x_i2s_map_fifo { -+ SII902X_I2S_MAP_FIFO0, -+ SII902X_I2S_MAP_FIFO1, -+ SII902X_I2S_MAP_FIFO2, -+ SII902X_I2S_MAP_FIFO3, -+}; -+ -+enum sii902x_aif_format { -+ SII902X_AIF_FORMAT_SPDIF = 1, -+ SII902X_AIF_FORMAT_I2S, -+ SII902X_AIF_FORMAT_DSD, -+}; -+ -+enum sii902x_aif_coding { -+ SII902X_AIF_CODING_STREAM_HEADER, -+ SII902X_AIF_CODING_PCM, -+ SII902X_AIF_CODING_AC3, -+ SII902X_AIF_CODING_MPEG1, -+ SII902X_AIF_CODING_MP3, -+ SII902X_AIF_CODING_MPEG2, -+ SII902X_AIF_CODING_AAC, -+ SII902X_AIF_CODING_DTS, -+ SII902X_AIF_CODING_ATRAC, -+}; -+ -+enum sii902x_sample_rate { -+ SII902X_SAMPLE_RATE_32000 = 1, -+ SII902X_SAMPLE_RATE_44100, -+ SII902X_SAMPLE_RATE_48000, -+ SII902X_SAMPLE_RATE_88200, -+ SII902X_SAMPLE_RATE_96000, -+ SII902X_SAMPLE_RATE_176400, -+ SII902X_SAMPLE_RATE_192000, -+}; -+ -+enum sii902x_sample_width { -+ SII902X_SAMPLE_RATE_SIZE_16 = 1, -+ SII902X_SAMPLE_RATE_SIZE_20, -+ SII902X_SAMPLE_RATE_SIZE_24, -+}; -+ -+struct sii902x_audio_params { -+ unsigned int aes_size; -+ unsigned int aes_rate; -+}; -+ - struct sii902x { - struct i2c_client *i2c; - struct regmap *regmap; - struct drm_bridge bridge; - struct drm_connector connector; - struct gpio_desc *reset_gpio; -+ struct i2c_mux_core *i2cmux; -+ struct regulator_bulk_data supplies[2]; -+ struct platform_device *audio_pdev; -+ struct sii902x_audio_params audio; -+ struct edid *edid; - }; - -+static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) -+{ -+ struct i2c_msg xfer[] = { -+ { -+ .addr = i2c->addr, -+ .flags = 0, -+ .len = 1, -+ .buf = ®, -+ }, { -+ .addr = i2c->addr, -+ .flags = I2C_M_RD, -+ .len = 1, -+ .buf = val, -+ } -+ }; -+ unsigned char xfers = ARRAY_SIZE(xfer); -+ int ret, retries = 5; -+ -+ do { -+ ret = __i2c_transfer(i2c->adapter, xfer, xfers); -+ if (ret < 0) -+ return ret; -+ } while (ret != xfers && --retries); -+ return ret == xfers ? 0 : -1; -+} -+ -+static int sii902x_write_unlocked(struct i2c_client *i2c, u8 reg, u8 val) -+{ -+ u8 data[2] = {reg, val}; -+ struct i2c_msg xfer = { -+ .addr = i2c->addr, -+ .flags = 0, -+ .len = sizeof(data), -+ .buf = data, -+ }; -+ int ret, retries = 5; -+ -+ do { -+ ret = __i2c_transfer(i2c->adapter, &xfer, 1); -+ if (ret < 0) -+ return ret; -+ } while (!ret && --retries); -+ return !ret ? -1 : 0; -+} -+ -+static int sii902x_update_bits_unlocked(struct i2c_client *i2c, u8 reg, u8 mask, -+ u8 val) -+{ -+ int ret; -+ u8 status; -+ -+ ret = sii902x_read_unlocked(i2c, reg, &status); -+ if (ret) -+ return ret; -+ status &= ~mask; -+ status |= val & mask; -+ return sii902x_write_unlocked(i2c, reg, status); -+} -+ - static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge) - { - return container_of(bridge, struct sii902x, bridge); -@@ -135,45 +349,18 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { - static int sii902x_get_modes(struct drm_connector *connector) - { - struct sii902x *sii902x = connector_to_sii902x(connector); -- struct regmap *regmap = sii902x->regmap; - u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; -- struct device *dev = &sii902x->i2c->dev; -- unsigned long timeout; -- unsigned int retries; -- unsigned int status; - struct edid *edid; -- int num = 0; -- int ret; -- -- ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, -- SII902X_SYS_CTRL_DDC_BUS_REQ, -- SII902X_SYS_CTRL_DDC_BUS_REQ); -- if (ret) -- return ret; -- -- timeout = jiffies + -- msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); -- do { -- ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); -- if (ret) -- return ret; -- } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) && -- time_before(jiffies, timeout)); -+ bool hdmi_mode = false; -+ int num = 0, ret; - -- if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { -- dev_err(dev, "failed to acquire the i2c bus\n"); -- return -ETIMEDOUT; -- } -- -- ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status); -- if (ret) -- return ret; -- -- edid = drm_get_edid(connector, sii902x->i2c->adapter); -+ edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); - drm_connector_update_edid_property(connector, edid); - if (edid) { - num = drm_add_edid_modes(connector, edid); -- kfree(edid); -+ hdmi_mode = drm_detect_hdmi_monitor(edid); -+ kfree(sii902x->edid); -+ sii902x->edid = edid; - } - - ret = drm_display_info_set_bus_formats(&connector->display_info, -@@ -181,41 +368,10 @@ static int sii902x_get_modes(struct drm_connector *connector) - if (ret) - return ret; - -- /* -- * Sometimes the I2C bus can stall after failure to use the -- * EDID channel. Retry a few times to see if things clear -- * up, else continue anyway. -- */ -- retries = 5; -- do { -- ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, -- &status); -- retries--; -- } while (ret && retries); -- if (ret) -- dev_err(dev, "failed to read status (%d)\n", ret); -- -- ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, -- SII902X_SYS_CTRL_DDC_BUS_REQ | -- SII902X_SYS_CTRL_DDC_BUS_GRTD, 0); -- if (ret) -- return ret; -- -- timeout = jiffies + -- msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); -- do { -- ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); -- if (ret) -- return ret; -- } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | -- SII902X_SYS_CTRL_DDC_BUS_GRTD) && -- time_before(jiffies, timeout)); -- -- if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | -- SII902X_SYS_CTRL_DDC_BUS_GRTD)) { -- dev_err(dev, "failed to release the i2c bus\n"); -- return -ETIMEDOUT; -- } -+ if (hdmi_mode) -+ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, -+ SII902X_SYS_CTRL_OUTPUT_MODE, -+ SII902X_SYS_CTRL_OUTPUT_HDMI); - - return num; - } -@@ -245,12 +401,22 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) - static void sii902x_bridge_enable(struct drm_bridge *bridge) - { - struct sii902x *sii902x = bridge_to_sii902x(bridge); -+ bool hdmi_mode; - - regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, - SII902X_AVI_POWER_STATE_MSK, - SII902X_AVI_POWER_STATE_D(0)); - regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_PWR_DWN, 0); -+ -+ if(sii902x->edid) { -+ hdmi_mode = drm_detect_hdmi_monitor(sii902x->edid); -+ if (hdmi_mode) -+ regmap_update_bits(sii902x->regmap, -+ SII902X_SYS_CTRL_DATA, -+ SII902X_SYS_CTRL_OUTPUT_MODE, -+ SII902X_SYS_CTRL_OUTPUT_HDMI); -+ } - } - - static void sii902x_bridge_mode_set(struct drm_bridge *bridge, -@@ -330,6 +496,267 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) - return 0; - } - -+static int sii902x_audio_infoframe_config(struct sii902x *sii902x, -+ struct hdmi_codec_params *params) -+{ -+ u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)]; -+ int ret; -+ -+ ret = hdmi_audio_infoframe_init(¶ms->cea); -+ if (ret) { -+ DRM_ERROR("Failed to init audio infoframe\n"); -+ return ret; -+ } -+ -+ ret = hdmi_audio_infoframe_pack(¶ms->cea, buf, sizeof(buf)); -+ if (ret < 0) { -+ DRM_ERROR("failed to pack audio infoframe: %d\n", ret); -+ return ret; -+ } -+ -+ regmap_update_bits(sii902x->regmap, -+ SII902X_OTHER_IF, -+ SII902X_OTHER_IF_SEL_MSK | -+ SII902X_OTHER_IF_REPEAT | -+ SII902X_OTHER_IF_ENABLE, -+ SII902X_OTHER_IF_SEL(SII902X_IF_AUDIO) | -+ SII902X_OTHER_IF_REPEAT | -+ SII902X_OTHER_IF_ENABLE); -+ -+ return regmap_bulk_write(sii902x->regmap, SII902X_OTHER_IF + 1, buf, -+ HDMI_INFOFRAME_SIZE(AUDIO) + -+ HDMI_INFOFRAME_HEADER_SIZE - 1); -+} -+ -+static int sii902x_audio_iec60958_config(struct sii902x *sii902x) -+{ -+ /* Bytes 0,1,2 are let to default setting. Configure bytes 3&4 */ -+ regmap_update_bits(sii902x->regmap, -+ SII902X_I2S_CS3, -+ SII902X_I2S_CS3_FS_MSK, -+ SII902X_I2S_CS3_FS(sii902x->audio.aes_rate)); -+ -+ return regmap_update_bits(sii902x->regmap, -+ SII902X_I2S_CS4, -+ SII902X_I2S_CS4_WL_MSK, -+ SII902X_I2S_CS4_WL(sii902x->audio.aes_size)); -+} -+ -+static int sii902x_i2s_configure(struct sii902x *sii902x, -+ struct hdmi_codec_params *params, -+ struct hdmi_codec_daifmt *fmt) -+{ -+ unsigned int rate, size, val, mask; -+ -+ /* Configure audio interface */ -+ regmap_update_bits(sii902x->regmap, SII902X_AIF, -+ SII902X_AIF_FMT_MSK | -+ SII902X_AIF_LAYOUT | -+ SII902X_AIF_MUTE | -+ SII902X_AIF_CODING_MSK, -+ SII902X_AIF_FMT(SII902X_AIF_FORMAT_I2S) | -+ SII902X_AIF_MUTE | -+ SII902X_AIF_CODING(SII902X_AIF_CODING_PCM)); -+ -+ switch (fmt->fmt) { -+ case HDMI_I2S: -+ val = SII902X_I2S_CONF_SCK_STROBING; -+ break; -+ case HDMI_LEFT_J: -+ val = SII902X_I2S_CONF_SCK_STROBING | -+ SII902X_I2S_CONF_WS_STROBING | -+ SII902X_I2S_CONF_NO_OFFSET; -+ break; -+ case HDMI_RIGHT_J: -+ val = SII902X_I2S_CONF_SCK_STROBING | -+ SII902X_I2S_CONF_WS_STROBING | -+ SII902X_I2S_CONF_NO_OFFSET | -+ SII902X_I2S_CONF_JUSTIFY; -+ break; -+ default: -+ DRM_ERROR("Unknown protocol %#x\n", fmt->fmt); -+ return -EINVAL; -+ } -+ mask = SII902X_I2S_CONF_NO_OFFSET | SII902X_I2S_CONF_WS_STROBING | -+ SII902X_I2S_CONF_JUSTIFY | SII902X_I2S_CONF_LSB_DIR | -+ SII902X_I2S_CONF_SCK_STROBING; -+ -+ if (fmt->frame_clk_inv) -+ val ^= SII902X_I2S_CONF_WS_STROBING; -+ -+ if (fmt->bit_clk_inv) -+ val ^= SII902X_I2S_CONF_SCK_STROBING; -+ -+ /* Configure i2s interface */ -+ regmap_update_bits(sii902x->regmap, -+ SII902X_I2S_CONF, mask, val); -+ -+ /* -+ * Configure i2s interface mapping -+ * Assume that only SD0 is used and connected to FIFO0 -+ */ -+ regmap_update_bits(sii902x->regmap, -+ SII902X_I2S_MAP, -+ SII902X_I2S_MAP_SWITCH | -+ SII902X_I2S_MAP_SD_MSK | SII902X_I2S_MAP_FIFO_MSK, -+ SII902X_I2S_MAP_SWITCH | -+ SII902X_I2S_MAP_SD0 | SII902X_I2S_MAP_FIFO0); -+ -+ switch (params->sample_rate) { -+ case 32000: -+ rate = SII902X_SAMPLE_RATE_32000; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_32000; -+ break; -+ case 44100: -+ rate = SII902X_SAMPLE_RATE_44100; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_44100; -+ break; -+ case 48000: -+ rate = SII902X_SAMPLE_RATE_48000; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_48000; -+ break; -+ case 88200: -+ rate = SII902X_SAMPLE_RATE_88200; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_88200; -+ break; -+ case 96000: -+ rate = SII902X_SAMPLE_RATE_96000; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_96000; -+ break; -+ case 176400: -+ rate = SII902X_SAMPLE_RATE_176400; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_176400; -+ break; -+ case 192000: -+ rate = SII902X_SAMPLE_RATE_192000; -+ sii902x->audio.aes_rate = IEC958_AES3_CON_FS_192000; -+ break; -+ default: -+ DRM_ERROR("Unknown sampling rate %d\n", params->sample_rate); -+ return -EINVAL; -+ } -+ -+ switch (params->sample_width) { -+ case 16: -+ size = SII902X_SAMPLE_RATE_SIZE_16; -+ sii902x->audio.aes_size = IEC958_AES4_CON_WORDLEN_20_16; -+ break; -+ case 20: -+ size = SII902X_SAMPLE_RATE_SIZE_20; -+ sii902x->audio.aes_size = IEC958_AES4_CON_WORDLEN_24_20; -+ break; -+ case 24: -+ case 32: -+ size = SII902X_SAMPLE_RATE_SIZE_24; -+ sii902x->audio.aes_size = IEC958_AES4_CON_WORDLEN_24_20 | -+ IEC958_AES4_CON_MAX_WORDLEN_24; -+ break; -+ default: -+ DRM_ERROR("Unknown sample width %d\n", params->sample_width); -+ return -EINVAL; -+ } -+ -+ /* Configure i2s interface rate and input/output word length */ -+ regmap_update_bits(sii902x->regmap, -+ SII902X_INDEXED_REG_PAGE, 0xff, 0x2); -+ regmap_update_bits(sii902x->regmap, -+ SII902X_INDEXED_REG_IDX, 0xff, 0x24); -+ regmap_update_bits(sii902x->regmap, -+ SII902X_INDEXED_REG_ACCESS, 0x0f, -+ sii902x->audio.aes_size); -+ -+ return regmap_update_bits(sii902x->regmap, -+ SII902X_I2S_AUD_FMT, -+ SII902X_I2S_AUD_FMT_FS_MSK | -+ SII902X_I2S_AUD_FMT_SZ_MSK, -+ SII902X_I2S_AUD_FMT_FS(rate) | -+ SII902X_I2S_AUD_FMT_SZ(size)); -+} -+ -+static int sii902x_audio_hw_params(struct device *dev, void *data, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *params) -+{ -+ struct sii902x *sii902x = dev_get_drvdata(dev); -+ int ret; -+ -+ if (fmt->bit_clk_master || fmt->frame_clk_master) { -+ DRM_ERROR("Master mode not supported\n"); -+ return -EINVAL; -+ } -+ -+ if (fmt->fmt == HDMI_I2S || fmt->fmt == HDMI_RIGHT_J || -+ fmt->fmt == HDMI_LEFT_J) { -+ /* Configure i2s interface */ -+ ret = sii902x_i2s_configure(sii902x, params, fmt); -+ if (ret) -+ return ret; -+ -+ /* Configure iec958 channel status */ -+ ret = sii902x_audio_iec60958_config(sii902x); -+ if (ret) -+ return ret; -+ } else { -+ DRM_ERROR("Unsupported format 0x%x\n", fmt->fmt); -+ return -EINVAL; -+ } -+ -+ /* Configure audio infoframes */ -+ return sii902x_audio_infoframe_config(sii902x, params); -+} -+ -+static int sii902x_audio_digital_mute(struct device *dev, -+ void *data, bool enable) -+{ -+ struct sii902x *sii902x = dev_get_drvdata(dev); -+ int ret; -+ -+ DRM_DEBUG("%s audio\n", enable ? "mute" : "unmute"); -+ -+ if (enable) -+ ret = regmap_update_bits(sii902x->regmap, SII902X_AIF, -+ SII902X_AIF_MUTE, SII902X_AIF_MUTE); -+ else -+ ret = regmap_update_bits(sii902x->regmap, SII902X_AIF, -+ SII902X_AIF_MUTE, 0); -+ -+ return ret; -+} -+ -+static int sii902x_audio_get_eld(struct device *dev, void *data, -+ u8 *buf, size_t len) -+{ -+ struct sii902x *sii902x = dev_get_drvdata(dev); -+ struct drm_connector *connector = &sii902x->connector; -+ -+ if (!sii902x->edid) -+ return -ENODEV; -+ -+ memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); -+ -+ return 0; -+} -+ -+static void sii902x_audio_shutdown(struct device *dev, void *data) -+{} -+ -+static int sii902x_audio_get_dai_id(struct snd_soc_component *component, -+ struct device_node *endpoint) -+{ -+ struct of_endpoint of_ep; -+ int ret; -+ -+ ret = of_graph_parse_endpoint(endpoint, &of_ep); -+ if (ret < 0) -+ return ret; -+ -+ /* HDMI sound should be located at reg = <1> */ -+ if (of_ep.port == 1) -+ return 0; -+ -+ return -EINVAL; -+} -+ - static const struct drm_bridge_funcs sii902x_bridge_funcs = { - .attach = sii902x_bridge_attach, - .mode_set = sii902x_bridge_mode_set, -@@ -349,10 +776,39 @@ static const struct regmap_access_table sii902x_volatile_table = { - static const struct regmap_config sii902x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -+ /* map up to infoframe data registers. 0xbf-0xde */ -+ .max_register = 0xde, - .volatile_table = &sii902x_volatile_table, - .cache_type = REGCACHE_NONE, - }; - -+static const struct hdmi_codec_ops sii902x_codec_ops = { -+ .hw_params = sii902x_audio_hw_params, -+ .audio_shutdown = sii902x_audio_shutdown, -+ .get_dai_id = sii902x_audio_get_dai_id, -+ .digital_mute = sii902x_audio_digital_mute, -+ .get_eld = sii902x_audio_get_eld, -+}; -+ -+static int sii902x_register_audio_driver(struct device *dev, -+ struct sii902x *sii902x) -+{ -+ struct hdmi_codec_pdata codec_data = { -+ .ops = &sii902x_codec_ops, -+ .max_i2s_channels = 2, -+ .i2s = 1, -+ }; -+ -+ sii902x->audio_pdev = platform_device_register_data( -+ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, -+ &codec_data, sizeof(codec_data)); -+ -+ if (IS_ERR(sii902x->audio_pdev)) -+ return PTR_ERR(sii902x->audio_pdev); -+ -+ return 0; -+} -+ - static irqreturn_t sii902x_interrupt(int irq, void *data) - { - struct sii902x *sii902x = data; -@@ -367,15 +823,134 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) - return IRQ_HANDLED; - } - -+/* -+ * The purpose of sii902x_i2c_bypass_select is to enable the pass through -+ * mode of the HDMI transmitter. Do not use regmap from within this function, -+ * only use sii902x_*_unlocked functions to read/modify/write registers. -+ * We are holding the parent adapter lock here, keep this in mind before -+ * adding more i2c transactions. -+ */ -+static int sii902x_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id) -+{ -+ struct sii902x *sii902x = i2c_mux_priv(mux); -+ struct device *dev = &sii902x->i2c->dev; -+ unsigned long timeout; -+ u8 status; -+ int ret; -+ -+ ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ SII902X_SYS_CTRL_DDC_BUS_REQ, -+ SII902X_SYS_CTRL_DDC_BUS_REQ); -+ -+ timeout = jiffies + -+ msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); -+ do { -+ ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ &status); -+ if (ret) -+ return ret; -+ } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) && -+ time_before(jiffies, timeout)); -+ -+ if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { -+ dev_err(dev, "Failed to acquire the i2c bus\n"); -+ return -ETIMEDOUT; -+ } -+ -+ ret = sii902x_write_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ status); -+ if (ret) -+ return ret; -+ return 0; -+} -+ -+/* -+ * The purpose of sii902x_i2c_bypass_deselect is to disable the pass through -+ * mode of the HDMI transmitter. Do not use regmap from within this function, -+ * only use sii902x_*_unlocked functions to read/modify/write registers. -+ * We are holding the parent adapter lock here, keep this in mind before -+ * adding more i2c transactions. -+ */ -+static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) -+{ -+ struct sii902x *sii902x = i2c_mux_priv(mux); -+ struct device *dev = &sii902x->i2c->dev; -+ unsigned long timeout; -+ unsigned int retries; -+ u8 status; -+ int ret; -+ -+ /* -+ * When the HDMI transmitter is in pass through mode, we need an -+ * (undocumented) additional delay between STOP and START conditions -+ * to guarantee the bus won't get stuck. -+ */ -+ udelay(30); -+ -+ /* -+ * Sometimes the I2C bus can stall after failure to use the -+ * EDID channel. Retry a few times to see if things clear -+ * up, else continue anyway. -+ */ -+ retries = 5; -+ do { -+ ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ &status); -+ retries--; -+ } while (ret && retries); -+ if (ret) { -+ dev_err(dev, "failed to read status (%d)\n", ret); -+ return ret; -+ } -+ -+ ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ SII902X_SYS_CTRL_DDC_BUS_REQ | -+ SII902X_SYS_CTRL_DDC_BUS_GRTD, 0); -+ if (ret) -+ return ret; -+ -+ timeout = jiffies + -+ msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); -+ do { -+ ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, -+ &status); -+ if (ret) -+ return ret; -+ } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | -+ SII902X_SYS_CTRL_DDC_BUS_GRTD) && -+ time_before(jiffies, timeout)); -+ -+ if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | -+ SII902X_SYS_CTRL_DDC_BUS_GRTD)) { -+ dev_err(dev, "failed to release the i2c bus\n"); -+ return -ETIMEDOUT; -+ } -+ -+ return 0; -+} -+ - static int sii902x_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { - struct device *dev = &client->dev; - unsigned int status = 0; - struct sii902x *sii902x; -+ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; -+ struct i2c_msg msg = { -+ .addr = SII902X_CEC_I2C_ADDR << 1, -+ .flags = 0, -+ .len = 2, -+ .buf = data, -+ }; - u8 chipid[4]; - int ret; - -+ ret = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); -+ if (!ret) { -+ dev_err(dev, "I2C adapter not suitable\n"); -+ return -EIO; -+ } -+ - sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); - if (!sii902x) - return -ENOMEM; -@@ -393,39 +968,66 @@ static int sii902x_probe(struct i2c_client *client, - return PTR_ERR(sii902x->reset_gpio); - } - -+ sii902x->supplies[0].supply = "iovcc"; -+ sii902x->supplies[1].supply = "cvcc12"; -+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ if (ret) { -+ if(ret != -EPROBE_DEFER) -+ dev_err(dev, "regulator_bulk_get failed\n"); -+ return ret; -+ } -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ if (ret) { -+ dev_err(dev, "regulator_bulk_enable failed\n"); -+ return ret; -+ } -+ - sii902x_reset(sii902x); - - ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); - if (ret) -- return ret; -+ goto err_disable_regulator; - - ret = regmap_bulk_read(sii902x->regmap, SII902X_REG_CHIPID(0), - &chipid, 4); - if (ret) { - dev_err(dev, "regmap_read failed %d\n", ret); -- return ret; -+ goto err_disable_regulator; - } - - if (chipid[0] != 0xb0) { - dev_err(dev, "Invalid chipid: %02x (expecting 0xb0)\n", - chipid[0]); -- return -EINVAL; -+ ret = -EINVAL; -+ goto err_disable_regulator; - } - -+ /* -+ * By default, CEC must be disabled to allow other CEC devives -+ * to bypass the bridge. -+ */ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) -+ dev_warn(&client->dev, "Failed to disable CEC device!\n"); -+ - /* Clear all pending interrupts */ - regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); - regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); - - if (client->irq > 0) { -- regmap_write(sii902x->regmap, SII902X_INT_ENABLE, -- SII902X_HOTPLUG_EVENT); -+ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, -+ SII902X_HOTPLUG_EVENT, -+ SII902X_HOTPLUG_EVENT); - - ret = devm_request_threaded_irq(dev, client->irq, NULL, - sii902x_interrupt, - IRQF_ONESHOT, dev_name(dev), - sii902x); - if (ret) -- return ret; -+ goto err_disable_regulator; - } - - sii902x->bridge.funcs = &sii902x_bridge_funcs; -@@ -434,7 +1036,31 @@ static int sii902x_probe(struct i2c_client *client, - - i2c_set_clientdata(client, sii902x); - -+ sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev, -+ 1, 0, I2C_MUX_GATE, -+ sii902x_i2c_bypass_select, -+ sii902x_i2c_bypass_deselect); -+ if (!sii902x->i2cmux) { -+ dev_err(dev, "failed to allocate I2C mux\n"); -+ return -ENOMEM; -+ } -+ -+ sii902x->i2cmux->priv = sii902x; -+ ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); -+ if (ret) { -+ dev_err(dev, "Couldn't add i2c mux adapter\n"); -+ return ret; -+ } -+ -+ sii902x_register_audio_driver(dev, sii902x); -+ - return 0; -+ -+err_disable_regulator: -+ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ -+ return ret; - } - - static int sii902x_remove(struct i2c_client *client) -@@ -442,11 +1068,76 @@ static int sii902x_remove(struct i2c_client *client) - { - struct sii902x *sii902x = i2c_get_clientdata(client); - -+ if (sii902x->i2cmux) -+ i2c_mux_del_adapters(sii902x->i2cmux); -+ - drm_bridge_remove(&sii902x->bridge); - -+ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ -+ return 0; -+} -+ -+static int sii902x_pm_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sii902x *sii902x = i2c_get_clientdata(client); -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ if (sii902x->reset_gpio) -+ gpiod_set_value(sii902x->reset_gpio, 1); -+ -+ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ - return 0; - } - -+static int sii902x_pm_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sii902x *sii902x = i2c_get_clientdata(client); -+ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; -+ struct i2c_msg msg = { -+ .addr = SII902X_CEC_I2C_ADDR << 1, -+ .flags = 0, -+ .len = 2, -+ .buf = data, -+ }; -+ int ret; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), -+ sii902x->supplies); -+ if (ret) { -+ DRM_ERROR("regulator_bulk_enable failed\n"); -+ return ret; -+ } -+ -+ if (sii902x->reset_gpio) -+ gpiod_set_value(sii902x->reset_gpio, 0); -+ -+ regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) -+ DRM_ERROR("Failed to disable CEC device!\n"); -+ -+ if (client->irq > 0) -+ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, -+ SII902X_HOTPLUG_EVENT, -+ SII902X_HOTPLUG_EVENT); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops sii902x_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) -+}; -+ - static const struct of_device_id sii902x_dt_ids[] = { - { .compatible = "sil,sii9022", }, - { } -@@ -465,6 +1156,7 @@ static struct i2c_driver sii902x_driver = { - .driver = { - .name = "sii902x", - .of_match_table = sii902x_dt_ids, -+ .pm = &sii902x_pm_ops, - }, - .id_table = sii902x_i2c_ids, - }; -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -index fd79996..2e4334f 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -@@ -206,6 +206,20 @@ - - #define DSI_INT_ST0 0xbc - #define DSI_INT_ST1 0xc0 -+#define GPRXE BIT(12) -+#define GPRDE BIT(11) -+#define GPTXE BIT(10) -+#define GPWRE BIT(9) -+#define GCWRE BIT(8) -+#define DPIPLDWE BIT(7) -+#define EOTPE BIT(6) -+#define PSE BIT(5) -+#define CRCE BIT(4) -+#define ECCME BIT(3) -+#define ECCSE BIT(2) -+#define TOLPRX BIT(1) -+#define TOHSTX BIT(0) -+ - #define DSI_INT_MSK0 0xc4 - #define DSI_INT_MSK1 0xc8 - -@@ -357,6 +371,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) - return 0; - } - -+static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi) -+{ -+ u32 val; -+ -+ val = dsi_read(dsi, DSI_INT_ST1); -+ -+ if (val & GPRXE) -+ DRM_DEBUG_DRIVER("DSI Generic payload receive error\n"); -+ if (val & GPRDE) -+ DRM_DEBUG_DRIVER("DSI Generic payload read error\n"); -+ if (val & GPTXE) -+ DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n"); -+ if (val & GPWRE) -+ DRM_DEBUG_DRIVER("DSI Generic payload write error\n"); -+ if (val & GCWRE) -+ DRM_DEBUG_DRIVER("DSI Generic command write error\n"); -+ if (val & DPIPLDWE) -+ DRM_DEBUG_DRIVER("DSI DPI payload write error\n"); -+ if (val & EOTPE) -+ DRM_DEBUG_DRIVER("DSI EoTp error\n"); -+ if (val & PSE) -+ DRM_DEBUG_DRIVER("DSI Packet size error\n"); -+ if (val & CRCE) -+ DRM_DEBUG_DRIVER("DSI CRC error\n"); -+ if (val & ECCME) -+ DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n"); -+ if (val & ECCSE) -+ DRM_DEBUG_DRIVER("DSI ECC single-bit error\n"); -+ if (val & TOLPRX) -+ DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n"); -+ if (val & TOHSTX) -+ DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n"); -+ -+ return val; -+} -+ - static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, - const struct mipi_dsi_packet *packet) - { -@@ -386,6 +436,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, - "failed to get available write payload FIFO\n"); - return ret; - } -+ -+ val = dw_mipi_dsi_read_status(dsi); -+ if (val) { -+ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); -+ return -EINVAL; -+ } - } - - word = 0; -@@ -419,6 +475,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, - return ret; - } - -+ val = dw_mipi_dsi_read_status(dsi); -+ if (val) { -+ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); -+ return -EINVAL; -+ } -+ - val = dsi_read(dsi, DSI_GEN_PLD_DATA); - for (j = 0; j < 4 && j + i < len; j++) - buf[i + j] = val >> (8 * j); -@@ -433,6 +495,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, - struct dw_mipi_dsi *dsi = host_to_dsi(host); - struct mipi_dsi_packet packet; - int ret, nb_bytes; -+ int retry = 3; - - ret = mipi_dsi_create_packet(&packet, msg); - if (ret) { -@@ -442,19 +505,26 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, - - 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); -+ while (retry--) { -+ ret = dw_mipi_dsi_write(dsi, &packet); - if (ret) -- return ret; -- nb_bytes = msg->rx_len; -- } else { -- nb_bytes = packet.size; -+ continue; -+ -+ if (msg->rx_buf && msg->rx_len) { -+ ret = dw_mipi_dsi_read(dsi, msg); -+ if (ret) -+ continue; -+ nb_bytes = msg->rx_len; -+ break; -+ } else { -+ nb_bytes = packet.size; -+ break; -+ } - } - -+ if (ret) -+ return ret; -+ - return nb_bytes; - } - -@@ -488,6 +558,9 @@ 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 dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; -+ void *priv_data = dsi->plat_data->priv_data; -+ - dsi_write(dsi, DSI_PWR_UP, RESET); - - if (mode_flags & MIPI_DSI_MODE_VIDEO) { -@@ -498,6 +571,9 @@ 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(priv_data, mode_flags); -+ - dsi_write(dsi, DSI_PWR_UP, POWERUP); - } - -@@ -588,6 +664,9 @@ 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 dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; -+ void *priv_data = dsi->plat_data->priv_data; -+ - /* - * TODO dw drv improvements - * compute high speed transmission counter timeout according -@@ -601,6 +680,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(priv_data, 0); - } - - /* Get lane byte clock cycles. */ -diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c -index bf90625..c7217b1 100644 ---- a/drivers/gpu/drm/drm_gem.c -+++ b/drivers/gpu/drm/drm_gem.c -@@ -326,12 +326,6 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - if (!obj) - return -ENOENT; - -- /* Don't allow imported objects to be mapped */ -- if (obj->import_attach) { -- ret = -EINVAL; -- goto out; -- } -- - ret = drm_gem_create_mmap_offset(obj); - if (ret) - goto out; -diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c -index a3104d7..f1600e4 100644 ---- a/drivers/gpu/drm/drm_modes.c -+++ b/drivers/gpu/drm/drm_modes.c -@@ -130,7 +130,7 @@ EXPORT_SYMBOL(drm_mode_probed_add); - * according to the hdisplay, vdisplay, vrefresh. - * It is based from the VESA(TM) Coordinated Video Timing Generator by - * Graham Loveridge April 9, 2003 available at -- * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls -+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls - * - * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. - * What I have done is to translate it by using integer calculation. -@@ -611,6 +611,15 @@ void drm_display_mode_from_videomode(const struct videomode *vm, - dmode->flags |= DRM_MODE_FLAG_DBLSCAN; - if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) - dmode->flags |= DRM_MODE_FLAG_DBLCLK; -+ if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) -+ dmode->flags |= DRM_MODE_FLAG_PPIXDATA; -+ else if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) -+ dmode->flags |= DRM_MODE_FLAG_NPIXDATA; -+ if (vm->flags & DISPLAY_FLAGS_DE_HIGH) -+ dmode->flags |= DRM_MODE_FLAG_PDE; -+ else if (vm->flags & DISPLAY_FLAGS_DE_LOW) -+ dmode->flags |= DRM_MODE_FLAG_NDE; -+ - drm_mode_set_name(dmode); - } - EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); -@@ -652,6 +661,14 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, - vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; - if (dmode->flags & DRM_MODE_FLAG_DBLCLK) - vm->flags |= DISPLAY_FLAGS_DOUBLECLK; -+ if (dmode->flags & DRM_MODE_FLAG_PPIXDATA) -+ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; -+ else if (dmode->flags & DRM_MODE_FLAG_NPIXDATA) -+ vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; -+ if (dmode->flags & DRM_MODE_FLAG_PDE) -+ vm->flags |= DISPLAY_FLAGS_DE_HIGH; -+ else if (dmode->flags & DRM_MODE_FLAG_NDE) -+ vm->flags |= DISPLAY_FLAGS_DE_LOW; - } - EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); - -diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index 58ccf64..afcae08 100644 ---- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -@@ -67,15 +67,15 @@ struct otm8009a { - }; - - static const struct drm_display_mode default_mode = { -- .clock = 32729, -+ .clock = 29700, - .hdisplay = 480, -- .hsync_start = 480 + 120, -- .hsync_end = 480 + 120 + 63, -- .htotal = 480 + 120 + 63 + 120, -+ .hsync_start = 480 + 98, -+ .hsync_end = 480 + 98 + 32, -+ .htotal = 480 + 98 + 32 + 98, - .vdisplay = 800, -- .vsync_start = 800 + 12, -- .vsync_end = 800 + 12 + 12, -- .vtotal = 800 + 12 + 12 + 12, -+ .vsync_start = 800 + 15, -+ .vsync_end = 800 + 15 + 10, -+ .vtotal = 800 + 15 + 10 + 14, - .vrefresh = 50, - .flags = 0, - .width_mm = 52, -@@ -257,24 +257,12 @@ static int otm8009a_init_sequence(struct otm8009a *ctx) - static int otm8009a_disable(struct drm_panel *panel) - { - struct otm8009a *ctx = panel_to_otm8009a(panel); -- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); -- int ret; - - if (!ctx->enabled) - return 0; /* This is not an issue so we return 0 here */ - - backlight_disable(ctx->bl_dev); - -- ret = mipi_dsi_dcs_set_display_off(dsi); -- if (ret) -- return ret; -- -- ret = mipi_dsi_dcs_enter_sleep_mode(dsi); -- if (ret) -- return ret; -- -- msleep(120); -- - ctx->enabled = false; - - return 0; -@@ -283,14 +271,23 @@ static int otm8009a_disable(struct drm_panel *panel) - static int otm8009a_unprepare(struct drm_panel *panel) - { - struct otm8009a *ctx = panel_to_otm8009a(panel); -+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); -+ int ret; - - if (!ctx->prepared) - return 0; - -- if (ctx->reset_gpio) { -- gpiod_set_value_cansleep(ctx->reset_gpio, 1); -- msleep(20); -- } -+ ret = mipi_dsi_dcs_set_display_off(dsi); -+ if (ret) -+ return ret; -+ -+ mdelay(10); -+ -+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); -+ if (ret) -+ return ret; -+ -+ mdelay(10); - - regulator_disable(ctx->supply); - -@@ -307,18 +304,24 @@ static int otm8009a_prepare(struct drm_panel *panel) - if (ctx->prepared) - return 0; - -+ if (ctx->reset_gpio) { -+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); -+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); -+ } -+ -+ mdelay(20); -+ - ret = regulator_enable(ctx->supply); - if (ret < 0) { - DRM_ERROR("failed to enable supply: %d\n", ret); - return ret; - } - -+ mdelay(120); -+ - if (ctx->reset_gpio) { - gpiod_set_value_cansleep(ctx->reset_gpio, 0); -- gpiod_set_value_cansleep(ctx->reset_gpio, 1); -- msleep(20); -- gpiod_set_value_cansleep(ctx->reset_gpio, 0); -- msleep(100); -+ mdelay(20); - } - - ret = otm8009a_init_sequence(ctx); -@@ -433,10 +436,22 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) - return PTR_ERR(ctx->reset_gpio); - } - -+ /* -+ * Due to a common reset between panel & touchscreen, the reset pin -+ * must be set to low level first and leave at high level at the -+ * end of probe -+ */ -+ if (ctx->reset_gpio) { -+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); -+ mdelay(1); -+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); -+ } -+ - ctx->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(ctx->supply)) { - ret = PTR_ERR(ctx->supply); -- dev_err(dev, "failed to request regulator: %d\n", ret); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to request regulator: %d\n", ret); - return ret; - } - -@@ -488,6 +503,13 @@ static int otm8009a_remove(struct mipi_dsi_device *dsi) - mipi_dsi_detach(dsi); - drm_panel_remove(&ctx->panel); - -+ if (ctx->reset_gpio) { -+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); -+ mdelay(20); -+ } -+ -+ regulator_disable(ctx->supply); -+ - return 0; - } - -diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -index 7759353..9fe15a4 100644 ---- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c -+++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -@@ -81,15 +81,15 @@ struct rm68200 { - }; - - static const struct drm_display_mode default_mode = { -- .clock = 52582, -+ .clock = 54000, - .hdisplay = 720, -- .hsync_start = 720 + 38, -- .hsync_end = 720 + 38 + 8, -- .htotal = 720 + 38 + 8 + 38, -+ .hsync_start = 720 + 48, -+ .hsync_end = 720 + 48 + 9, -+ .htotal = 720 + 48 + 9 + 48, - .vdisplay = 1280, - .vsync_start = 1280 + 12, -- .vsync_end = 1280 + 12 + 4, -- .vtotal = 1280 + 12 + 4 + 12, -+ .vsync_end = 1280 + 12 + 5, -+ .vtotal = 1280 + 12 + 5 + 12, - .vrefresh = 50, - .flags = 0, - .width_mm = 68, -@@ -265,11 +265,6 @@ static int rm68200_unprepare(struct drm_panel *panel) - - msleep(120); - -- if (ctx->reset_gpio) { -- gpiod_set_value_cansleep(ctx->reset_gpio, 1); -- msleep(20); -- } -- - regulator_disable(ctx->supply); - - ctx->prepared = false; -@@ -383,7 +378,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) - ctx->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(ctx->supply)) { - ret = PTR_ERR(ctx->supply); -- dev_err(dev, "cannot get regulator: %d\n", ret); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "cannot get regulator: %d\n", ret); - return ret; - } - -diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c -index f2021b2..f578da4 100644 ---- a/drivers/gpu/drm/stm/drv.c -+++ b/drivers/gpu/drm/stm/drv.c -@@ -10,6 +10,7 @@ - - #include - #include -+#include - - #include - #include -@@ -26,7 +27,6 @@ - - static const struct drm_mode_config_funcs drv_mode_config_funcs = { - .fb_create = drm_gem_fb_create, -- .output_poll_changed = drm_fb_helper_output_poll_changed, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, - }; -@@ -52,7 +52,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); - static struct drm_driver drv_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | - DRIVER_ATOMIC, -- .lastclose = drm_fb_helper_lastclose, - .name = "stm", - .desc = "STMicroelectronics SoC DRM", - .date = "20170330", -@@ -72,6 +71,8 @@ static struct drm_driver drv_driver = { - .gem_prime_vmap = drm_gem_cma_prime_vmap, - .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, -+ .get_scanout_position = ltdc_crtc_scanoutpos, -+ .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, - }; - - static int drv_load(struct drm_device *ddev) -@@ -108,12 +109,6 @@ static int drv_load(struct drm_device *ddev) - drm_mode_config_reset(ddev); - drm_kms_helper_poll_init(ddev); - -- if (ddev->mode_config.num_connector) { -- ret = drm_fb_cma_fbdev_init(ddev, 16, 0); -- if (ret) -- DRM_DEBUG("Warning: fails to create fbdev\n"); -- } -- - platform_set_drvdata(pdev, ddev); - - return 0; -@@ -126,12 +121,72 @@ static void drv_unload(struct drm_device *ddev) - { - DRM_DEBUG("%s\n", __func__); - -- drm_fb_cma_fbdev_fini(ddev); - drm_kms_helper_poll_fini(ddev); - ltdc_unload(ddev); - drm_mode_config_cleanup(ddev); - } - -+static __maybe_unused int drv_suspend(struct device *dev) -+{ -+ struct drm_device *ddev = dev_get_drvdata(dev); -+ struct ltdc_device *ldev = ddev->dev_private; -+ struct drm_atomic_state *state; -+ -+ WARN_ON(ldev->suspend_state); -+ -+ state = drm_atomic_helper_suspend(ddev); -+ if (IS_ERR(state)) -+ return PTR_ERR(state); -+ -+ ldev->suspend_state = state; -+ pm_runtime_force_suspend(dev); -+ -+ return 0; -+} -+ -+static __maybe_unused int drv_resume(struct device *dev) -+{ -+ struct drm_device *ddev = dev_get_drvdata(dev); -+ struct ltdc_device *ldev = ddev->dev_private; -+ int ret; -+ -+ if (WARN_ON(!ldev->suspend_state)) -+ return -ENOENT; -+ -+ pm_runtime_force_resume(dev); -+ ret = drm_atomic_helper_resume(ddev, ldev->suspend_state); -+ if (ret) -+ pm_runtime_force_suspend(dev); -+ -+ ldev->suspend_state = NULL; -+ -+ return ret; -+} -+ -+static __maybe_unused int drv_runtime_suspend(struct device *dev) -+{ -+ struct drm_device *ddev = dev_get_drvdata(dev); -+ -+ DRM_DEBUG_DRIVER("\n"); -+ ltdc_suspend(ddev); -+ -+ return 0; -+} -+ -+static __maybe_unused int drv_runtime_resume(struct device *dev) -+{ -+ struct drm_device *ddev = dev_get_drvdata(dev); -+ -+ DRM_DEBUG_DRIVER("\n"); -+ return ltdc_resume(ddev); -+} -+ -+static const struct dev_pm_ops drv_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(drv_suspend, drv_resume) -+ SET_RUNTIME_PM_OPS(drv_runtime_suspend, -+ drv_runtime_resume, NULL) -+}; -+ - static int stm_drm_platform_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -154,6 +209,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev) - if (ret) - goto err_put; - -+ drm_fbdev_generic_setup(ddev, 16); -+ - return 0; - - err_put: -@@ -187,6 +244,7 @@ static struct platform_driver stm_drm_platform_driver = { - .driver = { - .name = "stm32-display", - .of_match_table = drv_dt_ids, -+ .pm = &drv_pm_ops, - }, - }; - -diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index a514b59..44e29af 100644 ---- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -76,6 +77,7 @@ struct dw_mipi_dsi_stm { - u32 hw_version; - int lane_min_kbps; - int lane_max_kbps; -+ struct regulator *vdd_supply; - }; - - static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) -@@ -208,12 +210,26 @@ static int dw_mipi_dsi_phy_init(void *priv_data) - if (ret) - DRM_DEBUG_DRIVER("!TIMEOUT! waiting PLL, let's continue\n"); - -- /* Enable the DSI wrapper */ -- dsi_set(dsi, DSI_WCR, WCR_DSIEN); -- - return 0; - } - -+static void dw_mipi_dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags) -+{ -+ struct dw_mipi_dsi_stm *dsi = priv_data; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ /* -+ * 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 - dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, - unsigned long mode_flags, u32 lanes, u32 format, -@@ -225,7 +241,6 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, - 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) { -@@ -287,6 +302,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, - static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { - .init = dw_mipi_dsi_phy_init, - .get_lane_mbps = dw_mipi_dsi_get_lane_mbps, -+ .post_set_mode = dw_mipi_dsi_phy_post_set_mode, - }; - - static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { -@@ -304,6 +320,7 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; - struct dw_mipi_dsi_stm *dsi; -+ struct clk *pclk; - struct resource *res; - int ret; - -@@ -318,17 +335,53 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - return PTR_ERR(dsi->base); - } - -+ dsi->vdd_supply = devm_regulator_get_optional(dev, "phy-dsi"); -+ if (IS_ERR(dsi->vdd_supply)) { -+ ret = PTR_ERR(dsi->vdd_supply); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to request regulator: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_enable(dsi->vdd_supply); -+ if (ret) { -+ dev_err(dev, "failed to enable regulator: %d\n", ret); -+ return ret; -+ } -+ - dsi->pllref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(dsi->pllref_clk)) { - ret = PTR_ERR(dsi->pllref_clk); - dev_err(dev, "Unable to get pll reference clock: %d\n", ret); -- return ret; -+ goto err_clk_get; - } - - ret = clk_prepare_enable(dsi->pllref_clk); - if (ret) { - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); -- return ret; -+ goto err_clk_get; -+ } -+ -+ pclk = devm_clk_get(dev, "pclk"); -+ if (IS_ERR(pclk)) { -+ ret = PTR_ERR(pclk); -+ dev_err(dev, "Unable to get peripheral clock: %d\n", ret); -+ goto err_pclk_get; -+ } -+ -+ ret = clk_prepare_enable(pclk); -+ if (ret) { -+ dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__); -+ goto err_pclk_get; -+ } -+ -+ dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; -+ clk_disable_unprepare(pclk); -+ -+ if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) { -+ ret = -ENODEV; -+ dev_err(dev, "bad dsi hardware version\n"); -+ goto err_pclk_get; - } - - dw_mipi_dsi_stm_plat_data.base = dsi->base; -@@ -338,12 +391,21 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - - dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); - if (IS_ERR(dsi->dsi)) { -+ ret = PTR_ERR(dsi->dsi); - DRM_ERROR("Failed to initialize mipi dsi host\n"); -- clk_disable_unprepare(dsi->pllref_clk); -- return PTR_ERR(dsi->dsi); -+ goto err_pclk_get; - } - - return 0; -+ -+err_pclk_get: -+ clk_disable_unprepare(dsi->pllref_clk); -+ -+err_clk_get: -+ regulator_disable(dsi->vdd_supply); -+ -+ return ret; -+ - } - - static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) -@@ -351,17 +413,53 @@ static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) - struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev); - - clk_disable_unprepare(dsi->pllref_clk); -+ regulator_disable(dsi->vdd_supply); - dw_mipi_dsi_remove(dsi->dsi); - - return 0; - } - -+static int __maybe_unused dw_mipi_dsi_stm_suspend(struct device *dev) -+{ -+ struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ clk_disable_unprepare(dsi->pllref_clk); -+ regulator_disable(dsi->vdd_supply); -+ -+ return 0; -+} -+ -+static int __maybe_unused dw_mipi_dsi_stm_resume(struct device *dev) -+{ -+ struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data; -+ int ret; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ ret = regulator_enable(dsi->vdd_supply); -+ if (ret) { -+ DRM_ERROR("can't enable power supply\n"); -+ return ret; -+ } -+ clk_prepare_enable(dsi->pllref_clk); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops dw_mipi_dsi_stm_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(dw_mipi_dsi_stm_suspend, -+ dw_mipi_dsi_stm_resume) -+}; -+ - static struct platform_driver dw_mipi_dsi_stm_driver = { - .probe = dw_mipi_dsi_stm_probe, - .remove = dw_mipi_dsi_stm_remove, - .driver = { - .of_match_table = dw_mipi_dsi_stm_dt_ids, - .name = "stm32-display-dsi", -+ .pm = &dw_mipi_dsi_stm_pm_ops, - }, - }; - -diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 477d0a2..013b9f9 100644 ---- a/drivers/gpu/drm/stm/ltdc.c -+++ b/drivers/gpu/drm/stm/ltdc.c -@@ -12,6 +12,8 @@ - #include - #include - #include -+#include -+#include - #include - - #include -@@ -149,6 +151,8 @@ - #define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ - #define IER_RRIE BIT(3) /* Register Reload Interrupt enable */ - -+#define CPSR_CYPOS GENMASK(15, 0) /* Current Y position */ -+ - #define ISR_LIF BIT(0) /* Line Interrupt Flag */ - #define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ - #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ -@@ -421,9 +425,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, - /* Immediately commit the planes */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); - -- /* Enable LTDC */ -- reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); -- - drm_crtc_vblank_on(crtc); - } - -@@ -431,19 +432,19 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) - { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); -+ struct drm_device *ddev = crtc->dev; - - DRM_DEBUG_DRIVER("\n"); - - drm_crtc_vblank_off(crtc); - -- /* disable LTDC */ -- reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); -- - /* disable IRQ */ - reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); - - /* immediately commit disable of layers before switching off LTDC */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); -+ -+ pm_runtime_put_sync(ddev->dev); - } - - #define CLK_TOLERANCE_HZ 50 -@@ -492,33 +493,55 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode) - { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); -+ struct drm_device *ddev = crtc->dev; - int rate = mode->clock * 1000; -+ bool runtime_active; -+ int ret; - -- /* -- * TODO clk_round_rate() does not work yet. When ready, it can -- * be used instead of clk_set_rate() then clk_get_rate(). -- */ -+ runtime_active = pm_runtime_active(ddev->dev); -+ -+ if (runtime_active) -+ pm_runtime_put_sync(ddev->dev); - -- clk_disable(ldev->pixel_clk); - if (clk_set_rate(ldev->pixel_clk, rate) < 0) { - DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); - return false; - } -- clk_enable(ldev->pixel_clk); - - adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000; - -+ if (runtime_active) { -+ ret = pm_runtime_get_sync(ddev->dev); -+ if (ret) { -+ DRM_ERROR("Failed to fixup mode, cannot get sync\n"); -+ return false; -+ } -+ } -+ -+ DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n", -+ mode->clock, adjusted_mode->clock); -+ - return true; - } - - static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - { - struct ltdc_device *ldev = crtc_to_ltdc(crtc); -+ struct drm_device *ddev = crtc->dev; - struct drm_display_mode *mode = &crtc->state->adjusted_mode; - struct videomode vm; - u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; - u32 total_width, total_height; - u32 val; -+ int ret; -+ -+ if (!pm_runtime_active(ddev->dev)) { -+ ret = pm_runtime_get_sync(ddev->dev); -+ if (ret) { -+ DRM_ERROR("Failed to set mode, cannot get sync\n"); -+ return; -+ } -+ } - - drm_display_mode_to_videomode(mode, &vm); - -@@ -547,10 +570,10 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) - if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) - val |= GCR_VSPOL; - -- if (vm.flags & DISPLAY_FLAGS_DE_HIGH) -+ if (vm.flags & DISPLAY_FLAGS_DE_LOW) - val |= GCR_DEPOL; - -- if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) -+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) - val |= GCR_PCPOL; - - reg_update_bits(ldev->regs, LTDC_GCR, -@@ -627,6 +650,53 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) - reg_clear(ldev->regs, LTDC_IER, IER_LIE); - } - -+bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe, -+ bool in_vblank_irq, int *vpos, int *hpos, -+ ktime_t *stime, ktime_t *etime, -+ const struct drm_display_mode *mode) -+{ -+ struct ltdc_device *ldev = ddev->dev_private; -+ int line, vactive_start, vactive_end, vtotal; -+ -+ if (stime) -+ *stime = ktime_get(); -+ -+ /* The active area starts after vsync + front porch and ends -+ * at vsync + front porc + display size. -+ * The total height also include back porch. -+ * We have 3 possible cases to handle: -+ * - line < vactive_start: vpos = line - vactive_start and will be -+ * negative -+ * - vactive_start < line < vactive_end: vpos = line - vactive_start -+ * and will be positive -+ * - line > vactive_end: vpos = line - vtotal - vactive_start -+ * and will negative -+ * -+ * Computation for the two first cases are identical so we can -+ * simplify the code and only test if line > vactive_end -+ */ -+ if (pm_runtime_active(ddev->dev)) { -+ line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; -+ vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; -+ vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; -+ vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; -+ -+ if (line > vactive_end) -+ *vpos = line - vtotal - vactive_start; -+ else -+ *vpos = line - vactive_start; -+ } else { -+ *vpos = 0; -+ } -+ -+ *hpos = 0; -+ -+ if (etime) -+ *etime = ktime_get(); -+ -+ return true; -+} -+ - static const struct drm_crtc_funcs ltdc_crtc_funcs = { - .destroy = drm_crtc_cleanup, - .set_config = drm_atomic_helper_set_config, -@@ -647,24 +717,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) - { - struct drm_framebuffer *fb = state->fb; -- u32 src_x, src_y, src_w, src_h; -+ struct drm_crtc_state *crtc_state; -+ struct drm_rect *src = &state->src; -+ struct drm_rect *dst = &state->dst; - - DRM_DEBUG_DRIVER("\n"); - - if (!fb) - return 0; - -- /* convert src_ from 16:16 format */ -- src_x = state->src_x >> 16; -- src_y = state->src_y >> 16; -- src_w = state->src_w >> 16; -- src_h = state->src_h >> 16; -+ /* convert src from 16:16 format */ -+ src->x1 = state->src_x >> 16; -+ src->y1 = state->src_y >> 16; -+ src->x2 = (state->src_w >> 16) + src->x1 - 1; -+ src->y2 = (state->src_h >> 16) + src->y1 - 1; -+ -+ dst->x1 = state->crtc_x; -+ dst->y1 = state->crtc_y; -+ dst->x2 = state->crtc_w + dst->x1 - 1; -+ dst->y2 = state->crtc_h + dst->y1 - 1; - -- /* Reject scaling */ -- if (src_w != state->crtc_w || src_h != state->crtc_h) { -- DRM_ERROR("Scaling is not supported"); -+ DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", -+ plane->base.id, fb->base.id, -+ src->x2 - src->x1 + 1, src->y2 - src->y1 + 1, -+ src->x1, src->y1, -+ dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1, -+ dst->x1, dst->y1); -+ -+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, -+ state->crtc); -+ /* destination coordinates do not have to exceed display sizes */ -+ if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || -+ crtc_state->mode.vdisplay <= dst->y2)) -+ return -EINVAL; -+ -+ /* source sizes do not have to exceed destination sizes */ -+ if (dst->x2 - dst->x1 < src->x2 - src->x1 || -+ dst->y2 - dst->y1 < src->y2 - src->y1) - return -EINVAL; -- } - - return 0; - } -@@ -674,44 +764,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - { - struct ltdc_device *ldev = plane_to_ltdc(plane); - struct drm_plane_state *state = plane->state; -+ struct drm_rect *src = &state->src; -+ struct drm_rect *dst = &state->dst; - struct drm_framebuffer *fb = state->fb; - u32 lofs = plane->index * LAY_OFS; -- u32 x0 = state->crtc_x; -- u32 x1 = state->crtc_x + state->crtc_w - 1; -- u32 y0 = state->crtc_y; -- u32 y1 = state->crtc_y + state->crtc_h - 1; -- u32 src_x, src_y, src_w, src_h; - u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; - enum ltdc_pix_fmt pf; -+ struct drm_rect dr; - - if (!state->crtc || !fb) { - DRM_DEBUG_DRIVER("fb or crtc NULL"); - return; - } - -- /* convert src_ from 16:16 format */ -- src_x = state->src_x >> 16; -- src_y = state->src_y >> 16; -- src_w = state->src_w >> 16; -- src_h = state->src_h >> 16; -- -- DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", -- plane->base.id, fb->base.id, -- src_w, src_h, src_x, src_y, -- state->crtc_w, state->crtc_h, -- state->crtc_x, state->crtc_y); -+ /* compute final coordinates of frame buffer */ -+ dr.x1 = src->x1 + dst->x1; -+ dr.y1 = src->y1 + dst->y1; -+ dr.x2 = src->x2 + dst->x1; -+ dr.y2 = src->y2 + dst->y1; - - bpcr = reg_read(ldev->regs, LTDC_BPCR); - ahbp = (bpcr & BPCR_AHBP) >> 16; - avbp = bpcr & BPCR_AVBP; - - /* Configures the horizontal start and stop position */ -- val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); -+ val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp); - reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, - LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); - - /* Configures the vertical start and stop position */ -- val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); -+ val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp); - reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, - LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); - -@@ -731,7 +813,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - /* Configures the color frame buffer pitch in bytes & line length */ - pitch_in_bytes = fb->pitches[0]; - line_length = drm_format_plane_cpp(fb->format->format, 0) * -- (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; -+ (dr.x2 - dr.x1 + 1) + (ldev->caps.bus_width >> 3) - 1; - val = ((pitch_in_bytes << 16) | line_length); - reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, - LXCFBLR_CFBLL | LXCFBLR_CFBP, val); -@@ -754,7 +836,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - LXBFCR_BF2 | LXBFCR_BF1, val); - - /* Configures the frame buffer line number */ -- val = y1 - y0 + 1; -+ val = dr.y2 - dr.y1 + 1; - reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); - - /* Sets the FB address */ -@@ -773,11 +855,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, - - mutex_lock(&ldev->err_lock); - if (ldev->error_status & ISR_FUIF) { -- DRM_DEBUG_DRIVER("Fifo underrun\n"); -+ DRM_WARN("ltdc fifo underrun: please verify display mode\n"); - ldev->error_status &= ~ISR_FUIF; - } - if (ldev->error_status & ISR_TERRIF) { -- DRM_DEBUG_DRIVER("Transfer error\n"); -+ DRM_WARN("ltdc transfer error\n"); - ldev->error_status &= ~ISR_TERRIF; - } - mutex_unlock(&ldev->err_lock); -@@ -815,6 +897,13 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, - fpsi->counter = 0; - } - -+static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, -+ u32 format, -+ u64 modifier) -+{ -+ return modifier == DRM_FORMAT_MOD_LINEAR; -+} -+ - static const struct drm_plane_funcs ltdc_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, -@@ -823,6 +912,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, - .atomic_print_state = ltdc_plane_atomic_print_state, -+ .format_mod_supported = ltdc_plane_format_mod_supported, - }; - - static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { -@@ -843,6 +933,10 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, - u32 formats[NB_PF * 2]; - u32 drm_fmt, drm_fmt_no_alpha; - int ret; -+ const u64 modifiers[] = { -+ DRM_FORMAT_MOD_LINEAR, -+ DRM_FORMAT_MOD_INVALID -+ }; - - /* Get supported pixel formats */ - for (i = 0; i < NB_PF; i++) { -@@ -870,7 +964,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, - - ret = drm_universal_plane_init(ddev, plane, possible_crtcs, - <dc_plane_funcs, formats, nb_fmt, -- NULL, type, NULL); -+ modifiers, type, NULL); - if (ret < 0) - return NULL; - -@@ -942,6 +1036,54 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = { - .destroy = drm_encoder_cleanup, - }; - -+static void ltdc_encoder_disable(struct drm_encoder *encoder) -+{ -+ struct drm_device *ddev = encoder->dev; -+ struct ltdc_device *ldev = ddev->dev_private; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ /* Disable LTDC */ -+ reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); -+ -+ /* Set to sleep state the pinctrl whatever type of encoder */ -+ pinctrl_pm_select_sleep_state(ddev->dev); -+} -+ -+static void ltdc_encoder_enable(struct drm_encoder *encoder) -+{ -+ struct drm_device *ddev = encoder->dev; -+ struct ltdc_device *ldev = ddev->dev_private; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ /* Enable LTDC */ -+ reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); -+} -+ -+static void ltdc_encoder_mode_set(struct drm_encoder *encoder, -+ struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct drm_device *ddev = encoder->dev; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ /* -+ * Set to default state the pinctrl only with DPI type. -+ * Others types like DSI, don't need pinctrl due to -+ * internal bridge (the signals do not come out of the chipset). -+ */ -+ if (encoder->encoder_type == DRM_MODE_ENCODER_DPI) -+ pinctrl_pm_select_default_state(ddev->dev); -+} -+ -+static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = { -+ .disable = ltdc_encoder_disable, -+ .enable = ltdc_encoder_enable, -+ .mode_set = ltdc_encoder_mode_set, -+}; -+ - static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) - { - struct drm_encoder *encoder; -@@ -957,6 +1099,8 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) - drm_encoder_init(ddev, encoder, <dc_encoder_funcs, - DRM_MODE_ENCODER_DPI, NULL); - -+ drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs); -+ - ret = drm_bridge_attach(encoder, bridge, NULL); - if (ret) { - drm_encoder_cleanup(encoder); -@@ -1014,6 +1158,30 @@ static int ltdc_get_caps(struct drm_device *ddev) - return 0; - } - -+void ltdc_suspend(struct drm_device *ddev) -+{ -+ struct ltdc_device *ldev = ddev->dev_private; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ clk_disable_unprepare(ldev->pixel_clk); -+} -+ -+int ltdc_resume(struct drm_device *ddev) -+{ -+ struct ltdc_device *ldev = ddev->dev_private; -+ int ret; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ ret = clk_prepare_enable(ldev->pixel_clk); -+ if (ret) { -+ DRM_ERROR("failed to enable pixel clock (%d)\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ - int ltdc_load(struct drm_device *ddev) - { - struct platform_device *pdev = to_platform_device(ddev->dev); -@@ -1053,8 +1221,9 @@ int ltdc_load(struct drm_device *ddev) - - ldev->pixel_clk = devm_clk_get(dev, "lcd"); - if (IS_ERR(ldev->pixel_clk)) { -- DRM_ERROR("Unable to get lcd clock\n"); -- return -ENODEV; -+ if (PTR_ERR(ldev->pixel_clk) != -EPROBE_DEFER) -+ DRM_ERROR("Unable to get lcd clock\n"); -+ return PTR_ERR(ldev->pixel_clk); - } - - if (clk_prepare_enable(ldev->pixel_clk)) { -@@ -1072,6 +1241,9 @@ int ltdc_load(struct drm_device *ddev) - - for (i = 0; i < MAX_IRQ; i++) { - irq = platform_get_irq(pdev, i); -+ if (irq == -EPROBE_DEFER) -+ goto err; -+ - if (irq < 0) - continue; - -@@ -1131,6 +1303,8 @@ int ltdc_load(struct drm_device *ddev) - goto err; - } - -+ ddev->mode_config.allow_fb_modifiers = true; -+ - ret = ltdc_crtc_init(ddev, crtc); - if (ret) { - DRM_ERROR("Failed to init crtc\n"); -@@ -1146,8 +1320,13 @@ int ltdc_load(struct drm_device *ddev) - /* Allow usage of vblank without having to call drm_irq_install */ - ddev->irq_enabled = 1; - -- return 0; -+ clk_disable_unprepare(ldev->pixel_clk); -+ -+ pinctrl_pm_select_sleep_state(ddev->dev); -+ -+ pm_runtime_enable(ddev->dev); - -+ return 0; - err: - for (i = 0; i < MAX_ENDPOINTS; i++) - drm_panel_bridge_remove(bridge[i]); -@@ -1159,7 +1338,6 @@ int ltdc_load(struct drm_device *ddev) - - void ltdc_unload(struct drm_device *ddev) - { -- struct ltdc_device *ldev = ddev->dev_private; - int i; - - DRM_DEBUG_DRIVER("\n"); -@@ -1167,7 +1345,7 @@ void ltdc_unload(struct drm_device *ddev) - for (i = 0; i < MAX_ENDPOINTS; i++) - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); - -- clk_disable_unprepare(ldev->pixel_clk); -+ pm_runtime_disable(ddev->dev); - } - - MODULE_AUTHOR("Philippe Cornu "); -diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h -index d5afb89..9b410c6 100644 ---- a/drivers/gpu/drm/stm/ltdc.h -+++ b/drivers/gpu/drm/stm/ltdc.h -@@ -36,9 +36,16 @@ struct ltdc_device { - u32 error_status; - u32 irq_status; - struct fps_info plane_fpsi[LTDC_MAX_LAYER]; -+ struct drm_atomic_state *suspend_state; - }; - -+bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, -+ bool in_vblank_irq, int *vpos, int *hpos, -+ ktime_t *stime, ktime_t *etime, -+ const struct drm_display_mode *mode); - int ltdc_load(struct drm_device *ddev); - void ltdc_unload(struct drm_device *ddev); -+void ltdc_suspend(struct drm_device *ddev); -+int ltdc_resume(struct drm_device *ddev); - - #endif -diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h -index d9c6d54..0fdc550 100644 ---- a/include/drm/bridge/dw_mipi_dsi.h -+++ b/include/drm/bridge/dw_mipi_dsi.h -@@ -17,6 +17,7 @@ struct dw_mipi_dsi_phy_ops { - int (*get_lane_mbps)(void *priv_data, struct drm_display_mode *mode, - unsigned long mode_flags, u32 lanes, u32 format, - unsigned int *lane_mbps); -+ void (*post_set_mode)(void *priv_data, unsigned long mode_flags); - }; - - struct dw_mipi_dsi_plat_data { -diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h -index 8d67243..c20c4c3 100644 ---- a/include/uapi/drm/drm_mode.h -+++ b/include/uapi/drm/drm_mode.h -@@ -89,6 +89,12 @@ extern "C" { - #define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) - #define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) - -+/* flags for polarity clock & data enable polarities */ -+#define DRM_MODE_FLAG_PPIXDATA (1 << 19) -+#define DRM_MODE_FLAG_NPIXDATA (1 << 20) -+#define DRM_MODE_FLAG_PDE (1 << 21) -+#define DRM_MODE_FLAG_NDE (1 << 22) -+ - /* Picture aspect ratio options */ - #define DRM_MODE_PICTURE_ASPECT_NONE 0 - #define DRM_MODE_PICTURE_ASPECT_4_3 1 --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch deleted file mode 100644 index d0e5686..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch +++ /dev/null @@ -1,203 +0,0 @@ -From 7aa67bec68104aebb6a182e12cbfd62dfa81a5d3 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:40 +0100 -Subject: [PATCH 08/31] ARM stm32mp1 r3 GPIO - ---- - drivers/gpio/gpiolib-of.c | 5 +++++ - drivers/gpio/gpiolib.c | 50 ++++++++++++++++++++++++++++------------- - drivers/gpio/gpiolib.h | 2 ++ - include/dt-bindings/gpio/gpio.h | 6 +++++ - include/linux/gpio/machine.h | 2 ++ - include/linux/of_gpio.h | 2 ++ - 6 files changed, 51 insertions(+), 16 deletions(-) - -diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c -index e0f149b..a8cba78 100644 ---- a/drivers/gpio/gpiolib-of.c -+++ b/drivers/gpio/gpiolib-of.c -@@ -281,6 +281,11 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - if (of_flags & OF_GPIO_TRANSITORY) - *flags |= GPIO_TRANSITORY; - -+ if (of_flags & OF_GPIO_PULL_UP) -+ *flags |= GPIO_PULL_UP; -+ if (of_flags & OF_GPIO_PULL_DOWN) -+ *flags |= GPIO_PULL_DOWN; -+ - return desc; - } - -diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index a24f13d..aa750f9 100644 ---- a/drivers/gpio/gpiolib.c -+++ b/drivers/gpio/gpiolib.c -@@ -2537,6 +2537,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); - * rely on gpio_request() having been called beforehand. - */ - -+static int gpio_set_config(struct gpio_chip *gc, unsigned offset, -+ enum pin_config_param mode) -+{ -+ unsigned long config = { PIN_CONF_PACKED(mode, 0) }; -+ -+ return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; -+} -+ - /** - * gpiod_direction_input - set the GPIO direction to input - * @desc: GPIO to set to input -@@ -2573,20 +2581,19 @@ int gpiod_direction_input(struct gpio_desc *desc) - if (status == 0) - clear_bit(FLAG_IS_OUT, &desc->flags); - -+ if (test_bit(FLAG_PULL_UP, &desc->flags)) -+ gpio_set_config(chip, gpio_chip_hwgpio(desc), -+ PIN_CONFIG_BIAS_PULL_UP); -+ else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) -+ gpio_set_config(chip, gpio_chip_hwgpio(desc), -+ PIN_CONFIG_BIAS_PULL_DOWN); -+ - trace_gpio_direction(desc_to_gpio(desc), 1, status); - - return status; - } - EXPORT_SYMBOL_GPL(gpiod_direction_input); - --static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset, -- enum pin_config_param mode) --{ -- unsigned long config = { PIN_CONF_PACKED(mode, 0) }; -- -- return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; --} -- - static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) - { - struct gpio_chip *gc = desc->gdev->chip; -@@ -2672,8 +2679,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) - gc = desc->gdev->chip; - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { - /* First see if we can enable open drain in hardware */ -- ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), -- PIN_CONFIG_DRIVE_OPEN_DRAIN); -+ ret = gpio_set_config(gc, gpio_chip_hwgpio(desc), -+ PIN_CONFIG_DRIVE_OPEN_DRAIN); - if (!ret) - goto set_output_value; - /* Emulate open drain by not actively driving the line high */ -@@ -2683,8 +2690,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) - } - } - else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { -- ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), -- PIN_CONFIG_DRIVE_OPEN_SOURCE); -+ ret = gpio_set_config(gc, gpio_chip_hwgpio(desc), -+ PIN_CONFIG_DRIVE_OPEN_SOURCE); - if (!ret) - goto set_output_value; - /* Emulate open source by not actively driving the line low */ -@@ -2693,8 +2700,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) - goto set_output_flag; - } - } else { -- gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), -- PIN_CONFIG_DRIVE_PUSH_PULL); -+ gpio_set_config(gc, gpio_chip_hwgpio(desc), -+ PIN_CONFIG_DRIVE_PUSH_PULL); - } - - set_output_value: -@@ -2737,7 +2744,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) - } - - config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); -- return chip->set_config(chip, gpio_chip_hwgpio(desc), config); -+ return gpio_set_config(chip, gpio_chip_hwgpio(desc), config); - } - EXPORT_SYMBOL_GPL(gpiod_set_debounce); - -@@ -2774,7 +2781,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) - packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, - !transitory); - gpio = gpio_chip_hwgpio(desc); -- rc = chip->set_config(chip, gpio, packed); -+ rc = gpio_set_config(chip, gpio, packed); - if (rc == -ENOTSUPP) { - dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", - gpio); -@@ -3908,6 +3915,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, - if (lflags & GPIO_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); - -+ if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) { -+ gpiod_err(desc, -+ "both pull-up and pull-down enabled, invalid configuration\n"); -+ return -EINVAL; -+ } -+ -+ if (lflags & GPIO_PULL_UP) -+ set_bit(FLAG_PULL_UP, &desc->flags); -+ else if (lflags & GPIO_PULL_DOWN) -+ set_bit(FLAG_PULL_DOWN, &desc->flags); -+ - status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); - if (status < 0) - return status; -diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h -index a7e49fef..34d2650 100644 ---- a/drivers/gpio/gpiolib.h -+++ b/drivers/gpio/gpiolib.h -@@ -216,6 +216,8 @@ struct gpio_desc { - #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ - #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ - #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ -+#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ -+#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ - - /* Connection label */ - const char *label; -diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h -index 2cc10ae..c029467 100644 ---- a/include/dt-bindings/gpio/gpio.h -+++ b/include/dt-bindings/gpio/gpio.h -@@ -33,4 +33,10 @@ - #define GPIO_PERSISTENT 0 - #define GPIO_TRANSITORY 8 - -+/* Bit 4 express pull up */ -+#define GPIO_PULL_UP 16 -+ -+/* Bit 5 express pull down */ -+#define GPIO_PULL_DOWN 32 -+ - #endif -diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h -index daa44ea..69673be 100644 ---- a/include/linux/gpio/machine.h -+++ b/include/linux/gpio/machine.h -@@ -12,6 +12,8 @@ enum gpio_lookup_flags { - GPIO_OPEN_SOURCE = (1 << 2), - GPIO_PERSISTENT = (0 << 3), - GPIO_TRANSITORY = (1 << 3), -+ GPIO_PULL_UP = (1 << 4), -+ GPIO_PULL_DOWN = (1 << 5), - }; - - /** -diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h -index 163b79e..f9737de 100644 ---- a/include/linux/of_gpio.h -+++ b/include/linux/of_gpio.h -@@ -28,6 +28,8 @@ enum of_gpio_flags { - OF_GPIO_SINGLE_ENDED = 0x2, - OF_GPIO_OPEN_DRAIN = 0x4, - OF_GPIO_TRANSITORY = 0x8, -+ OF_GPIO_PULL_UP = 0x10, -+ OF_GPIO_PULL_DOWN = 0x20, - }; - - #ifdef CONFIG_OF_GPIO --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch deleted file mode 100644 index 5f226fe..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch +++ /dev/null @@ -1,249 +0,0 @@ -From da8d8b897bc61f58b87237394c4a9ff4f89e906d Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:40 +0100 -Subject: [PATCH 09/31] ARM stm32mp1 r3 HWSPINLOCK - ---- - drivers/hwspinlock/Kconfig | 9 ++ - drivers/hwspinlock/Makefile | 1 + - drivers/hwspinlock/hwspinlock_core.c | 15 ++-- - drivers/hwspinlock/stm32_hwspinlock.c | 164 ++++++++++++++++++++++++++++++++++ - 4 files changed, 182 insertions(+), 7 deletions(-) - create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c - -diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig -index e895d29..7869c67 100644 ---- a/drivers/hwspinlock/Kconfig -+++ b/drivers/hwspinlock/Kconfig -@@ -49,6 +49,15 @@ config HWSPINLOCK_SPRD - - If unsure, say N. - -+config HWSPINLOCK_STM32 -+ tristate "STM32 Hardware Spinlock device" -+ depends on MACH_STM32MP157 -+ depends on HWSPINLOCK -+ help -+ Say y here to support the STM32 Hardware Spinlock device. -+ -+ If unsure, say N. -+ - config HSEM_U8500 - tristate "STE Hardware Semaphore functionality" - depends on HWSPINLOCK -diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile -index b87c01a..ed053e3 100644 ---- a/drivers/hwspinlock/Makefile -+++ b/drivers/hwspinlock/Makefile -@@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o - obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o - obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o - obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o -+obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o - obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o -diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c -index 2bad40d..287e1b3 100644 ---- a/drivers/hwspinlock/hwspinlock_core.c -+++ b/drivers/hwspinlock/hwspinlock_core.c -@@ -333,6 +333,9 @@ int of_hwspin_lock_get_id(struct device_node *np, int index) - if (ret) - return ret; - -+ if (!of_device_is_available(args.np)) -+ return -ENOENT; -+ - /* Find the hwspinlock device: we need its base_id */ - ret = -EPROBE_DEFER; - rcu_read_lock(); -@@ -742,13 +745,11 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) - /* sanity check (this shouldn't happen) */ - WARN_ON(hwlock_to_id(hwlock) != id); - -- /* make sure this hwspinlock is unused */ -- ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); -- if (ret == 0) { -- pr_warn("hwspinlock %u is already in use\n", id); -- hwlock = NULL; -- goto out; -- } -+ /* -+ * We intentionally do not check for the HWSPINLOCK_UNUSED tag as -+ * we want to share HWSPINLOCK between several devices. This is safe -+ * since the lock/unlock requests are called under &hwlock->lock control -+ */ - - /* mark as used and power up */ - ret = __hwspin_lock_request(hwlock); -diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c -new file mode 100644 -index 0000000..b9b9b99 ---- /dev/null -+++ b/drivers/hwspinlock/stm32_hwspinlock.c -@@ -0,0 +1,164 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics SA 2018 -+ * Author: Benjamin Gaignard for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "hwspinlock_internal.h" -+ -+#define STM32_MUTEX_COREID BIT(8) -+#define STM32_MUTEX_LOCK_BIT BIT(31) -+#define STM32_MUTEX_NUM_LOCKS 32 -+ -+struct stm32_hwspinlock { -+ struct clk *clk; -+ struct hwspinlock_device bank; -+}; -+ -+static int stm32_hwspinlock_trylock(struct hwspinlock *lock) -+{ -+ void __iomem *lock_addr = lock->priv; -+ u32 status; -+ -+ writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, lock_addr); -+ status = readl(lock_addr); -+ -+ return status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID); -+} -+ -+static void stm32_hwspinlock_unlock(struct hwspinlock *lock) -+{ -+ void __iomem *lock_addr = lock->priv; -+ -+ writel(STM32_MUTEX_COREID, lock_addr); -+} -+ -+static void stm32_hwspinlock_relax(struct hwspinlock *lock) -+{ -+ ndelay(50); -+} -+ -+static const struct hwspinlock_ops stm32_hwspinlock_ops = { -+ .trylock = stm32_hwspinlock_trylock, -+ .unlock = stm32_hwspinlock_unlock, -+ .relax = stm32_hwspinlock_relax, -+}; -+ -+static int stm32_hwspinlock_probe(struct platform_device *pdev) -+{ -+ struct stm32_hwspinlock *hw; -+ void __iomem *io_base; -+ struct resource *res; -+ size_t array_size; -+ int i, ret; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ io_base = devm_ioremap_resource(&pdev->dev, res); -+ if (!io_base) -+ return -ENOMEM; -+ -+ array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); -+ hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL); -+ if (!hw) -+ return -ENOMEM; -+ -+ hw->clk = devm_clk_get(&pdev->dev, "hsem"); -+ if (IS_ERR(hw->clk)) -+ return PTR_ERR(hw->clk); -+ -+ for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++) -+ hw->bank.lock[i].priv = io_base + i * sizeof(u32); -+ -+ platform_set_drvdata(pdev, hw); -+ pm_runtime_enable(&pdev->dev); -+ -+ ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops, -+ 0, STM32_MUTEX_NUM_LOCKS); -+ -+ if (ret) -+ pm_runtime_disable(&pdev->dev); -+ -+ return ret; -+} -+ -+static int stm32_hwspinlock_remove(struct platform_device *pdev) -+{ -+ struct stm32_hwspinlock *hw = platform_get_drvdata(pdev); -+ int ret; -+ -+ ret = hwspin_lock_unregister(&hw->bank); -+ if (ret) -+ dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); -+ -+ pm_runtime_disable(&pdev->dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev) -+{ -+ struct stm32_hwspinlock *hw = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(hw->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_hwspinlock_runtime_resume(struct device *dev) -+{ -+ struct stm32_hwspinlock *hw = dev_get_drvdata(dev); -+ -+ clk_prepare_enable(hw->clk); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops stm32_hwspinlock_pm_ops = { -+ SET_RUNTIME_PM_OPS(stm32_hwspinlock_runtime_suspend, -+ stm32_hwspinlock_runtime_resume, -+ NULL) -+}; -+ -+static const struct of_device_id stm32_hwpinlock_ids[] = { -+ { .compatible = "st,stm32-hwspinlock", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids); -+ -+static struct platform_driver stm32_hwspinlock_driver = { -+ .probe = stm32_hwspinlock_probe, -+ .remove = stm32_hwspinlock_remove, -+ .driver = { -+ .name = "stm32_hwspinlock", -+ .of_match_table = stm32_hwpinlock_ids, -+ .pm = &stm32_hwspinlock_pm_ops, -+ }, -+}; -+ -+static int __init stm32_hwspinlock_init(void) -+{ -+ return platform_driver_register(&stm32_hwspinlock_driver); -+} -+ -+/* board init code might need to reserve hwspinlocks for predefined purposes */ -+postcore_initcall(stm32_hwspinlock_init); -+ -+static void __exit stm32_hwspinlock_exit(void) -+{ -+ platform_driver_unregister(&stm32_hwspinlock_driver); -+} -+module_exit(stm32_hwspinlock_exit); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("Hardware spinlock driver for STM32 SoCs"); -+MODULE_AUTHOR("Benjamin Gaignard "); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch deleted file mode 100644 index d58bde2..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch +++ /dev/null @@ -1,1500 +0,0 @@ -From 4091e5a5278a8434585a9a3ab578d8920f41351c Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:40 +0100 -Subject: [PATCH 10/31] ARM stm32mp1 r3 HWTRACING I2C - ---- - drivers/hwtracing/coresight/coresight-stm.c | 58 +- - drivers/i2c/busses/Kconfig | 1 + - drivers/i2c/busses/i2c-stm32f7.c | 834 ++++++++++++++++++++++++---- - 3 files changed, 774 insertions(+), 119 deletions(-) - -diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c -index c46c70a..65687c0 100644 ---- a/drivers/hwtracing/coresight/coresight-stm.c -+++ b/drivers/hwtracing/coresight/coresight-stm.c -@@ -40,6 +40,7 @@ - #define STMHETER 0xd20 - #define STMHEBSR 0xd60 - #define STMHEMCR 0xd64 -+#define STMHEEXTMUXR 0xd68 - #define STMHEMASTR 0xdf4 - #define STMHEFEAT1R 0xdf8 - #define STMHEIDR 0xdfc -@@ -125,9 +126,11 @@ struct channel_space { - * @stmheer: settings for register STMHEER. - * @stmheter: settings for register STMHETER. - * @stmhebsr: settings for register STMHEBSR. -+ * @stmheextmuxr: settings for register STMHEEXTMUXR. - */ - struct stm_drvdata { - void __iomem *base; -+ void __iomem *base_cti; - struct device *dev; - struct clk *atclk; - struct coresight_device *csdev; -@@ -143,6 +146,7 @@ struct stm_drvdata { - u32 stmheer; - u32 stmheter; - u32 stmhebsr; -+ u32 stmheextmuxr; - }; - - static void stm_hwevent_enable_hw(struct stm_drvdata *drvdata) -@@ -152,6 +156,7 @@ static void stm_hwevent_enable_hw(struct stm_drvdata *drvdata) - writel_relaxed(drvdata->stmhebsr, drvdata->base + STMHEBSR); - writel_relaxed(drvdata->stmheter, drvdata->base + STMHETER); - writel_relaxed(drvdata->stmheer, drvdata->base + STMHEER); -+ writel_relaxed(drvdata->stmheextmuxr, drvdata->base + STMHEEXTMUXR); - writel_relaxed(0x01 | /* Enable HW event tracing */ - 0x04, /* Error detection on event tracing */ - drvdata->base + STMHEMCR); -@@ -222,6 +227,7 @@ static void stm_hwevent_disable_hw(struct stm_drvdata *drvdata) - writel_relaxed(0x0, drvdata->base + STMHEMCR); - writel_relaxed(0x0, drvdata->base + STMHEER); - writel_relaxed(0x0, drvdata->base + STMHETER); -+ writel_relaxed(0x0, drvdata->base + STMHEEXTMUXR); - - CS_LOCK(drvdata->base); - } -@@ -455,6 +461,34 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, - return size; - } - -+static ssize_t hwevent_extmux_select_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); -+ unsigned long val = drvdata->stmheextmuxr; -+ -+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); -+} -+ -+static ssize_t hwevent_extmux_select_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); -+ unsigned long val; -+ int ret = 0; -+ -+ ret = kstrtoul(buf, 16, &val); -+ if (ret) -+ return -EINVAL; -+ -+ drvdata->stmheextmuxr = val; -+ -+ return size; -+} -+static DEVICE_ATTR_RW(hwevent_extmux_select); -+ - static ssize_t hwevent_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) - { -@@ -644,10 +678,16 @@ coresight_stm_reg(spfeat1r, STMSPFEAT1R); - coresight_stm_reg(spfeat2r, STMSPFEAT2R); - coresight_stm_reg(spfeat3r, STMSPFEAT3R); - coresight_stm_reg(devid, CORESIGHT_DEVID); -+coresight_stm_reg(stmheer, STMHEER); -+coresight_stm_reg(stmheter, STMHETER); -+coresight_stm_reg(stmhebsr, STMHEBSR); -+coresight_stm_reg(stmheextmux, STMHEEXTMUXR); -+coresight_stm_reg(stmhemcr, STMHEMCR); - - static struct attribute *coresight_stm_attrs[] = { - &dev_attr_hwevent_enable.attr, - &dev_attr_hwevent_select.attr, -+ &dev_attr_hwevent_extmux_select.attr, - &dev_attr_port_enable.attr, - &dev_attr_port_select.attr, - &dev_attr_traceid.attr, -@@ -667,6 +707,11 @@ static struct attribute *coresight_stm_mgmt_attrs[] = { - &dev_attr_spfeat2r.attr, - &dev_attr_spfeat3r.attr, - &dev_attr_devid.attr, -+ &dev_attr_stmheer.attr, -+ &dev_attr_stmheter.attr, -+ &dev_attr_stmhebsr.attr, -+ &dev_attr_stmheextmux.attr, -+ &dev_attr_stmhemcr.attr, - NULL, - }; - -@@ -792,7 +837,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) - struct coresight_platform_data *pdata = NULL; - struct stm_drvdata *drvdata; - struct resource *res = &adev->res; -- struct resource ch_res; -+ struct resource ch_res, cti_res; - size_t res_size, bitmap_size; - struct coresight_desc desc = { 0 }; - struct device_node *np = adev->dev.of_node; -@@ -821,6 +866,17 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) - return PTR_ERR(base); - drvdata->base = base; - -+ ret = stm_get_resource_byname(np, "cti-base", &cti_res); -+ if (ret) -+ return ret; -+ -+ base = devm_ioremap_resource(dev, &cti_res); -+ -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ drvdata->base_cti = base; -+ - ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res); - if (ret) - return ret; -diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index ee6dd1b..48bbbc9 100644 ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -963,6 +963,7 @@ config I2C_STM32F7 - tristate "STMicroelectronics STM32F7 I2C support" - depends on ARCH_STM32 || COMPILE_TEST - select I2C_SLAVE -+ select I2C_SMBUS - help - Enable this option to add support for STM32 I2C controller embedded - in STM32F7 SoCs. -diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index f4e3613..08b7416 100644 ---- a/drivers/i2c/busses/i2c-stm32f7.c -+++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -18,14 +18,20 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include - #include - #include - #include - #include -+#include -+#include -+#include -+#include - #include - #include - -@@ -45,6 +51,9 @@ - - /* STM32F7 I2C control 1 */ - #define STM32F7_I2C_CR1_PECEN BIT(23) -+#define STM32F7_I2C_CR1_ALERTEN BIT(22) -+#define STM32F7_I2C_CR1_SMBHEN BIT(20) -+#define STM32F7_I2C_CR1_WUPEN BIT(18) - #define STM32F7_I2C_CR1_SBC BIT(16) - #define STM32F7_I2C_CR1_RXDMAEN BIT(15) - #define STM32F7_I2C_CR1_TXDMAEN BIT(14) -@@ -115,6 +124,7 @@ - (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) - #define STM32F7_I2C_ISR_DIR BIT(16) - #define STM32F7_I2C_ISR_BUSY BIT(15) -+#define STM32F7_I2C_ISR_ALERT BIT(13) - #define STM32F7_I2C_ISR_PECERR BIT(11) - #define STM32F7_I2C_ISR_ARLO BIT(9) - #define STM32F7_I2C_ISR_BERR BIT(8) -@@ -128,6 +138,7 @@ - #define STM32F7_I2C_ISR_TXE BIT(0) - - /* STM32F7 I2C Interrupt Clear */ -+#define STM32F7_I2C_ICR_ALERTCF BIT(13) - #define STM32F7_I2C_ICR_PECCF BIT(11) - #define STM32F7_I2C_ICR_ARLOCF BIT(9) - #define STM32F7_I2C_ICR_BERRCF BIT(8) -@@ -144,7 +155,7 @@ - - #define STM32F7_I2C_MAX_LEN 0xff - #define STM32F7_I2C_DMA_LEN_MIN 0x16 --#define STM32F7_I2C_MAX_SLAVE 0x2 -+#define STM32F7_I2C_MAX_SLAVE 0x3 - - #define STM32F7_I2C_DNF_DEFAULT 0 - #define STM32F7_I2C_DNF_MAX 16 -@@ -162,11 +173,29 @@ - #define STM32F7_SCLH_MAX BIT(8) - #define STM32F7_SCLL_MAX BIT(8) - -+#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100) -+ -+/** -+ * struct stm32f7_i2c_regs - i2c f7 registers backup -+ * @cr1: Control register 1 -+ * @cr2: Control register 2 -+ * @oar1: Own address 1 register -+ * @oar2: Own address 2 register -+ * @pecr: PEC register -+ * @timingr: Timing register -+ */ -+struct stm32f7_i2c_regs { -+ u32 cr1; -+ u32 cr2; -+ u32 oar1; -+ u32 oar2; -+ u32 pecr; -+ u32 tmgr; -+}; -+ - /** - * struct stm32f7_i2c_spec - private i2c specification timing - * @rate: I2C bus speed (Hz) -- * @rate_min: 80% of I2C bus speed (Hz) -- * @rate_max: 100% of I2C bus speed (Hz) - * @fall_max: Max fall time of both SDA and SCL signals (ns) - * @rise_max: Max rise time of both SDA and SCL signals (ns) - * @hddat_min: Min data hold time (ns) -@@ -177,8 +206,6 @@ - */ - struct stm32f7_i2c_spec { - u32 rate; -- u32 rate_min; -- u32 rate_max; - u32 fall_max; - u32 rise_max; - u32 hddat_min; -@@ -190,7 +217,6 @@ struct stm32f7_i2c_spec { - - /** - * struct stm32f7_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) -@@ -199,7 +225,6 @@ struct stm32f7_i2c_spec { - * @analog_filter: Analog filter delay (On/Off) - */ - struct stm32f7_i2c_setup { -- enum stm32_i2c_speed speed; - u32 speed_freq; - u32 clock_src; - u32 rise_time; -@@ -255,13 +280,38 @@ struct stm32f7_i2c_msg { - }; - - /** -+ * struct stm32f7_i2c_host - SMBus host specific data -+ * @client: I2C slave device that represents SMBus host -+ * @notify_start: indicate that this is the start of the notify transaction -+ * @addr: device address of SMBus device that initiate SMBus host protocol -+ */ -+struct stm32f7_i2c_host { -+ struct i2c_client *client; -+ bool notify_start; -+ u8 addr; -+}; -+ -+/** -+ * struct stm32f7_i2c_alert - SMBus alert specific data -+ * @setup: platform data for the smbus_alert i2c client -+ * @ara: I2C slave device used to respond to the SMBus Alert with Alert -+ * Response Address -+ */ -+struct stm32f7_i2c_alert { -+ struct i2c_smbus_alert_setup setup; -+ struct i2c_client *ara; -+}; -+ -+/** - * struct stm32f7_i2c_dev - private data of the controller - * @adap: I2C adapter for this controller - * @dev: device for this controller -+ * @irq_event: interrupt event line for the controller -+ * @irq_wakeup: interrupt wakeup line for the controller - * @base: virtual memory area - * @complete: completion of I2C message - * @clk: hw i2c clock -- * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+ -+ * @bus_rate: I2C clock frequency of the controller. - * @msg: Pointer to data to be written - * @msg_num: number of I2C messages to be executed - * @msg_id: message identifiant -@@ -275,14 +325,25 @@ struct stm32f7_i2c_msg { - * slave) - * @dma: dma data - * @use_dma: boolean to know if dma is used in the current transfer -- */ -+ * @sregmap: holds SYSCFG phandle for Fast Mode Plus bits -+ * @cregmap: holds SYSCFG phandle for Fast Mode Plus clear bits -+ * @regmap_sreg: register address for setting Fast Mode Plus bits -+ * @regmap_smask: mask for Fast Mode Plus bits in set register -+ * @regmap_creg: register address for setting Fast Mode Plus bits -+ * @regmap_cmask: mask for Fast Mode Plus bits in set register -+ * @is_suspended: boolean to know if the driver has been suspended -+ * @host: SMBus host protocol specific data -+ * @alert: SMBus alert specific data -+*/ - struct stm32f7_i2c_dev { - struct i2c_adapter adap; - struct device *dev; - void __iomem *base; -+ int irq_event; -+ int irq_wakeup; - struct completion complete; - struct clk *clk; -- int speed; -+ unsigned int bus_rate; - struct i2c_msg *msg; - unsigned int msg_num; - unsigned int msg_id; -@@ -291,10 +352,20 @@ struct stm32f7_i2c_dev { - struct stm32f7_i2c_timings timing; - struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; - struct i2c_client *slave_running; -+ struct stm32f7_i2c_regs regs; - u32 slave_dir; - bool master_mode; - struct stm32_i2c_dma *dma; - bool use_dma; -+ struct regmap *sregmap; -+ struct regmap *cregmap; -+ u32 regmap_sreg; -+ u32 regmap_smask; -+ u32 regmap_creg; -+ u32 regmap_cmask; -+ bool is_suspended; -+ struct stm32f7_i2c_host *host; -+ struct stm32f7_i2c_alert *alert; - }; - - /* -@@ -304,11 +375,13 @@ struct stm32f7_i2c_dev { - * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast, - * and Fast-mode Plus I2C-bus devices - */ -+#define I2C_STD_RATE 100000 -+#define I2C_FAST_RATE 400000 -+#define I2C_FASTPLUS_RATE 1000000 - static struct stm32f7_i2c_spec i2c_specs[] = { -- [STM32_I2C_SPEED_STANDARD] = { -- .rate = 100000, -- .rate_min = 80000, -- .rate_max = 100000, -+ /* Standard - 100KHz */ -+ { -+ .rate = I2C_STD_RATE, - .fall_max = 300, - .rise_max = 1000, - .hddat_min = 0, -@@ -317,10 +390,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { - .l_min = 4700, - .h_min = 4000, - }, -- [STM32_I2C_SPEED_FAST] = { -- .rate = 400000, -- .rate_min = 320000, -- .rate_max = 400000, -+ /* Fast - 400KHz */ -+ { -+ .rate = I2C_FAST_RATE, - .fall_max = 300, - .rise_max = 300, - .hddat_min = 0, -@@ -329,10 +401,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { - .l_min = 1300, - .h_min = 600, - }, -- [STM32_I2C_SPEED_FAST_PLUS] = { -- .rate = 1000000, -- .rate_min = 800000, -- .rate_max = 1000000, -+ /* FastPlus - 1MHz */ -+ { -+ .rate = I2C_FASTPLUS_RATE, - .fall_max = 100, - .rise_max = 120, - .hddat_min = 0, -@@ -365,10 +436,24 @@ static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); - } - -+static struct stm32f7_i2c_spec *get_specs(u32 rate) -+{ -+ 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); -+} -+ -+#define RATE_MIN(rate) (rate / 100 * 80) - static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - struct stm32f7_i2c_setup *setup, - struct stm32f7_i2c_timings *output) - { -+ struct stm32f7_i2c_spec *specs; - u32 p_prev = STM32F7_PRESC_MAX; - u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, - setup->clock_src); -@@ -386,18 +471,19 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - u16 p, l, a, h; - int ret = 0; - -- if (setup->speed >= STM32_I2C_SPEED_END) { -- dev_err(i2c_dev->dev, "speed out of bound {%d/%d}\n", -- setup->speed, STM32_I2C_SPEED_END - 1); -+ specs = get_specs(setup->speed_freq); -+ if (specs == ERR_PTR(-EINVAL)) { -+ dev_err(i2c_dev->dev, "speed out of bound {%d}\n", -+ 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)) { - dev_err(i2c_dev->dev, - "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", -- 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; - } - -@@ -408,12 +494,6 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - return -EINVAL; - } - -- if (setup->speed_freq > i2c_specs[setup->speed].rate) { -- dev_err(i2c_dev->dev, "ERROR: Freq {%d/%d}\n", -- setup->speed_freq, i2c_specs[setup->speed].rate); -- return -EINVAL; -- } -- - /* Analog and Digital Filters */ - af_delay_min = - (setup->analog_filter ? -@@ -423,13 +503,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); - dnf_delay = setup->dnf * i2cclk; - -- 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; -@@ -467,8 +547,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - - list_add_tail(&v->node, - &solutions); -+ break; - } - } -+ -+ if (p_prev == p) -+ break; - } - } - -@@ -480,8 +564,8 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - - tsync = af_delay_min + dnf_delay + (2 * i2cclk); - s = NULL; -- clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; -- clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; -+ clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq); -+ clk_min = NSEC_PER_SEC / setup->speed_freq; - - /* - * Among Prescaler possibilities discovered above figures out SCL Low -@@ -499,7 +583,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - for (l = 0; l < STM32F7_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; -@@ -511,7 +595,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - 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)) { - int clk_error = tscl - i2cbus; - -@@ -557,13 +641,23 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, - return ret; - } - -+static u32 get_lower_rate(u32 rate) -+{ -+ int i; -+ -+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) -+ if (i2c_specs[i].rate < rate) -+ return i2c_specs[i].rate; -+ -+ return i2c_specs[0].rate; -+} -+ - static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - struct stm32f7_i2c_setup *setup) - { - int ret = 0; - -- setup->speed = i2c_dev->speed; -- setup->speed_freq = i2c_specs[setup->speed].rate; -+ setup->speed_freq = i2c_dev->bus_rate; - setup->clock_src = clk_get_rate(i2c_dev->clk); - - if (!setup->clock_src) { -@@ -577,14 +671,12 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - if (ret) { - dev_err(i2c_dev->dev, - "failed to compute I2C timings.\n"); -- if (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) { -- i2c_dev->speed--; -- setup->speed = i2c_dev->speed; -+ if (setup->speed_freq > I2C_STD_RATE) { - setup->speed_freq = -- i2c_specs[setup->speed].rate; -+ get_lower_rate(setup->speed_freq); - dev_warn(i2c_dev->dev, - "downgrade I2C Speed Freq to (%i)\n", -- i2c_specs[setup->speed].rate); -+ setup->speed_freq); - } else { - break; - } -@@ -596,13 +688,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, - return ret; - } - -- dev_dbg(i2c_dev->dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n", -- setup->speed, setup->speed_freq, setup->clock_src); -+ dev_dbg(i2c_dev->dev, "I2C Freq(%i), Clk Source(%i)\n", -+ setup->speed_freq, setup->clock_src); - dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", - setup->rise_time, setup->fall_time); - dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", - (setup->analog_filter ? "On" : "Off"), setup->dnf); - -+ i2c_dev->bus_rate = setup->speed_freq; -+ - return 0; - } - -@@ -940,6 +1034,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, - cr2 &= ~STM32F7_I2C_CR2_RD_WRN; - f7_msg->read_write = I2C_SMBUS_READ; - break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /* Rely on emulated i2c transfer (through master_xfer) */ -+ return -EOPNOTSUPP; - default: - dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); - return -EOPNOTSUPP; -@@ -1249,11 +1346,21 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, - int i; - - /* -- * slave[0] supports 7-bit and 10-bit slave address -- * slave[1] supports 7-bit slave address only -+ * slave[0] support only SMBus Host address (0x8) -+ * slave[1] supports 7-bit and 10-bit slave address -+ * slave[2] supports 7-bit slave address only - */ -- for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { -- if (i == 1 && (slave->flags & I2C_CLIENT_PEC)) -+ if (i2c_dev->host) { -+ if (slave->addr == 0x08) { -+ if (i2c_dev->slave[0]) -+ goto fail; -+ *id = 0; -+ return 0; -+ } -+ } -+ -+ for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) { -+ if (i == 2 && (slave->flags & I2C_CLIENT_TEN)) - continue; - if (!i2c_dev->slave[i]) { - *id = i; -@@ -1261,6 +1368,7 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, - } - } - -+fail: - dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); - - return -EINVAL; -@@ -1513,6 +1621,13 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) - f7_msg->result = -EINVAL; - } - -+ if (status & STM32F7_I2C_ISR_ALERT) { -+ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); -+ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); -+ i2c_handle_smbus_alert(i2c_dev->alert->ara); -+ return IRQ_HANDLED; -+ } -+ - if (!i2c_dev->slave_running) { - u32 mask; - /* Disable interrupts */ -@@ -1544,20 +1659,21 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, - unsigned long time_left; - int ret; - -+ if (i2c_dev->is_suspended) -+ return -EBUSY; -+ - i2c_dev->msg = msgs; - i2c_dev->msg_num = num; - i2c_dev->msg_id = 0; - f7_msg->smbus = false; - -- ret = clk_enable(i2c_dev->clk); -- if (ret) { -- dev_err(i2c_dev->dev, "Failed to enable clock\n"); -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) - return ret; -- } - - ret = stm32f7_i2c_wait_free_bus(i2c_dev); - if (ret) -- goto clk_free; -+ goto pm_free; - - stm32f7_i2c_xfer_msg(i2c_dev, msgs); - -@@ -1573,8 +1689,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, - ret = -ETIMEDOUT; - } - --clk_free: -- clk_disable(i2c_dev->clk); -+pm_free: -+ pm_runtime_mark_last_busy(i2c_dev->dev); -+ pm_runtime_put_autosuspend(i2c_dev->dev); - - return (ret < 0) ? ret : num; - } -@@ -1591,44 +1708,45 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - unsigned long timeout; - int i, ret; - -+ if (i2c_dev->is_suspended) -+ return -EBUSY; -+ - f7_msg->addr = addr; - f7_msg->size = size; - f7_msg->read_write = read_write; - f7_msg->smbus = true; - -- ret = clk_enable(i2c_dev->clk); -- if (ret) { -- dev_err(i2c_dev->dev, "Failed to enable clock\n"); -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) - return ret; -- } - - ret = stm32f7_i2c_wait_free_bus(i2c_dev); - if (ret) -- goto clk_free; -+ goto pm_free; - - ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data); - if (ret) -- goto clk_free; -+ goto pm_free; - - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); - ret = f7_msg->result; - if (ret) -- goto clk_free; -+ goto pm_free; - - if (!timeout) { - dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); - if (i2c_dev->use_dma) - dmaengine_terminate_all(dma->chan_using); - ret = -ETIMEDOUT; -- goto clk_free; -+ goto pm_free; - } - - /* Check PEC */ - if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) { - ret = stm32f7_i2c_smbus_check_pec(i2c_dev); - if (ret) -- goto clk_free; -+ goto pm_free; - } - - if (read_write && size != I2C_SMBUS_QUICK) { -@@ -1653,11 +1771,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - } - } - --clk_free: -- clk_disable(i2c_dev->clk); -+pm_free: -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - return ret; - } - -+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, -+ bool enable); -+ - static int stm32f7_i2c_reg_slave(struct i2c_client *slave) - { - struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); -@@ -1680,15 +1802,20 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) - if (ret) - return ret; - -- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { -- ret = clk_enable(i2c_dev->clk); -- if (ret) { -- dev_err(dev, "Failed to enable clock\n"); -- return ret; -- } -- } -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) -+ return ret; - -- if (id == 0) { -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) -+ stm32f7_i2c_enable_wakeup(i2c_dev, true); -+ -+ switch (id) { -+ case 0: -+ /* Slave SMBus Host */ -+ i2c_dev->slave[id] = slave; -+ break; -+ -+ case 1: - /* Configure Own Address 1 */ - oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); - oar1 &= ~STM32F7_I2C_OAR1_MASK; -@@ -1701,22 +1828,27 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) - oar1 |= STM32F7_I2C_OAR1_OA1EN; - i2c_dev->slave[id] = slave; - writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); -- } else if (id == 1) { -+ break; -+ -+ case 2: - /* Configure Own Address 2 */ - oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); - oar2 &= ~STM32F7_I2C_OAR2_MASK; - if (slave->flags & I2C_CLIENT_TEN) { - ret = -EOPNOTSUPP; -- goto exit; -+ goto pm_free; - } - - oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); - oar2 |= STM32F7_I2C_OAR2_OA2EN; - i2c_dev->slave[id] = slave; - writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); -- } else { -+ break; -+ -+ default: -+ dev_err(dev, "I2C slave id not supported\n"); - ret = -ENODEV; -- goto exit; -+ goto pm_free; - } - - /* Enable ACK */ -@@ -1727,11 +1859,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) - STM32F7_I2C_CR1_PE; - stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); - -- return 0; -+ ret = 0; -+pm_free: -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) -+ stm32f7_i2c_enable_wakeup(i2c_dev, false); - --exit: -- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) -- clk_disable(i2c_dev->clk); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - - return ret; - } -@@ -1749,31 +1883,246 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) - - WARN_ON(!i2c_dev->slave[id]); - -- if (id == 0) { -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) -+ return ret; -+ -+ if (id == 1) { - mask = STM32F7_I2C_OAR1_OA1EN; - stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); -- } else { -+ } else if (id == 2) { - mask = STM32F7_I2C_OAR2_OA2EN; - stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); - } - - i2c_dev->slave[id] = NULL; - -- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); -- clk_disable(i2c_dev->clk); -+ stm32f7_i2c_enable_wakeup(i2c_dev, false); -+ } -+ -+ pm_runtime_mark_last_busy(i2c_dev->dev); -+ pm_runtime_put_autosuspend(i2c_dev->dev); -+ -+ return 0; -+} -+ -+static int stm32f7_i2c_setup_wakeup(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ int ret; -+ -+ device_init_wakeup(i2c_dev->dev, true); -+ ret = dev_pm_set_dedicated_wake_irq(i2c_dev->dev, i2c_dev->irq_wakeup); -+ if (ret) { -+ device_init_wakeup(i2c_dev->dev, false); -+ dev_warn(i2c_dev->dev, "failed to set up wakeup irq"); -+ return ret; -+ } -+ -+ return device_set_wakeup_enable(i2c_dev->dev, false); -+} -+ -+static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev, -+ bool enable) -+{ -+ int ret; -+ u32 reg, mask; -+ -+ if (i2c_dev->bus_rate <= I2C_FAST_RATE || -+ IS_ERR_OR_NULL(i2c_dev->sregmap)) { -+ /* Optional */ -+ return 0; -+ } -+ -+ reg = i2c_dev->regmap_sreg; -+ mask = i2c_dev->regmap_smask; -+ -+ if (IS_ERR(i2c_dev->cregmap)) -+ ret = regmap_update_bits(i2c_dev->sregmap, reg, mask, -+ enable ? mask : 0); -+ else -+ ret = regmap_write(enable ? i2c_dev->sregmap : i2c_dev->cregmap, -+ enable ? reg : i2c_dev->regmap_creg, -+ enable ? mask : i2c_dev->regmap_cmask); -+ -+ return ret; -+} -+ -+static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev, -+ struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ int ret; -+ u32 reg, mask; -+ -+ i2c_dev->sregmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp"); -+ if (IS_ERR(i2c_dev->sregmap)) { -+ /* Optional */ -+ return 0; -+ } -+ -+ ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1, ®); -+ if (ret) -+ return ret; -+ -+ ret = of_property_read_u32_index(np, "st,syscfg-fmp", 2, &mask); -+ if (ret) -+ return ret; -+ -+ i2c_dev->regmap_sreg = reg; -+ i2c_dev->regmap_smask = mask; -+ i2c_dev->cregmap = syscon_regmap_lookup_by_phandle(np, -+ "st,syscfg-fmp-clr"); -+ if (!IS_ERR(i2c_dev->cregmap)) { -+ ret = of_property_read_u32_index(np, "st,syscfg-fmp-clr", 1, -+ &i2c_dev->regmap_creg); -+ if (ret) -+ return ret; -+ -+ ret = of_property_read_u32_index(np, "st,syscfg-fmp-clr", 2, -+ &i2c_dev->regmap_cmask); -+ if (ret) -+ return ret; -+ } -+ -+ return stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); -+} -+ -+static int stm32f7_i2c_smbus_host_cb(struct i2c_client *client, -+ enum i2c_slave_event event, -+ u8 *val) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(client->adapter); -+ struct stm32f7_i2c_host *host = i2c_dev->host; -+ int ret; -+ -+ switch (event) { -+ case I2C_SLAVE_WRITE_REQUESTED: -+ host->notify_start = true; -+ break; -+ case I2C_SLAVE_WRITE_RECEIVED: -+ /* We only retrieve the first byte received (addr) -+ * From Documentation/i2c/smbus-protocol: -+ * There is currently no way to retrieve the data parameter -+ * from the client. -+ */ -+ if (!host->notify_start) -+ break; -+ host->addr = *val; -+ host->notify_start = false; -+ break; -+ case I2C_SLAVE_STOP: -+ ret = i2c_handle_smbus_host_notify(client->adapter, -+ host->addr); -+ if (ret < 0) { -+ dev_dbg(i2c_dev->dev, "failed to handle host_notify (%d)\n", -+ ret); -+ return ret; -+ } -+ break; -+ default: -+ dev_err(i2c_dev->dev, "slave event not supported\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct stm32f7_i2c_host *host; -+ struct i2c_adapter *adap = &i2c_dev->adap; -+ struct device *dev = i2c_dev->dev; -+ void __iomem *base = i2c_dev->base; -+ struct i2c_board_info host_notify_board_info = { -+ I2C_BOARD_INFO("smbus_host_notify", 0x8), -+ .flags = I2C_CLIENT_SLAVE, -+ }; -+ int ret; -+ -+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); -+ if (!host) -+ return -ENOMEM; -+ -+ host->client = i2c_new_device(adap, &host_notify_board_info); -+ if (!host->client) -+ return -ENOMEM; -+ -+ i2c_dev->host = host; -+ -+ ret = i2c_slave_register(host->client, stm32f7_i2c_smbus_host_cb); -+ if (ret) { -+ i2c_dev->host = NULL; -+ i2c_unregister_device(host->client); -+ return ret; - } - -+ /* Enable SMBus Host address */ -+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN); -+ - return 0; - } - -+static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ void __iomem *base = i2c_dev->base; -+ struct stm32f7_i2c_host *host = i2c_dev->host; -+ -+ if (host) { -+ /* Disable SMBus Host address */ -+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_SMBHEN); -+ i2c_slave_unregister(host->client); -+ i2c_dev->host = NULL; -+ i2c_unregister_device(host->client); -+ } -+} -+ -+static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct stm32f7_i2c_alert *alert; -+ struct i2c_adapter *adap = &i2c_dev->adap; -+ struct device *dev = i2c_dev->dev; -+ void __iomem *base = i2c_dev->base; -+ -+ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL); -+ if (!alert) -+ return -ENOMEM; -+ -+ alert->ara = i2c_setup_smbus_alert(adap, &alert->setup); -+ if (!alert->ara) -+ return -ENOMEM; -+ -+ i2c_dev->alert = alert; -+ -+ /* Enable SMBus Alert */ -+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN); -+ -+ return 0; -+} -+ -+static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ struct stm32f7_i2c_alert *alert = i2c_dev->alert; -+ void __iomem *base = i2c_dev->base; -+ -+ if (alert) { -+ /* Disable SMBus Alert */ -+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_ALERTEN); -+ i2c_unregister_device(alert->ara); -+ } -+} -+ - static u32 stm32f7_i2c_func(struct i2c_adapter *adap) - { - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE | - I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | -- I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC; -+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC | -+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HOST_NOTIFY; - } - - static struct i2c_algorithm stm32f7_i2c_algo = { -@@ -1789,11 +2138,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - struct stm32f7_i2c_dev *i2c_dev; - const struct stm32f7_i2c_setup *setup; - struct resource *res; -- u32 clk_rate, rise_time, fall_time; -+ u32 rise_time, fall_time; - struct i2c_adapter *adap; - struct reset_control *rst; - dma_addr_t phy_addr; -- int irq_error, irq_event, ret; -+ int irq_error, ret; - - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) -@@ -1805,15 +2154,15 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - return PTR_ERR(i2c_dev->base); - phy_addr = (dma_addr_t)res->start; - -- irq_event = platform_get_irq(pdev, 0); -- if (irq_event <= 0) { -- if (irq_event != -EPROBE_DEFER) -+ i2c_dev->irq_event = platform_get_irq_byname(pdev, "event"); -+ if (i2c_dev->irq_event <= 0) { -+ if (i2c_dev->irq_event != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", -- irq_event); -- return irq_event ? : -ENOENT; -+ i2c_dev->irq_event); -+ return i2c_dev->irq_event ? : -ENOENT; - } - -- irq_error = platform_get_irq(pdev, 1); -+ irq_error = platform_get_irq_byname(pdev, "error"); - if (irq_error <= 0) { - if (irq_error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", -@@ -1821,26 +2170,36 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - return irq_error ? : -ENOENT; - } - -+ i2c_dev->irq_wakeup = platform_get_irq_byname(pdev, "wakeup"); -+ if (i2c_dev->irq_wakeup < 0 && i2c_dev->irq_wakeup != -ENXIO) { -+ if (i2c_dev->irq_wakeup != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Failed to get IRQ wakeup: %d\n", -+ i2c_dev->irq_wakeup); -+ return i2c_dev->irq_wakeup; -+ } -+ - i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "Error: Missing controller clock\n"); - return PTR_ERR(i2c_dev->clk); - } -+ - ret = clk_prepare_enable(i2c_dev->clk); - if (ret) { - dev_err(&pdev->dev, "Failed to prepare_enable clock\n"); - return ret; - } - -- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; - ret = device_property_read_u32(&pdev->dev, "clock-frequency", -- &clk_rate); -- if (!ret && clk_rate >= 1000000) -- i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS; -- else if (!ret && clk_rate >= 400000) -- i2c_dev->speed = STM32_I2C_SPEED_FAST; -- else if (!ret && clk_rate >= 100000) -- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; -+ &i2c_dev->bus_rate); -+ if (ret) -+ i2c_dev->bus_rate = I2C_STD_RATE; -+ -+ if (i2c_dev->bus_rate > I2C_FASTPLUS_RATE) { -+ dev_err(&pdev->dev, "Invalid bus speed (%i>%i)\n", -+ i2c_dev->bus_rate, I2C_FASTPLUS_RATE); -+ return -EINVAL; -+ } - - rst = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(rst)) { -@@ -1854,14 +2213,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - - i2c_dev->dev = &pdev->dev; - -- ret = devm_request_threaded_irq(&pdev->dev, irq_event, -+ ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event, - stm32f7_i2c_isr_event, - stm32f7_i2c_isr_event_thread, - IRQF_ONESHOT, - pdev->name, i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq event %i\n", -- irq_event); -+ i2c_dev->irq_event); - goto clk_free; - } - -@@ -1895,7 +2254,12 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - if (ret) - goto clk_free; - -- stm32f7_i2c_hw_config(i2c_dev); -+ /* Setup Fast mode plus if necessary */ -+ if (i2c_dev->bus_rate > I2C_FAST_RATE) { -+ ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); -+ if (ret) -+ goto clk_free; -+ } - - adap = &i2c_dev->adap; - i2c_set_adapdata(adap, i2c_dev); -@@ -1915,18 +2279,77 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - STM32F7_I2C_TXDR, - STM32F7_I2C_RXDR); - -+ if (i2c_dev->irq_wakeup > 0) { -+ ret = stm32f7_i2c_setup_wakeup(i2c_dev); -+ if (ret) -+ goto dma_free; -+ } -+ -+ platform_set_drvdata(pdev, i2c_dev); -+ -+ pm_runtime_set_autosuspend_delay(i2c_dev->dev, -+ STM32F7_AUTOSUSPEND_DELAY); -+ pm_runtime_use_autosuspend(i2c_dev->dev); -+ pm_runtime_set_active(i2c_dev->dev); -+ pm_runtime_enable(i2c_dev->dev); -+ -+ pm_runtime_get_noresume(&pdev->dev); -+ -+ stm32f7_i2c_hw_config(i2c_dev); -+ - ret = i2c_add_adapter(adap); - if (ret) -- goto clk_free; -+ goto pm_disable; - -- platform_set_drvdata(pdev, i2c_dev); -+ if (device_property_read_bool(&pdev->dev, "st,smbus-host-notify")) { -+ ret = stm32f7_i2c_enable_smbus_host(i2c_dev); -+ if (ret) { -+ dev_err(i2c_dev->dev, -+ "failed to enable SMBus host notify (%d)\n", -+ ret); -+ goto i2c_adapter_remove; -+ } -+ } - -- clk_disable(i2c_dev->clk); -+ if (device_property_read_bool(&pdev->dev, "st,smbus-alert")) { -+ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev); -+ if (ret) { -+ dev_err(i2c_dev->dev, -+ "failed to enable SMBus alert protocol (%d)\n", -+ ret); -+ goto host_notify_disable; -+ } -+ } - - dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); - -+ pm_runtime_mark_last_busy(i2c_dev->dev); -+ pm_runtime_put_autosuspend(i2c_dev->dev); -+ - return 0; - -+host_notify_disable: -+ stm32f7_i2c_disable_smbus_host(i2c_dev); -+ -+i2c_adapter_remove: -+ i2c_del_adapter(adap); -+ -+pm_disable: -+ dev_pm_clear_wake_irq(i2c_dev->dev); -+ device_init_wakeup(i2c_dev->dev, false); -+ -+ pm_runtime_put_noidle(i2c_dev->dev); -+ pm_runtime_disable(i2c_dev->dev); -+ pm_runtime_set_suspended(i2c_dev->dev); -+ pm_runtime_dont_use_autosuspend(i2c_dev->dev); -+ -+dma_free: -+ if (i2c_dev->dma) { -+ stm32_i2c_dma_free(i2c_dev->dma); -+ i2c_dev->dma = NULL; -+ } -+ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); -+ - clk_free: - clk_disable_unprepare(i2c_dev->clk); - -@@ -1937,18 +2360,192 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) - { - struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - -+ stm32f7_i2c_disable_smbus_alert(i2c_dev); -+ -+ stm32f7_i2c_disable_smbus_host(i2c_dev); -+ -+ i2c_del_adapter(&i2c_dev->adap); -+ pm_runtime_get_sync(i2c_dev->dev); -+ -+ dev_pm_clear_wake_irq(i2c_dev->dev); -+ device_init_wakeup(i2c_dev->dev, false); -+ -+ pm_runtime_put_noidle(i2c_dev->dev); -+ pm_runtime_disable(i2c_dev->dev); -+ pm_runtime_set_suspended(i2c_dev->dev); -+ pm_runtime_dont_use_autosuspend(i2c_dev->dev); -+ - if (i2c_dev->dma) { - stm32_i2c_dma_free(i2c_dev->dma); - i2c_dev->dma = NULL; - } -+ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); - -- i2c_del_adapter(&i2c_dev->adap); -+ clk_disable_unprepare(i2c_dev->clk); - -- clk_unprepare(i2c_dev->clk); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int stm32f7_i2c_runtime_suspend(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) -+ clk_disable_unprepare(i2c_dev->clk); -+ -+ return 0; -+} -+ -+static int stm32f7_i2c_runtime_resume(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ int ret; -+ -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -+ ret = clk_prepare_enable(i2c_dev->clk); -+ if (ret) { -+ dev_err(dev, "failed to prepare_enable clock\n"); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ int ret; -+ -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) -+ return ret; -+ -+ i2c_dev->regs.cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); -+ i2c_dev->regs.cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); -+ i2c_dev->regs.oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); -+ i2c_dev->regs.oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); -+ i2c_dev->regs.pecr = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR); -+ i2c_dev->regs.tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR); -+ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); -+ -+ pm_runtime_put_sync(i2c_dev->dev); -+ -+ return ret; -+} -+ -+static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) -+{ -+ u32 cr1; -+ int ret; -+ -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) -+ return ret; -+ -+ cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); -+ if (cr1 & STM32F7_I2C_CR1_PE) -+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_PE); -+ -+ writel_relaxed(i2c_dev->regs.tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR); -+ writel_relaxed(i2c_dev->regs.cr1 & ~STM32F7_I2C_CR1_PE, -+ i2c_dev->base + STM32F7_I2C_CR1); -+ if (i2c_dev->regs.cr1 & STM32F7_I2C_CR1_PE) -+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_PE); -+ writel_relaxed(i2c_dev->regs.cr2, i2c_dev->base + STM32F7_I2C_CR2); -+ writel_relaxed(i2c_dev->regs.oar1, i2c_dev->base + STM32F7_I2C_OAR1); -+ writel_relaxed(i2c_dev->regs.oar2, i2c_dev->base + STM32F7_I2C_OAR2); -+ writel_relaxed(i2c_dev->regs.pecr, i2c_dev->base + STM32F7_I2C_PECR); -+ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); -+ -+ pm_runtime_put_sync(i2c_dev->dev); -+ -+ return ret; -+} -+ -+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, -+ bool enable) -+{ -+ void __iomem *base = i2c_dev->base; -+ u32 mask = STM32F7_I2C_CR1_WUPEN; -+ -+ if (i2c_dev->irq_wakeup <= 0) -+ return; -+ -+ if (enable) { -+ device_set_wakeup_enable(i2c_dev->dev, true); -+ enable_irq_wake(i2c_dev->irq_wakeup); -+ enable_irq_wake(i2c_dev->irq_event); -+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); -+ readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); -+ } else { -+ disable_irq_wake(i2c_dev->irq_wakeup); -+ disable_irq_wake(i2c_dev->irq_event); -+ device_set_wakeup_enable(i2c_dev->dev, false); -+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); -+ } -+} -+ -+static int stm32f7_i2c_suspend(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ int ret; -+ -+ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); -+ i2c_dev->is_suspended = true; -+ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); -+ -+ ret = stm32f7_i2c_regs_backup(i2c_dev); -+ if (ret < 0) -+ return ret; -+ -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -+ pinctrl_pm_select_sleep_state(dev); -+ pm_runtime_force_suspend(dev); -+ } - - return 0; - } - -+static int stm32f7_i2c_resume(struct device *dev) -+{ -+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ int ret; -+ -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -+ ret = pm_runtime_force_resume(dev); -+ if (ret < 0) -+ return ret; -+ pinctrl_pm_select_default_state(dev); -+ } -+ -+ ret = stm32f7_i2c_regs_restore(i2c_dev); -+ if (ret < 0) -+ return ret; -+ -+ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); -+ i2c_dev->is_suspended = false; -+ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); -+ -+ return 0; -+} -+#else -+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, -+ bool enable) -+{ -+} -+#endif -+ -+static const struct dev_pm_ops stm32f7_i2c_pm_ops = { -+ SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, -+ stm32f7_i2c_runtime_resume, NULL) -+ SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume) -+}; -+ - static const struct of_device_id stm32f7_i2c_match[] = { - { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, - {}, -@@ -1959,6 +2556,7 @@ static struct platform_driver stm32f7_i2c_driver = { - .driver = { - .name = "stm32f7-i2c", - .of_match_table = stm32f7_i2c_match, -+ .pm = &stm32f7_i2c_pm_ops, - }, - .probe = stm32f7_i2c_probe, - .remove = stm32f7_i2c_remove, --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch deleted file mode 100644 index 2b31874..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch +++ /dev/null @@ -1,6486 +0,0 @@ -From 46ab5b40eb3e51c796f28fb2bd098b4177b20d50 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:41 +0100 -Subject: [PATCH 11/31] ARM stm32mp1 r3 IIO - ---- - drivers/iio/adc/Kconfig | 11 + - drivers/iio/adc/Makefile | 1 + - drivers/iio/adc/sd_adc_modulator.c | 84 +- - drivers/iio/adc/stm32-adc-core.c | 637 +++++++++++-- - drivers/iio/adc/stm32-adc-core.h | 170 ++++ - drivers/iio/adc/stm32-adc-temp.c | 412 +++++++++ - drivers/iio/adc/stm32-adc.c | 1416 ++++++++++++++++++++++++----- - drivers/iio/adc/stm32-dfsdm-adc.c | 975 ++++++++++++++++---- - drivers/iio/adc/stm32-dfsdm-core.c | 176 +++- - drivers/iio/adc/stm32-dfsdm.h | 24 +- - drivers/iio/counter/stm32-lptimer-cnt.c | 55 ++ - drivers/iio/dac/stm32-dac-core.c | 142 ++- - drivers/iio/dac/stm32-dac.c | 96 +- - drivers/iio/trigger/stm32-timer-trigger.c | 167 +++- - 14 files changed, 3777 insertions(+), 589 deletions(-) - create mode 100644 drivers/iio/adc/stm32-adc-temp.c - -diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig -index 9421c1e..66af479 100644 ---- a/drivers/iio/adc/Kconfig -+++ b/drivers/iio/adc/Kconfig -@@ -662,6 +662,7 @@ config STM32_ADC_CORE - select MFD_STM32_TIMERS - select IIO_STM32_TIMER_TRIGGER - select IIO_TRIGGERED_BUFFER -+ select IRQ_WORK - help - Select this option to enable the core driver for STMicroelectronics - STM32 analog-to-digital converter (ADC). -@@ -679,6 +680,16 @@ config STM32_ADC - This driver can also be built as a module. If so, the module - will be called stm32-adc. - -+config STM32_ADC_TEMP -+ tristate "STMicroelectronics STM32 ADC temperature sensor" -+ depends on STM32_ADC -+ help -+ Select this option to enable the driver for temperature sensor -+ connected internally to STM32 ADC. -+ -+ This driver can also be built as a module. If so, the module -+ will be called stm32-adc-temp. -+ - config STM32_DFSDM_CORE - tristate "STMicroelectronics STM32 DFSDM core" - depends on (ARCH_STM32 && OF) || COMPILE_TEST -diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile -index 03db7b5..527f9ef 100644 ---- a/drivers/iio/adc/Makefile -+++ b/drivers/iio/adc/Makefile -@@ -65,6 +65,7 @@ obj-$(CONFIG_STX104) += stx104.o - obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o - obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o - obj-$(CONFIG_STM32_ADC) += stm32-adc.o -+obj-$(CONFIG_STM32_ADC_TEMP) += stm32-adc-temp.o - obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o - obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o - obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o -diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c -index 560d8c7..c0a6e89 100644 ---- a/drivers/iio/adc/sd_adc_modulator.c -+++ b/drivers/iio/adc/sd_adc_modulator.c -@@ -10,8 +10,7 @@ - #include - #include - #include -- --static const struct iio_info iio_sd_mod_iio_info; -+#include - - static const struct iio_chan_spec iio_sd_mod_ch = { - .type = IIO_VOLTAGE, -@@ -21,36 +20,99 @@ static const struct iio_chan_spec iio_sd_mod_ch = { - .realbits = 1, - .shift = 0, - }, -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), -+}; -+ -+static const struct iio_chan_spec iio_sd_mod_ch_ads = { -+ .type = IIO_VOLTAGE, -+ .indexed = 1, -+ .scan_type = { -+ .sign = 'u', -+ .realbits = 1, -+ .shift = 0, -+ }, -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), -+ .differential = 1, -+}; -+ -+struct iio_sd_mod_priv { -+ int vref_mv; -+}; -+ -+static const struct of_device_id sd_adc_of_match[] = { -+ { .compatible = "sd-modulator", .data = &iio_sd_mod_ch }, -+ { .compatible = "ads1201", .data = &iio_sd_mod_ch_ads }, -+ { } -+}; -+ -+static int iio_sd_mod_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int *val, -+ int *val2, long mask) -+{ -+ struct iio_sd_mod_priv *priv = iio_priv(indio_dev); -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_SCALE: -+ *val = priv->vref_mv; -+ *val2 = chan->scan_type.realbits; -+ return IIO_VAL_INT; -+ } -+ -+ return -EINVAL; -+} -+ -+static const struct iio_info iio_sd_mod_iio_info = { -+ .read_raw = iio_sd_mod_read_raw, - }; - - static int iio_sd_mod_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -+ struct iio_sd_mod_priv *priv; -+ struct regulator *vref; - struct iio_dev *iio; -+ int ret; - -- iio = devm_iio_device_alloc(dev, 0); -+ iio = devm_iio_device_alloc(dev, sizeof(*priv)); - if (!iio) - return -ENOMEM; - -+ iio->channels = (const struct iio_chan_spec *) -+ of_match_device(sd_adc_of_match, &pdev->dev)->data; -+ -+ priv = iio_priv(iio); -+ - iio->dev.parent = dev; - iio->dev.of_node = dev->of_node; - iio->name = dev_name(dev); - iio->info = &iio_sd_mod_iio_info; - iio->modes = INDIO_BUFFER_HARDWARE; -- - iio->num_channels = 1; -- iio->channels = &iio_sd_mod_ch; - -- platform_set_drvdata(pdev, iio); -+ vref = devm_regulator_get_optional(dev, "vref"); -+ if (IS_ERR(vref)) { -+ ret = PTR_ERR(vref); -+ if (ret != -ENODEV) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "vref get failed, %d\n", ret); -+ return ret; -+ } -+ } -+ -+ if (!IS_ERR(vref)) { -+ ret = regulator_get_voltage(vref); -+ if (ret < 0) { -+ dev_err(dev, "vref get failed, %d\n", ret); -+ return ret; -+ } -+ -+ priv->vref_mv = ret / 1000; -+ dev_dbg(dev, "vref+=%dmV\n", priv->vref_mv); -+ } - - return devm_iio_device_register(&pdev->dev, iio); - } - --static const struct of_device_id sd_adc_of_match[] = { -- { .compatible = "sd-modulator" }, -- { .compatible = "ads1201" }, -- { } --}; - MODULE_DEVICE_TABLE(of, sd_adc_of_match); - - static struct platform_driver iio_sd_mod_adc = { -diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index 38eb966..5062661 100644 ---- a/drivers/iio/adc/stm32-adc-core.c -+++ b/drivers/iio/adc/stm32-adc-core.c -@@ -10,31 +10,47 @@ - */ - - #include -+#include -+#include - #include - #include - #include - #include -+#include - #include - #include -+#include -+#include -+#include - #include - #include - - #include "stm32-adc-core.h" - -+#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 -+ - /** - * stm32_adc_common_regs - stm32 common registers, compatible dependent data - * @csr: common status register offset -+ * @ccr: common control register offset - * @eoc1: adc1 end of conversion flag in @csr - * @eoc2: adc2 end of conversion flag in @csr - * @eoc3: adc3 end of conversion flag in @csr -+ * @jeoc1: adc1 end of injected conversion flag in @csr -+ * @jeoc2: adc2 end of injected conversion flag in @csr -+ * @jeoc3: adc3 end of injected conversion flag in @csr - * @ier: interrupt enable register offset for each adc - * @eocie_msk: end of conversion interrupt enable mask in @ier - */ - struct stm32_adc_common_regs { - u32 csr; -+ u32 ccr; - u32 eoc1_msk; - u32 eoc2_msk; - u32 eoc3_msk; -+ u32 jeoc1_msk; -+ u32 jeoc2_msk; -+ u32 jeoc3_msk; - u32 ier; - u32 eocie_msk; - }; -@@ -46,11 +62,27 @@ struct stm32_adc_priv; - * @regs: common registers for all instances - * @clk_sel: clock selection routine - * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) -+ * @has_syscfg_clr: analog switch control use set and clear registers -+ * @exti_trigs EXTI triggers info - */ - struct stm32_adc_priv_cfg { - const struct stm32_adc_common_regs *regs; - int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); - u32 max_clk_rate_hz; -+ int has_syscfg_clr; -+ struct stm32_adc_trig_info *exti_trigs; -+}; -+ -+/** -+ * stm32_adc_syscfg - stm32 ADC SYSCFG data -+ * @regmap: reference to syscon -+ * @reg: register offset within SYSCFG -+ * @mask: bitmask within SYSCFG register -+ */ -+struct stm32_adc_syscfg { -+ struct regmap *regmap; -+ u32 reg; -+ u32 mask; - }; - - /** -@@ -59,18 +91,32 @@ struct stm32_adc_priv_cfg { - * @domain: irq domain reference - * @aclk: clock reference for the analog circuitry - * @bclk: bus clock common for all ADCs, depends on part used -+ * @max_clk_rate desired maximum clock rate - * @vref: regulator reference - * @cfg: compatible configuration data - * @common: common data for all ADC instances -+ * @ccr_bak: backup'ed CCR in low power mode -+ * @vbooster: BOOSTE syscfg / EN_BOOSTER syscfg set -+ * @vbooster_clr: EN_BOOSTER syscfg clear -+ * @anaswvdd: ANASWVDD syscfg set -+ * @anaswvdd_clr: ANASWVDD syscfg clear - */ - struct stm32_adc_priv { - int irq[STM32_ADC_MAX_ADCS]; - struct irq_domain *domain; - struct clk *aclk; - struct clk *bclk; -+ u32 max_clk_rate; -+ struct regulator *vdd; -+ struct regulator *vdda; - struct regulator *vref; - const struct stm32_adc_priv_cfg *cfg; - struct stm32_adc_common common; -+ u32 ccr_bak; -+ struct stm32_adc_syscfg vbooster; -+ struct stm32_adc_syscfg vbooster_clr; -+ struct stm32_adc_syscfg anaswvdd; -+ struct stm32_adc_syscfg anaswvdd_clr; - }; - - static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) -@@ -106,7 +152,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, - } - - for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { -- if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz) -+ if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate) - break; - } - if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { -@@ -195,7 +241,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - if (ckmode) - continue; - -- if ((rate / div) <= priv->cfg->max_clk_rate_hz) -+ if ((rate / div) <= priv->max_clk_rate) - goto out; - } - } -@@ -215,7 +261,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - if (!ckmode) - continue; - -- if ((rate / div) <= priv->cfg->max_clk_rate_hz) -+ if ((rate / div) <= priv->max_clk_rate) - goto out; - } - -@@ -242,9 +288,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, - /* STM32F4 common registers definitions */ - static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { - .csr = STM32F4_ADC_CSR, -- .eoc1_msk = STM32F4_EOC1, -- .eoc2_msk = STM32F4_EOC2, -- .eoc3_msk = STM32F4_EOC3, -+ .ccr = STM32F4_ADC_CCR, -+ .eoc1_msk = STM32F4_EOC_MASK1, -+ .eoc2_msk = STM32F4_EOC_MASK2, -+ .eoc3_msk = STM32F4_EOC_MASK3, -+ .jeoc1_msk = STM32F4_JEOC_MASK1, -+ .jeoc2_msk = STM32F4_JEOC_MASK2, -+ .jeoc3_msk = STM32F4_JEOC_MASK3, - .ier = STM32F4_ADC_CR1, - .eocie_msk = STM32F4_EOCIE, - }; -@@ -252,8 +302,11 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { - /* STM32H7 common registers definitions */ - static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { - .csr = STM32H7_ADC_CSR, -- .eoc1_msk = STM32H7_EOC_MST, -- .eoc2_msk = STM32H7_EOC_SLV, -+ .ccr = STM32H7_ADC_CCR, -+ .eoc1_msk = STM32H7_EOC_MASK1, -+ .eoc2_msk = STM32H7_EOC_MASK2, -+ .jeoc1_msk = STM32H7_JEOC_MASK1, -+ .jeoc2_msk = STM32H7_JEOC_MASK2, - .ier = STM32H7_ADC_IER, - .eocie_msk = STM32H7_EOCIE, - }; -@@ -306,6 +359,15 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) - stm32_adc_eoc_enabled(priv, 2)) - generic_handle_irq(irq_find_mapping(priv->domain, 2)); - -+ if (status & priv->cfg->regs->jeoc1_msk) -+ generic_handle_irq(irq_find_mapping(priv->domain, 3)); -+ -+ if (status & priv->cfg->regs->jeoc2_msk) -+ generic_handle_irq(irq_find_mapping(priv->domain, 4)); -+ -+ if (status & priv->cfg->regs->jeoc3_msk) -+ generic_handle_irq(irq_find_mapping(priv->domain, 5)); -+ - chained_irq_exit(chip, desc); - }; - -@@ -354,7 +416,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, - } - } - -- priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, -+ /* 2 interrupt sources per ADC instance: regular & injected */ -+ priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS * 2, 0, - &stm32_adc_domain_ops, - priv); - if (!priv->domain) { -@@ -378,7 +441,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, - int hwirq; - unsigned int i; - -- for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++) -+ for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS * 2; hwirq++) - irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); - irq_domain_remove(priv->domain); - -@@ -389,13 +452,415 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, - } - } - -+static struct stm32_adc_trig_info stm32f4_adc_exti_trigs[] = { -+ { "exti11", STM32_EXT15, 0, TRG_REGULAR }, -+ { "exti15", 0, STM32_EXT15, TRG_INJECTED }, -+ {}, -+}; -+ -+static struct stm32_adc_trig_info stm32h7_adc_exti_trigs[] = { -+ { "exti11", STM32_EXT6, 0, TRG_REGULAR }, -+ { "exti15", 0, STM32_EXT6, TRG_INJECTED }, -+ {}, -+}; -+ -+static int is_stm32_adc_child_dev(struct device *dev, void *data) -+{ -+ return dev == data; -+} -+ -+static int stm32_adc_validate_device(struct iio_trigger *trig, -+ struct iio_dev *indio_dev) -+{ -+ /* Iterate over stm32 adc child devices, is indio_dev one of them ? */ -+ if (device_for_each_child(trig->dev.parent, indio_dev->dev.parent, -+ is_stm32_adc_child_dev)) -+ return 0; -+ -+ return -EINVAL; -+} -+ -+static const struct iio_trigger_ops stm32_adc_trigger_ops = { -+ .validate_device = stm32_adc_validate_device, -+}; -+ -+static irqreturn_t stm32_adc_trigger_isr(int irq, void *p) -+{ -+ /* EXTI handler shouldn't be invoked, and isn't used */ -+ return IRQ_HANDLED; -+} -+ -+static struct iio_trigger *stm32_adc_trig_alloc_register( -+ struct platform_device *pdev, -+ struct stm32_adc_priv *priv, -+ struct stm32_adc_trig_info *trinfo) -+{ -+ struct iio_trigger *trig; -+ int ret; -+ -+ trig = devm_iio_trigger_alloc(&pdev->dev, "%s-%s", trinfo->name, -+ dev_name(&pdev->dev)); -+ if (!trig) -+ return ERR_PTR(-ENOMEM); -+ -+ trig->dev.parent = &pdev->dev; -+ trig->ops = &stm32_adc_trigger_ops; -+ iio_trigger_set_drvdata(trig, trinfo); -+ -+ ret = devm_iio_trigger_register(&pdev->dev, trig); -+ if (ret) { -+ dev_err(&pdev->dev, "%s trig register failed\n", trinfo->name); -+ return ERR_PTR(ret); -+ } -+ -+ list_add_tail(&trig->alloc_list, &priv->common.extrig_list); -+ -+ return trig; -+} -+ -+static int stm32_adc_triggers_probe(struct platform_device *pdev, -+ struct stm32_adc_priv *priv) -+{ -+ struct device_node *child, *node = pdev->dev.of_node; -+ struct stm32_adc_trig_info *trinfo = priv->cfg->exti_trigs; -+ struct iio_trigger *trig; -+ int i, irq, ret; -+ -+ INIT_LIST_HEAD(&priv->common.extrig_list); -+ -+ for (i = 0; trinfo && trinfo[i].name; i++) { -+ for_each_available_child_of_node(node, child) { -+ if (of_property_match_string(child, "trigger-name", -+ trinfo[i].name) < 0) -+ continue; -+ trig = stm32_adc_trig_alloc_register(pdev, priv, -+ &trinfo[i]); -+ if (IS_ERR(trig)) -+ return PTR_ERR(trig); -+ -+ /* -+ * STM32 ADC can use EXTI GPIO (external interrupt line) -+ * as trigger source. EXTI line can generate IRQs and/or -+ * be used as trigger: EXTI line is hard wired as -+ * an input of ADC trigger selection MUX (muxed in with -+ * extsel on ADC controller side). -+ * Getting IRQs when trigger occurs is unused, rely on -+ * EOC interrupt instead. So, get EXTI IRQ, then mask it -+ * by default (on EXTI controller). After this, EXTI -+ * line HW path is configured (GPIO->EXTI->ADC), -+ */ -+ irq = of_irq_get(child, 0); -+ if (irq <= 0) { -+ dev_err(&pdev->dev, "Can't get trigger irq\n"); -+ return irq ? irq : -ENODEV; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, irq, -+ stm32_adc_trigger_isr, 0, NULL, -+ trig); -+ if (ret) { -+ dev_err(&pdev->dev, "Request IRQ failed\n"); -+ return ret; -+ } -+ disable_irq(irq); -+ } -+ } -+ -+ return 0; -+} -+ -+static int stm32_adc_switches_supply_en(struct device *dev) -+{ -+ struct stm32_adc_common *common = dev_get_drvdata(dev); -+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common); -+ int ret, vdda, vdd = 0; -+ u32 anaswvdd, en_booster; -+ -+ /* -+ * On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog -+ * switches (e.g. PCSEL) which have reduced performances when their -+ * supply is below 2.7V (vdda by default): -+ * - Voltage booster can be used, to get full ADC performances -+ * (increases power consumption). -+ * - Vdd can be used if above 2.7V (STM32MP1 only). -+ * -+ * Make all this optional, since this is a trade-off between analog -+ * performance and power consumption. -+ */ -+ if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap)) { -+ dev_dbg(dev, "%s: nothing to do\n", __func__); -+ return 0; -+ } -+ -+ ret = regulator_enable(priv->vdda); -+ if (ret < 0) { -+ dev_err(dev, "vdda enable failed %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_get_voltage(priv->vdda); -+ if (ret < 0) { -+ dev_err(dev, "vdda get voltage failed %d\n", ret); -+ goto vdda_dis; -+ } -+ vdda = ret; -+ -+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) { -+ ret = regulator_enable(priv->vdd); -+ if (ret < 0) { -+ dev_err(dev, "vdd enable failed %d\n", ret); -+ goto vdda_dis; -+ } -+ -+ ret = regulator_get_voltage(priv->vdd); -+ if (ret < 0) { -+ dev_err(dev, "vdd get voltage failed %d\n", ret); -+ goto vdd_dis; -+ } -+ vdd = ret; -+ } -+ -+ /* -+ * Recommended settings for ANASWVDD and EN_BOOSTER: -+ * - vdda > 2.7V: ANASWVDD = 0, EN_BOOSTER = 0 -+ * - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1 -+ * - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1) -+ */ -+ if (vdda > 2700000) { -+ /* analog switches supplied by vdda (default) */ -+ anaswvdd = 0; -+ en_booster = 0; -+ } else { -+ if (vdd < 2700000) { -+ /* Voltage booster enabled */ -+ anaswvdd = 0; -+ en_booster = priv->vbooster.mask; -+ } else { -+ /* analog switches supplied by vdd */ -+ anaswvdd = priv->anaswvdd.mask; -+ en_booster = 0; -+ } -+ } -+ -+ dev_dbg(dev, "vdda=%d, vdd=%d, setting: en_booster=%x, anaswvdd=%x\n", -+ vdda, vdd, en_booster, anaswvdd); -+ -+ /* direct write en_booster value (or use clear register) */ -+ if (en_booster || IS_ERR(priv->vbooster_clr.regmap)) -+ ret = regmap_update_bits(priv->vbooster.regmap, -+ priv->vbooster.reg, -+ priv->vbooster.mask, en_booster); -+ else -+ ret = regmap_write(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask); -+ if (ret) { -+ dev_err(dev, "can't access voltage booster, %d\n", ret); -+ goto vdd_dis; -+ } -+ -+ /* Booster voltage can take up to 50 μs to stabilize */ -+ if (en_booster) -+ usleep_range(50, 100); -+ -+ if (!IS_ERR(priv->anaswvdd.regmap)) { -+ /* direct write anaswvdd value (or use clear register) */ -+ if (anaswvdd || IS_ERR(priv->anaswvdd_clr.regmap)) -+ ret = regmap_update_bits(priv->anaswvdd.regmap, -+ priv->anaswvdd.reg, -+ priv->anaswvdd.mask, anaswvdd); -+ else -+ ret = regmap_write(priv->anaswvdd_clr.regmap, -+ priv->anaswvdd_clr.reg, -+ priv->anaswvdd_clr.mask); -+ if (ret) { -+ dev_err(dev, "can't access anaswvdd, %d\n", ret); -+ goto booster_dis; -+ } -+ } -+ -+ return ret; -+ -+booster_dis: -+ if (IS_ERR(priv->vbooster_clr.regmap)) -+ regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg, -+ priv->vbooster.mask, 0); -+ else -+ regmap_write(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask); -+vdd_dis: -+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) -+ regulator_disable(priv->vdd); -+vdda_dis: -+ regulator_disable(priv->vdda); -+ -+ return ret; -+} -+ -+static void stm32_adc_switches_supply_dis(struct device *dev) -+{ -+ struct stm32_adc_common *common = dev_get_drvdata(dev); -+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common); -+ -+ if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap)) -+ return; -+ -+ if (!IS_ERR(priv->anaswvdd.regmap)) { -+ if (IS_ERR(priv->anaswvdd_clr.regmap)) -+ regmap_update_bits(priv->anaswvdd.regmap, -+ priv->anaswvdd.reg, -+ priv->anaswvdd.mask, 0); -+ else -+ regmap_write(priv->anaswvdd_clr.regmap, -+ priv->anaswvdd_clr.reg, -+ priv->anaswvdd_clr.mask); -+ } -+ -+ if (IS_ERR(priv->vbooster_clr.regmap)) -+ regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg, -+ priv->vbooster.mask, 0); -+ else -+ regmap_write(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask); -+ -+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) -+ regulator_disable(priv->vdd); -+ -+ regulator_disable(priv->vdda); -+} -+ -+static int stm32_adc_core_hw_start(struct device *dev) -+{ -+ struct stm32_adc_common *common = dev_get_drvdata(dev); -+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common); -+ int ret; -+ -+ ret = stm32_adc_switches_supply_en(dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = regulator_enable(priv->vref); -+ if (ret < 0) { -+ dev_err(dev, "vref enable failed\n"); -+ goto err_switches_disable; -+ } -+ -+ if (priv->bclk) { -+ ret = clk_prepare_enable(priv->bclk); -+ if (ret < 0) { -+ dev_err(dev, "bus clk enable failed\n"); -+ goto err_regulator_disable; -+ } -+ } -+ -+ if (priv->aclk) { -+ ret = clk_prepare_enable(priv->aclk); -+ if (ret < 0) { -+ dev_err(dev, "adc clk enable failed\n"); -+ goto err_bclk_disable; -+ } -+ } -+ -+ writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr); -+ -+ return 0; -+ -+err_bclk_disable: -+ if (priv->bclk) -+ clk_disable_unprepare(priv->bclk); -+err_regulator_disable: -+ regulator_disable(priv->vref); -+err_switches_disable: -+ stm32_adc_switches_supply_dis(dev); -+ -+ return ret; -+} -+ -+static void stm32_adc_core_hw_stop(struct device *dev) -+{ -+ struct stm32_adc_common *common = dev_get_drvdata(dev); -+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common); -+ -+ /* Backup CCR that may be lost (depends on power state to achieve) */ -+ priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr); -+ if (priv->aclk) -+ clk_disable_unprepare(priv->aclk); -+ if (priv->bclk) -+ clk_disable_unprepare(priv->bclk); -+ regulator_disable(priv->vref); -+ stm32_adc_switches_supply_dis(dev); -+} -+ -+static int stm32_adc_get_syscfg_cell(struct device_node *np, -+ struct stm32_adc_syscfg *syscfg, -+ const char * prop) -+{ -+ int ret; -+ -+ syscfg->regmap = syscon_regmap_lookup_by_phandle(np, prop); -+ if (IS_ERR(syscfg->regmap)) { -+ /* Optional */ -+ if (PTR_ERR(syscfg->regmap) == -ENODEV) -+ return 0; -+ else -+ return PTR_ERR(syscfg->regmap); -+ } -+ -+ ret = of_property_read_u32_index(np, prop, 1, &syscfg->reg); -+ if (ret) -+ return ret; -+ -+ return of_property_read_u32_index(np, prop, 2, &syscfg->mask); -+} -+ -+static int stm32_adc_syscfg_probe(struct platform_device *pdev, -+ struct stm32_adc_priv *priv) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ int ret; -+ -+ /* Start to lookup BOOSTE/EN_BOOSTER first, for stm32h7/stm32mp1 */ -+ ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster, -+ "st,syscfg-vbooster"); -+ if (ret) -+ return ret; -+ -+ /* Continue with stm32mp1 EN_BOOSTER/ANASWVDD set and clear bits*/ -+ ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster_clr, -+ "st,syscfg-vbooster-clr"); -+ if (ret) -+ return ret; -+ -+ ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd, -+ "st,syscfg-anaswvdd"); -+ if (ret) -+ return ret; -+ -+ ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd_clr, -+ "st,syscfg-anaswvdd-clr"); -+ if (ret) -+ return ret; -+ -+ /* Sanity, check syscfg set/clear pairs are filled in */ -+ if (priv->cfg->has_syscfg_clr && ((!IS_ERR(priv->vbooster.regmap) && -+ IS_ERR(priv->vbooster_clr.regmap)) || -+ (!IS_ERR(priv->anaswvdd.regmap) && -+ IS_ERR(priv->anaswvdd_clr.regmap)))) -+ return -EINVAL; -+ -+ return ret; -+} -+ - static int stm32_adc_probe(struct platform_device *pdev) - { - struct stm32_adc_priv *priv; - struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; - struct resource *res; -- int ret; -+ u32 max_rate; -+ int i, ret; - - if (!pdev->dev.of_node) - return -ENODEV; -@@ -403,6 +868,7 @@ static int stm32_adc_probe(struct platform_device *pdev) - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; -+ platform_set_drvdata(pdev, &priv->common); - - priv->cfg = (const struct stm32_adc_priv_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; -@@ -412,6 +878,8 @@ static int stm32_adc_probe(struct platform_device *pdev) - if (IS_ERR(priv->common.base)) - return PTR_ERR(priv->common.base); - priv->common.phys_base = res->start; -+ for (i = 0; i < STM32_ADC_MAX_ADCS; i++) -+ mutex_init(&priv->common.inj[i]); - - priv->vref = devm_regulator_get(&pdev->dev, "vref"); - if (IS_ERR(priv->vref)) { -@@ -420,67 +888,87 @@ static int stm32_adc_probe(struct platform_device *pdev) - return ret; - } - -- ret = regulator_enable(priv->vref); -- if (ret < 0) { -- dev_err(&pdev->dev, "vref enable failed\n"); -- return ret; -+ priv->vdda = devm_regulator_get_optional(&pdev->dev, "vdda"); -+ if (IS_ERR(priv->vdda)) { -+ ret = PTR_ERR(priv->vdda); -+ if (ret != -ENODEV) { -+ dev_err(&pdev->dev, "vdda get failed, %d\n", ret); -+ return ret; -+ } - } - -- ret = regulator_get_voltage(priv->vref); -- if (ret < 0) { -- dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret); -- goto err_regulator_disable; -+ priv->vdd = devm_regulator_get_optional(&pdev->dev, "vdd"); -+ if (IS_ERR(priv->vdd)) { -+ ret = PTR_ERR(priv->vdd); -+ if (ret != -ENODEV) { -+ dev_err(&pdev->dev, "vdd get failed, %d\n", ret); -+ return ret; -+ } - } -- priv->common.vref_mv = ret / 1000; -- dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); - - priv->aclk = devm_clk_get(&pdev->dev, "adc"); - if (IS_ERR(priv->aclk)) { - ret = PTR_ERR(priv->aclk); -- if (ret == -ENOENT) { -- priv->aclk = NULL; -- } else { -+ if (ret != -ENOENT) { - dev_err(&pdev->dev, "Can't get 'adc' clock\n"); -- goto err_regulator_disable; -- } -- } -- -- if (priv->aclk) { -- ret = clk_prepare_enable(priv->aclk); -- if (ret < 0) { -- dev_err(&pdev->dev, "adc clk enable failed\n"); -- goto err_regulator_disable; -+ return ret; - } -+ priv->aclk = NULL; - } - - priv->bclk = devm_clk_get(&pdev->dev, "bus"); - if (IS_ERR(priv->bclk)) { - ret = PTR_ERR(priv->bclk); -- if (ret == -ENOENT) { -- priv->bclk = NULL; -- } else { -+ if (ret != -ENOENT) { - dev_err(&pdev->dev, "Can't get 'bus' clock\n"); -- goto err_aclk_disable; -+ return ret; - } -+ priv->bclk = NULL; - } - -- if (priv->bclk) { -- ret = clk_prepare_enable(priv->bclk); -- if (ret < 0) { -- dev_err(&pdev->dev, "adc clk enable failed\n"); -- goto err_aclk_disable; -- } -+ ret = stm32_adc_syscfg_probe(pdev, priv); -+ if (ret) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Can't probe syscfg: %d\n", ret); -+ return ret; -+ } -+ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_enable(dev); -+ -+ ret = stm32_adc_core_hw_start(dev); -+ if (ret) -+ goto err_pm_stop; -+ -+ ret = regulator_get_voltage(priv->vref); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret); -+ goto err_hw_stop; - } -+ priv->common.vref_mv = ret / 1000; -+ dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); -+ -+ ret = of_property_read_u32(pdev->dev.of_node, "st,max-clk-rate-hz", -+ &max_rate); -+ if (!ret) -+ priv->max_clk_rate = min(max_rate, priv->cfg->max_clk_rate_hz); -+ else -+ priv->max_clk_rate = priv->cfg->max_clk_rate_hz; - - ret = priv->cfg->clk_sel(pdev, priv); - if (ret < 0) -- goto err_bclk_disable; -+ goto err_hw_stop; - - ret = stm32_adc_irq_probe(pdev, priv); - if (ret < 0) -- goto err_bclk_disable; -+ goto err_hw_stop; - -- platform_set_drvdata(pdev, &priv->common); -+ ret = stm32_adc_triggers_probe(pdev, priv); -+ if (ret < 0) -+ goto err_irq_remove; - - ret = of_platform_populate(np, NULL, NULL, &pdev->dev); - if (ret < 0) { -@@ -488,21 +976,19 @@ static int stm32_adc_probe(struct platform_device *pdev) - goto err_irq_remove; - } - -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ - return 0; - - err_irq_remove: - stm32_adc_irq_remove(pdev, priv); -- --err_bclk_disable: -- if (priv->bclk) -- clk_disable_unprepare(priv->bclk); -- --err_aclk_disable: -- if (priv->aclk) -- clk_disable_unprepare(priv->aclk); -- --err_regulator_disable: -- regulator_disable(priv->vref); -+err_hw_stop: -+ stm32_adc_core_hw_stop(dev); -+err_pm_stop: -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); - - return ret; - } -@@ -512,33 +998,59 @@ static int stm32_adc_remove(struct platform_device *pdev) - struct stm32_adc_common *common = platform_get_drvdata(pdev); - struct stm32_adc_priv *priv = to_stm32_adc_priv(common); - -+ pm_runtime_get_sync(&pdev->dev); - of_platform_depopulate(&pdev->dev); - stm32_adc_irq_remove(pdev, priv); -- if (priv->bclk) -- clk_disable_unprepare(priv->bclk); -- if (priv->aclk) -- clk_disable_unprepare(priv->aclk); -- regulator_disable(priv->vref); -+ stm32_adc_core_hw_stop(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_PM) -+static int stm32_adc_core_runtime_suspend(struct device *dev) -+{ -+ stm32_adc_core_hw_stop(dev); - - return 0; - } - -+static int stm32_adc_core_runtime_resume(struct device *dev) -+{ -+ return stm32_adc_core_hw_start(dev); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_adc_core_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend, -+ stm32_adc_core_runtime_resume, -+ NULL) -+}; -+ - static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { - .regs = &stm32f4_adc_common_regs, - .clk_sel = stm32f4_adc_clk_sel, - .max_clk_rate_hz = 36000000, -+ .exti_trigs = stm32f4_adc_exti_trigs, - }; - - static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { - .regs = &stm32h7_adc_common_regs, - .clk_sel = stm32h7_adc_clk_sel, - .max_clk_rate_hz = 36000000, -+ .exti_trigs = stm32h7_adc_exti_trigs, - }; - - static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { - .regs = &stm32h7_adc_common_regs, - .clk_sel = stm32h7_adc_clk_sel, -+ .has_syscfg_clr = true, - .max_clk_rate_hz = 40000000, -+ .exti_trigs = stm32h7_adc_exti_trigs, - }; - - static const struct of_device_id stm32_adc_of_match[] = { -@@ -562,6 +1074,7 @@ static struct platform_driver stm32_adc_driver = { - .driver = { - .name = "stm32-adc-core", - .of_match_table = stm32_adc_of_match, -+ .pm = &stm32_adc_core_pm_ops, - }, - }; - module_platform_driver(stm32_adc_driver); -diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h -index 2579d51..3eacb06 100644 ---- a/drivers/iio/adc/stm32-adc-core.h -+++ b/drivers/iio/adc/stm32-adc-core.h -@@ -51,14 +51,26 @@ - #define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) - - /* STM32F4_ADC_SR - bit fields */ -+#define STM32F4_OVR BIT(5) - #define STM32F4_STRT BIT(4) -+#define STM32F4_JSTRT BIT(3) -+#define STM32F4_JEOC BIT(2) - #define STM32F4_EOC BIT(1) -+#define STM32F4_AWD BIT(0) - - /* STM32F4_ADC_CR1 - bit fields */ -+#define STM32F4_OVRIE BIT(26) - #define STM32F4_RES_SHIFT 24 - #define STM32F4_RES_MASK GENMASK(25, 24) -+#define STM32F4_AWDEN BIT(23) -+#define STM32F4_JAWDEN BIT(22) -+#define STM32F4_AWDSGL BIT(9) - #define STM32F4_SCAN BIT(8) -+#define STM32F4_JEOCIE BIT(7) -+#define STM32F4_AWDIE BIT(6) - #define STM32F4_EOCIE BIT(5) -+#define STM32F4_AWDCH_SHIFT 0 -+#define STM32F4_AWDCH_MASK GENMASK(4, 0) - - /* STM32F4_ADC_CR2 - bit fields */ - #define STM32F4_SWSTART BIT(30) -@@ -66,17 +78,41 @@ - #define STM32F4_EXTEN_MASK GENMASK(29, 28) - #define STM32F4_EXTSEL_SHIFT 24 - #define STM32F4_EXTSEL_MASK GENMASK(27, 24) -+#define STM32F4_JSWSTART BIT(22) -+#define STM32F4_JEXTEN_SHIFT 20 -+#define STM32F4_JEXTEN_MASK GENMASK(21, 20) -+#define STM32F4_JEXTSEL_SHIFT 16 -+#define STM32F4_JEXTSEL_MASK GENMASK(19, 16) - #define STM32F4_EOCS BIT(10) - #define STM32F4_DDS BIT(9) - #define STM32F4_DMA BIT(8) - #define STM32F4_ADON BIT(0) - - /* STM32F4_ADC_CSR - bit fields */ -+#define STM32F4_OVR3 BIT(21) -+#define STM32F4_JEOC3 BIT(18) - #define STM32F4_EOC3 BIT(17) -+#define STM32F4_AWD3 BIT(16) -+#define STM32F4_OVR2 BIT(13) -+#define STM32F4_JEOC2 BIT(10) - #define STM32F4_EOC2 BIT(9) -+#define STM32F4_AWD2 BIT(8) -+#define STM32F4_OVR1 BIT(5) -+#define STM32F4_JEOC1 BIT(2) - #define STM32F4_EOC1 BIT(1) -+#define STM32F4_AWD1 BIT(0) -+#define STM32F4_EOC_MASK1 (STM32F4_EOC1 | STM32F4_AWD1 | \ -+ STM32F4_OVR1) -+#define STM32F4_EOC_MASK2 (STM32F4_EOC2 | STM32F4_AWD2 | \ -+ STM32F4_OVR2) -+#define STM32F4_EOC_MASK3 (STM32F4_EOC3 | STM32F4_AWD3 | \ -+ STM32F4_OVR3) -+#define STM32F4_JEOC_MASK1 (STM32F4_JEOC1 | STM32F4_AWD1) -+#define STM32F4_JEOC_MASK2 (STM32F4_JEOC2 | STM32F4_AWD2) -+#define STM32F4_JEOC_MASK3 (STM32F4_JEOC3 | STM32F4_AWD3) - - /* STM32F4_ADC_CCR - bit fields */ -+#define STM32F4_ADC_TSVREFE BIT(23) - #define STM32F4_ADC_ADCPRE_SHIFT 16 - #define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) - -@@ -88,11 +124,24 @@ - #define STM32H7_ADC_SMPR1 0x14 - #define STM32H7_ADC_SMPR2 0x18 - #define STM32H7_ADC_PCSEL 0x1C -+#define STM32H7_ADC_LTR1 0x20 -+#define STM32H7_ADC_HTR1 0x24 - #define STM32H7_ADC_SQR1 0x30 - #define STM32H7_ADC_SQR2 0x34 - #define STM32H7_ADC_SQR3 0x38 - #define STM32H7_ADC_SQR4 0x3C - #define STM32H7_ADC_DR 0x40 -+#define STM32H7_ADC_JSQR 0x4C -+#define STM32H7_ADC_JDR1 0x80 -+#define STM32H7_ADC_JDR2 0x84 -+#define STM32H7_ADC_JDR3 0x88 -+#define STM32H7_ADC_JDR4 0x8C -+#define STM32H7_ADC_AWD2CR 0xA0 -+#define STM32H7_ADC_AWD3CR 0xA4 -+#define STM32H7_ADC_LTR2 0xB0 -+#define STM32H7_ADC_HTR2 0xB4 -+#define STM32H7_ADC_LTR3 0xB8 -+#define STM32H7_ADC_HTR3 0xBC - #define STM32H7_ADC_DIFSEL 0xC0 - #define STM32H7_ADC_CALFACT 0xC4 - #define STM32H7_ADC_CALFACT2 0xC8 -@@ -103,10 +152,20 @@ - - /* STM32H7_ADC_ISR - bit fields */ - #define STM32MP1_VREGREADY BIT(12) -+#define STM32H7_AWD3 BIT(9) -+#define STM32H7_AWD2 BIT(8) -+#define STM32H7_AWD1 BIT(7) -+#define STM32H7_JEOS BIT(6) -+#define STM32H7_OVR BIT(4) - #define STM32H7_EOC BIT(2) - #define STM32H7_ADRDY BIT(0) - - /* STM32H7_ADC_IER - bit fields */ -+#define STM32H7_AWD3IE STM32H7_AWD3 -+#define STM32H7_AWD2IE STM32H7_AWD2 -+#define STM32H7_AWD1IE STM32H7_AWD1 -+#define STM32H7_JEOSIE STM32H7_JEOS -+#define STM32H7_OVRIE STM32H7_OVR - #define STM32H7_EOCIE STM32H7_EOC - - /* STM32H7_ADC_CR - bit fields */ -@@ -122,12 +181,19 @@ - #define STM32H7_LINCALRDYW1 BIT(22) - #define STM32H7_ADCALLIN BIT(16) - #define STM32H7_BOOST BIT(8) -+#define STM32H7_JADSTP BIT(5) - #define STM32H7_ADSTP BIT(4) -+#define STM32H7_JADSTART BIT(3) - #define STM32H7_ADSTART BIT(2) - #define STM32H7_ADDIS BIT(1) - #define STM32H7_ADEN BIT(0) - - /* STM32H7_ADC_CFGR bit fields */ -+#define STM32H7_AWD1CH_SHIFT 26 -+#define STM32H7_AWD1CH_MASK GENMASK(30, 26) -+#define STM32H7_JAWD1EN BIT(24) -+#define STM32H7_AWD1EN BIT(23) -+#define STM32H7_AWD1SGL BIT(22) - #define STM32H7_EXTEN_SHIFT 10 - #define STM32H7_EXTEN_MASK GENMASK(11, 10) - #define STM32H7_EXTSEL_SHIFT 5 -@@ -144,6 +210,12 @@ enum stm32h7_adc_dmngt { - STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */ - }; - -+/* STM32H7_ADC_JSQR - bit fields */ -+#define STM32H7_JEXTEN_SHIFT 7 -+#define STM32H7_JEXTEN_MASK GENMASK(8, 7) -+#define STM32H7_JEXTSEL_SHIFT 2 -+#define STM32H7_JEXTSEL_MASK GENMASK(6, 2) -+ - /* STM32H7_ADC_CALFACT - bit fields */ - #define STM32H7_CALFACT_D_SHIFT 16 - #define STM32H7_CALFACT_D_MASK GENMASK(26, 16) -@@ -155,27 +227,125 @@ enum stm32h7_adc_dmngt { - #define STM32H7_LINCALFACT_MASK GENMASK(29, 0) - - /* STM32H7_ADC_CSR - bit fields */ -+#define STM32H7_AWD3_SLV BIT(25) -+#define STM32H7_AWD2_SLV BIT(24) -+#define STM32H7_AWD1_SLV BIT(23) -+#define STM32H7_JEOS_SLV BIT(22) -+#define STM32H7_OVR_SLV BIT(20) - #define STM32H7_EOC_SLV BIT(18) -+#define STM32H7_AWD3_MST BIT(9) -+#define STM32H7_AWD2_MST BIT(8) -+#define STM32H7_AWD1_MST BIT(7) -+#define STM32H7_JEOS_MST BIT(6) -+#define STM32H7_OVR_MST BIT(4) - #define STM32H7_EOC_MST BIT(2) -+#define STM32H7_EOC_MASK1 (STM32H7_EOC_MST | STM32H7_AWD1_MST | \ -+ STM32H7_AWD2_MST | STM32H7_AWD3_MST | \ -+ STM32H7_OVR_MST) -+#define STM32H7_EOC_MASK2 (STM32H7_EOC_SLV | STM32H7_AWD1_SLV | \ -+ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV | \ -+ STM32H7_OVR_SLV) -+#define STM32H7_JEOC_MASK1 (STM32H7_JEOS_MST | STM32H7_AWD1_MST | \ -+ STM32H7_AWD2_MST | STM32H7_AWD3_MST) -+#define STM32H7_JEOC_MASK2 (STM32H7_JEOS_SLV | STM32H7_AWD1_SLV | \ -+ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV) - - /* STM32H7_ADC_CCR - bit fields */ -+#define STM32H7_VSENSEEN BIT(23) - #define STM32H7_PRESC_SHIFT 18 - #define STM32H7_PRESC_MASK GENMASK(21, 18) - #define STM32H7_CKMODE_SHIFT 16 - #define STM32H7_CKMODE_MASK GENMASK(17, 16) - -+/* Number of linear calibration shadow registers / LINCALRDYW control bits */ -+#define STM32H7_LINCALFACT_NUM 6 -+ -+/** -+ * struct stm32_adc_calib - optional adc calibration data -+ * @calfact_s: Calibration offset for single ended channels -+ * @calfact_d: Calibration offset in differential -+ * @lincalfact: Linearity calibration factor -+ * @calibrated: Indicates calibration status -+ */ -+struct stm32_adc_calib { -+ u32 calfact_s; -+ u32 calfact_d; -+ u32 lincalfact[STM32H7_LINCALFACT_NUM]; -+ bool calibrated; -+}; -+ - /** - * struct stm32_adc_common - stm32 ADC driver common data (for all instances) - * @base: control registers base cpu addr - * @phys_base: control registers base physical addr - * @rate: clock rate used for analog circuitry - * @vref_mv: vref voltage (mv) -+ * @extrig_list: External trigger list registered by adc core -+ * -+ * Reserved variables for child devices, shared between regular/injected: -+ * @difsel bitmask array to set single-ended/differential channel -+ * @pcsel bitmask array to preselect channels on some devices -+ * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) -+ * @prepcnt: counter to manage prepare() calls concurrency -+ * @inj: mutex to protect regular/injected concurrency -+ * @cal: optional calibration data on some devices - */ - struct stm32_adc_common { - void __iomem *base; - phys_addr_t phys_base; - unsigned long rate; - int vref_mv; -+ struct list_head extrig_list; -+ u32 difsel[STM32_ADC_MAX_ADCS]; -+ u32 pcsel[STM32_ADC_MAX_ADCS]; -+ u32 smpr_val[STM32_ADC_MAX_ADCS][2]; -+ int prepcnt[STM32_ADC_MAX_ADCS]; -+ struct mutex inj[STM32_ADC_MAX_ADCS]; /* injected */ -+ struct stm32_adc_calib cal[STM32_ADC_MAX_ADCS]; -+}; -+ -+/* extsel - trigger mux selection value */ -+enum stm32_adc_extsel { -+ STM32_EXT0, -+ STM32_EXT1, -+ STM32_EXT2, -+ STM32_EXT3, -+ STM32_EXT4, -+ STM32_EXT5, -+ STM32_EXT6, -+ STM32_EXT7, -+ STM32_EXT8, -+ STM32_EXT9, -+ STM32_EXT10, -+ STM32_EXT11, -+ STM32_EXT12, -+ STM32_EXT13, -+ STM32_EXT14, -+ STM32_EXT15, -+ STM32_EXT16, -+ STM32_EXT17, -+ STM32_EXT18, -+ STM32_EXT19, -+ STM32_EXT20, -+}; -+ -+/* trigger information flags */ -+#define TRG_REGULAR BIT(0) -+#define TRG_INJECTED BIT(1) -+#define TRG_BOTH (TRG_REGULAR | TRG_INJECTED) -+ -+/** -+ * struct stm32_adc_trig_info - ADC trigger info -+ * @name: name of the trigger, corresponding to its source -+ * @extsel: regular trigger selection -+ * @jextsel: injected trigger selection -+ * @flags: trigger flags: e.g. for regular, injected or both -+ */ -+struct stm32_adc_trig_info { -+ const char *name; -+ u32 extsel; -+ u32 jextsel; -+ u32 flags; - }; - - #endif -diff --git a/drivers/iio/adc/stm32-adc-temp.c b/drivers/iio/adc/stm32-adc-temp.c -new file mode 100644 -index 0000000..dd31916 ---- /dev/null -+++ b/drivers/iio/adc/stm32-adc-temp.c -@@ -0,0 +1,412 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * STM32 ADC temperature sensor driver. -+ * This file is part of STM32 ADC driver. -+ * -+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved -+ * Author: Fabrice Gasnier for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "stm32-adc-core.h" -+ -+#define STM32_ADC_TEMP_SUSPEND_DELAY_MS 2000 -+ -+/* -+ * stm32_adc_temp_cfg - stm32 temperature compatible configuration data -+ * @avg_slope: temp sensor average slope (uV/deg: from datasheet) -+ * @ts: temp sensor sample temperature (°C: from datasheet) -+ * @vts: temp sensor voltage @ts (mV: V25 or V30 in datasheet) -+ * @en_bit: temp sensor enable bits -+ * @en_reg: temp sensor enable register -+ * @ts_cal_bits: temp sensor ts_cal[1..2] raw resolution (bits) -+ * @t1: ts_cal1 sample temperature (°C: from datasheet) -+ * @t2: ts_cal2 sample temperature (°C: from datasheet) -+ */ -+struct stm32_adc_temp_cfg { -+ unsigned int avg_slope; -+ unsigned int ts; -+ unsigned int vts; -+ unsigned int en_bit; -+ unsigned int en_reg; -+ unsigned int ts_cal_bits; -+ unsigned int t1; -+ unsigned int t2; -+}; -+ -+/* -+ * stm32_adc_temp - private data of STM32 ADC temperature sensor driver -+ * @base: control registers base cpu addr -+ * @cfg: compatible configuration data -+ * @temp_offset: temperature sensor offset -+ * @temp_scale: temperature sensor scale -+ * @realbits: adc resolution -+ * @ts_chan temperature sensor ADC channel (consumer) -+ * @tzd: thermal zone device -+ */ -+struct stm32_adc_temp { -+ void __iomem *base; -+ const struct stm32_adc_temp_cfg *cfg; -+ int temp_offset; -+ int temp_scale; -+ int realbits; -+ struct iio_channel *ts_chan; -+ struct thermal_zone_device *tzd; -+}; -+ -+static const struct iio_chan_spec stm32_adc_temp_channel = { -+ .type = IIO_TEMP, -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | -+ BIT(IIO_CHAN_INFO_SCALE) | -+ BIT(IIO_CHAN_INFO_OFFSET), -+ .datasheet_name = "adc_temp", -+}; -+ -+static int stm32_adc_temp_get_temp(void *data, int *temp) -+{ -+ struct stm32_adc_temp *priv = data; -+ struct iio_dev *indio_dev = iio_priv_to_dev(priv); -+ struct device *dev = indio_dev->dev.parent; -+ s64 val64; -+ int sense, ret; -+ -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ -+ ret = iio_read_channel_raw(priv->ts_chan, &sense); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ if (ret != IIO_VAL_INT) -+ return ret < 0 ? ret : -EINVAL; -+ -+ val64 = (s64)(sense + priv->temp_offset) * priv->temp_scale; -+ *temp = val64 >> priv->realbits; -+ -+ return 0; -+} -+ -+static const struct thermal_zone_of_device_ops stm32_adc_tzd_ops = { -+ .get_temp = &stm32_adc_temp_get_temp, -+}; -+ -+static int stm32_adc_temp_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, -+ int *val, int *val2, long mask) -+{ -+ struct stm32_adc_temp *priv = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; -+ int ret; -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_RAW: -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ ret = iio_read_channel_raw(priv->ts_chan, val); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ return ret; -+ -+ case IIO_CHAN_INFO_SCALE: -+ *val = priv->temp_scale; -+ *val2 = priv->realbits; -+ return IIO_VAL_FRACTIONAL_LOG2; -+ -+ case IIO_CHAN_INFO_OFFSET: -+ *val = priv->temp_offset; -+ return IIO_VAL_INT; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct iio_info stm32_adc_temp_iio_info = { -+ .read_raw = stm32_adc_temp_read_raw, -+}; -+ -+static void stm32_adc_temp_set_enable_state(struct device *dev, bool en) -+{ -+ struct stm32_adc_temp *priv = dev_get_drvdata(dev); -+ u32 val = readl_relaxed(priv->base + priv->cfg->en_reg); -+ -+ if (en) -+ val |= priv->cfg->en_bit; -+ else -+ val &= ~priv->cfg->en_bit; -+ writel_relaxed(val, priv->base + priv->cfg->en_reg); -+ -+ /* -+ * Temperature sensor "startup time" from datasheet, must be greater -+ * than slowest supported device. -+ */ -+ if (en) -+ usleep_range(40, 50); -+} -+ -+static int stm32_adc_temp_setup_offset_scale(struct platform_device *pdev, -+ struct stm32_adc_temp *priv) -+{ -+ int scale_type, vref_mv, ret; -+ u16 ts_cal1 = 0, ts_cal2 = 0; -+ unsigned int slope, vts, ts; -+ u64 val64; -+ -+ scale_type = iio_read_channel_scale(priv->ts_chan, &vref_mv, -+ &priv->realbits); -+ if (scale_type != IIO_VAL_FRACTIONAL_LOG2) -+ return scale_type < 0 ? scale_type : -EINVAL; -+ -+ /* Optional read of temperature sensor calibration data */ -+ ret = nvmem_cell_read_u16(&pdev->dev, "ts_cal1", &ts_cal1); -+ if (ret && ret != -ENOENT && ret != -ENOSYS) -+ return ret; -+ ret = nvmem_cell_read_u16(&pdev->dev, "ts_cal2", &ts_cal2); -+ if (ret && ret != -ENOENT && ret != -ENOSYS) -+ return ret; -+ -+ if (!ts_cal1 || !ts_cal2) { -+ /* Use datasheet temperature sensor characteristics */ -+ slope = priv->cfg->avg_slope; -+ ts = priv->cfg->ts; -+ vts = priv->cfg->vts; -+ } else { -+ /* -+ * Compute average slope (µV/°C) from calibration data: -+ * - ts_cal1: raw data @t1(°C), factory vref = 3.3V -+ * - ts_cal2: raw data @t2(°C), factory vref = 3.3V -+ */ -+ slope = ts_cal2 - ts_cal1; -+ slope *= 3300000 / (priv->cfg->t2 - priv->cfg->t1); -+ slope >>= priv->cfg->ts_cal_bits; -+ ts = priv->cfg->t1; -+ vts = ts_cal1 * 3300; -+ vts >>= priv->cfg->ts_cal_bits; -+ } -+ -+ dev_dbg(&pdev->dev, "ts_cal1=%x ts_cal2=%x slope=%d vts=%d\n", -+ ts_cal1, ts_cal2, slope, vts); -+ -+ priv->temp_scale = vref_mv * 1000000 / slope; -+ -+ /* -+ * T (°C) = (Vsense - V25) / AVG_slope + 25. -+ * raw offset to subtract @0°C: Vts0 = V25 - 25 * AVG_slope -+ */ -+ val64 = ts << priv->realbits; -+ priv->temp_offset = div_u64(val64 * (u64)slope, 1000LL); -+ priv->temp_offset -= vts << priv->realbits; -+ priv->temp_offset /= vref_mv; -+ -+ return 0; -+} -+ -+static int stm32_adc_temp_probe(struct platform_device *pdev) -+{ -+ struct stm32_adc_common *common = dev_get_drvdata(pdev->dev.parent); -+ struct device *dev = &pdev->dev; -+ struct stm32_adc_temp *priv; -+ struct iio_dev *indio_dev; -+ int ret; -+ -+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); -+ if (!indio_dev) -+ return -ENOMEM; -+ -+ indio_dev->name = dev_name(dev); -+ indio_dev->dev.parent = dev; -+ indio_dev->dev.of_node = pdev->dev.of_node; -+ indio_dev->info = &stm32_adc_temp_iio_info; -+ indio_dev->modes = INDIO_DIRECT_MODE; -+ indio_dev->channels = &stm32_adc_temp_channel; -+ indio_dev->num_channels = 1; -+ -+ priv = iio_priv(indio_dev); -+ priv->base = common->base; -+ priv->cfg = (const struct stm32_adc_temp_cfg *) -+ of_match_device(dev->driver->of_match_table, dev)->data; -+ -+ priv->ts_chan = devm_iio_channel_get(dev, NULL); -+ platform_set_drvdata(pdev, priv); -+ if (IS_ERR(priv->ts_chan)) { -+ ret = PTR_ERR(priv->ts_chan); -+ dev_err(&indio_dev->dev, "Can't get temp channel: %d\n", ret); -+ return ret; -+ } -+ -+ ret = stm32_adc_temp_setup_offset_scale(pdev, priv); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Can't get offset/scale: %d\n", ret); -+ return ret; -+ } -+ -+ /* Get stm32-adc-core PM online */ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_TEMP_SUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_enable(dev); -+ -+ /* Power-on temperature sensor */ -+ stm32_adc_temp_set_enable_state(dev, true); -+ -+ ret = iio_device_register(indio_dev); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Can't register iio dev: %d\n", ret); -+ goto fail; -+ } -+ -+ priv->tzd = thermal_zone_of_sensor_register(dev, 0, priv, -+ &stm32_adc_tzd_ops); -+ /* Optional thermal zone device */ -+ if (IS_ERR(priv->tzd)) { -+ ret = PTR_ERR(priv->tzd); -+ if (ret != -ENOENT && ret != -ENODEV) { -+ dev_err(&indio_dev->dev, "Can't register thermal: %d\n", -+ ret); -+ goto unreg; -+ } -+ dev_dbg(&indio_dev->dev, "Not using thermal: %d\n", ret); -+ priv->tzd = NULL; -+ } -+ -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ -+ return 0; -+ -+unreg: -+ iio_device_unregister(indio_dev); -+ -+fail: -+ stm32_adc_temp_set_enable_state(dev, false); -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); -+ -+ return ret; -+} -+ -+static int stm32_adc_temp_remove(struct platform_device *pdev) -+{ -+ struct stm32_adc_temp *priv = platform_get_drvdata(pdev); -+ struct iio_dev *indio_dev = iio_priv_to_dev(priv); -+ -+ pm_runtime_get_sync(&pdev->dev); -+ if (priv->tzd) -+ thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd); -+ iio_device_unregister(indio_dev); -+ stm32_adc_temp_set_enable_state(&pdev->dev, false); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_PM) -+static int stm32_adc_temp_runtime_suspend(struct device *dev) -+{ -+ stm32_adc_temp_set_enable_state(dev, false); -+ -+ return 0; -+} -+ -+static int stm32_adc_temp_runtime_resume(struct device *dev) -+{ -+ stm32_adc_temp_set_enable_state(dev, true); -+ -+ return 0; -+} -+#endif -+ -+static const struct dev_pm_ops stm32_adc_temp_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(stm32_adc_temp_runtime_suspend, -+ stm32_adc_temp_runtime_resume, -+ NULL) -+}; -+ -+static const struct stm32_adc_temp_cfg stm32f4_adc_temp_cfg = { -+ .avg_slope = 2500, -+ .ts = 25, -+ .vts = 760, /* V25 from datasheet */ -+ .en_reg = STM32F4_ADC_CCR, -+ .en_bit = STM32F4_ADC_TSVREFE, -+ .ts_cal_bits = 12, -+ .t1 = 30, /* ts_cal1 @30°C */ -+ .t2 = 110, /* ts_cal2 @110°C */ -+}; -+ -+static const struct stm32_adc_temp_cfg stm32h7_adc_temp_cfg = { -+ .avg_slope = 2000, -+ .ts = 30, -+ .vts = 620, /* V30 from datasheet */ -+ .en_reg = STM32H7_ADC_CCR, -+ .en_bit = STM32H7_VSENSEEN, -+ .ts_cal_bits = 16, -+ .t1 = 30, /* ts_cal1 @30°C */ -+ .t2 = 110, /* ts_cal2 @110°C */ -+}; -+ -+/* TODO: update typical values when confirmed for stm32mp1 */ -+static const struct stm32_adc_temp_cfg stm32mp1_adc_temp_cfg = { -+ .avg_slope = 2050, -+ .ts = 30, -+ .vts = 620, /* V30 from datasheet */ -+ .en_reg = STM32H7_ADC_CCR, -+ .en_bit = STM32H7_VSENSEEN, -+ .ts_cal_bits = 16, -+ .t1 = 30, /* ts_cal1 @30°C */ -+ .t2 = 130, /* ts_cal2 @130°C */ -+}; -+ -+static const struct of_device_id stm32_adc_temp_of_match[] = { -+ { -+ .compatible = "st,stm32f4-adc-temp", -+ .data = (void *)&stm32f4_adc_temp_cfg, -+ }, -+ { -+ .compatible = "st,stm32h7-adc-temp", -+ .data = (void *)&stm32h7_adc_temp_cfg, -+ }, -+ { -+ .compatible = "st,stm32mp1-adc-temp", -+ .data = (void *)&stm32mp1_adc_temp_cfg, -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_adc_temp_of_match); -+ -+static struct platform_driver stm32_adc_temp_driver = { -+ .probe = stm32_adc_temp_probe, -+ .remove = stm32_adc_temp_remove, -+ .driver = { -+ .name = "stm32-adc-temp", -+ .of_match_table = of_match_ptr(stm32_adc_temp_of_match), -+ .pm = &stm32_adc_temp_pm_ops, -+ }, -+}; -+module_platform_driver(stm32_adc_temp_driver); -+ -+MODULE_AUTHOR("Fabrice Gasnier "); -+MODULE_DESCRIPTION("STMicroelectronics STM32 ADC Temperature IIO driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:stm32-adc-temp"); -diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c -index 0409dcf..55c8362 100644 ---- a/drivers/iio/adc/stm32-adc.c -+++ b/drivers/iio/adc/stm32-adc.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -20,25 +21,26 @@ - #include - #include - #include -+#include - #include - #include -+#include - #include - #include - - #include "stm32-adc-core.h" - --/* Number of linear calibration shadow registers / LINCALRDYW control bits */ --#define STM32H7_LINCALFACT_NUM 6 -- - /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ - #define STM32H7_BOOST_CLKRATE 20000000UL - - #define STM32_ADC_CH_MAX 20 /* max number of channels */ - #define STM32_ADC_CH_SZ 10 /* max channel name size */ - #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ -+#define STM32_ADC_MAX_JSQ 4 /* JSQ1..JSQ4 */ - #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ - #define STM32_ADC_TIMEOUT_US 100000 - #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) -+#define STM32_ADC_HW_STOP_DELAY_MS 100 - - #define STM32_DMA_BUFFER_SIZE PAGE_SIZE - -@@ -50,53 +52,6 @@ enum stm32_adc_exten { - STM32_EXTEN_HWTRIG_BOTH_EDGES, - }; - --/* extsel - trigger mux selection value */ --enum stm32_adc_extsel { -- STM32_EXT0, -- STM32_EXT1, -- STM32_EXT2, -- STM32_EXT3, -- STM32_EXT4, -- STM32_EXT5, -- STM32_EXT6, -- STM32_EXT7, -- STM32_EXT8, -- STM32_EXT9, -- STM32_EXT10, -- STM32_EXT11, -- STM32_EXT12, -- STM32_EXT13, -- STM32_EXT14, -- STM32_EXT15, -- STM32_EXT16, -- STM32_EXT17, -- STM32_EXT18, -- STM32_EXT19, -- STM32_EXT20, --}; -- --/** -- * struct stm32_adc_trig_info - ADC trigger info -- * @name: name of the trigger, corresponding to its source -- * @extsel: trigger selection -- */ --struct stm32_adc_trig_info { -- const char *name; -- enum stm32_adc_extsel extsel; --}; -- --/** -- * struct stm32_adc_calib - optional adc calibration data -- * @calfact_s: Calibration offset for single ended channels -- * @calfact_d: Calibration offset in differential -- * @lincalfact: Linearity calibration factor -- */ --struct stm32_adc_calib { -- u32 calfact_s; -- u32 calfact_d; -- u32 lincalfact[STM32H7_LINCALFACT_NUM]; --}; -- - /** - * stm32_adc_regs - stm32 ADC misc registers & bitfield desc - * @reg: register offset -@@ -110,27 +65,73 @@ struct stm32_adc_regs { - }; - - /** -+ * struct stm32_adc_awd_reginfo - stm32 ADC analog watchdog regs desc -+ * @reg: awd control register offset -+ * @en_bits: ADW enable bits for regular conversions, in @reg -+ * @jen_bits: ADW enable bits for injected conversions, in @reg -+ * @awdch_mask: AWDCH bitfield mask, in @reg -+ * @awdch_shift: AWDCH shift, in @reg -+ * @htr: High threshold register offset -+ * @ltr: Low threshold register offset -+ * @ier_msk: interrupt enable bit mask in ier register -+ * @isr_msk: interrupt status bit mask in isr register -+ */ -+struct stm32_adc_awd_reginfo { -+ u32 reg; -+ u32 en_bits; -+ u32 jen_bits; -+ u32 awdch_mask; -+ u32 awdch_shift; -+ u32 htr; -+ u32 ltr; -+ u32 ier_msk; -+ u32 isr_msk; -+}; -+ -+/** - * stm32_adc_regspec - stm32 registers definition, compatible dependent data - * @dr: data register offset -+ * @jdr: injected data registers offsets - * @ier_eoc: interrupt enable register & eocie bitfield -+ * @ier_jeoc: interrupt enable register & jeocie bitfield -+ * @ier_ovr: interrupt enable register & overrun bitfield - * @isr_eoc: interrupt status register & eoc bitfield -+ * @isr_jeoc: interrupt status register & jeoc bitfield -+ * @isr_ovr: interrupt status register & overrun bitfield - * @sqr: reference to sequence registers array -+ * @jsqr: reference to injected sequence registers array - * @exten: trigger control register & bitfield - * @extsel: trigger selection register & bitfield -+ * @jexten: injected trigger control register & bitfield -+ * @jextsel: injected trigger selection register & bitfield - * @res: resolution selection register & bitfield - * @smpr: smpr1 & smpr2 registers offset array - * @smp_bits: smpr1 & smpr2 index and bitfields -+ * @write_one_to_clear: clear isr flags by writing one to it -+ * @awd_reginfo: Analog watchdog description -+ * @num_awd: Number of Analog watchdog - */ - struct stm32_adc_regspec { - const u32 dr; -+ const u32 jdr[4]; - const struct stm32_adc_regs ier_eoc; -+ const struct stm32_adc_regs ier_jeoc; -+ const struct stm32_adc_regs ier_ovr; - const struct stm32_adc_regs isr_eoc; -+ const struct stm32_adc_regs isr_jeoc; -+ const struct stm32_adc_regs isr_ovr; - const struct stm32_adc_regs *sqr; -+ const struct stm32_adc_regs *jsqr; - const struct stm32_adc_regs exten; - const struct stm32_adc_regs extsel; -+ const struct stm32_adc_regs jexten; -+ const struct stm32_adc_regs jextsel; - const struct stm32_adc_regs res; - const u32 smpr[2]; - const struct stm32_adc_regs *smp_bits; -+ const bool write_one_to_clear; -+ const struct stm32_adc_awd_reginfo *awd_reginfo; -+ unsigned int num_awd; - }; - - struct stm32_adc; -@@ -142,12 +143,12 @@ struct stm32_adc; - * @trigs: external trigger sources - * @clk_required: clock is required - * @has_vregready: vregready status flag presence -- * @selfcalib: optional routine for self-calibration - * @prepare: optional prepare routine (power-up, enable) - * @start_conv: routine to start conversions - * @stop_conv: routine to stop conversions - * @unprepare: optional unprepare routine (disable, power-down) - * @smp_cycles: programmable sampling time (ADC clock cycles) -+ * @is_started: routine to get adc 'started' state - */ - struct stm32_adc_cfg { - const struct stm32_adc_regspec *regs; -@@ -155,18 +156,39 @@ struct stm32_adc_cfg { - struct stm32_adc_trig_info *trigs; - bool clk_required; - bool has_vregready; -- int (*selfcalib)(struct stm32_adc *); - int (*prepare)(struct stm32_adc *); - void (*start_conv)(struct stm32_adc *, bool dma); - void (*stop_conv)(struct stm32_adc *); - void (*unprepare)(struct stm32_adc *); - const unsigned int *smp_cycles; -+ bool (*is_started)(struct stm32_adc *adc); -+}; -+ -+/** -+ * struct stm32_adc_evt - Configuration data for Analog watchdog events -+ * @list: event configuration list -+ * @awd_id: assigned AWD index -+ * @chan: IIO chan spec reference for this event -+ * @hthresh: High threshold value -+ * @lthresh: Low threshold value -+ * @enabled: Event enabled state -+ * @set: Flag, event has been assigned an AWD and has been set -+ */ -+struct stm32_adc_evt { -+ struct list_head list; -+ int awd_id; -+ const struct iio_chan_spec *chan; -+ u32 hthresh; -+ u32 lthresh; -+ bool enabled; -+ bool set; - }; - - /** - * struct stm32_adc - private data of each ADC IIO instance - * @common: reference to ADC block common data - * @offset: ADC instance register offset in ADC block -+ * @id: ADC instance id from offset - * @cfg: compatible configuration data - * @completion: end of single conversion completion - * @buffer: data buffer -@@ -181,15 +203,16 @@ struct stm32_adc_cfg { - * @rx_buf: dma rx buffer cpu address - * @rx_dma_buf: dma rx buffer bus address - * @rx_buf_sz: dma rx buffer size -- * @difsel bitmask to set single-ended/differential channel -- * @pcsel bitmask to preselect channels on some devices -- * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) -- * @cal: optional calibration data on some devices - * @chan_name: channel name array -+ * @injected: use injected channels on this adc -+ * @evt_list: list of all events configured for this ADC block -+ * @awd_mask: analog watchdog bitmask for this adc -+ * @work: irq work used to call trigger poll routine - */ - struct stm32_adc { - struct stm32_adc_common *common; - u32 offset; -+ u32 id; - const struct stm32_adc_cfg *cfg; - struct completion completion; - u16 buffer[STM32_ADC_MAX_SQ]; -@@ -204,11 +227,11 @@ struct stm32_adc { - u8 *rx_buf; - dma_addr_t rx_dma_buf; - unsigned int rx_buf_sz; -- u32 difsel; -- u32 pcsel; -- u32 smpr_val[2]; -- struct stm32_adc_calib cal; - char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; -+ bool injected; -+ struct list_head evt_list; -+ u32 awd_mask; -+ struct irq_work work; - }; - - struct stm32_adc_diff_channel { -@@ -233,9 +256,9 @@ static const unsigned int stm32f4_adc_resolutions[] = { - 12, 10, 8, 6, - }; - --/* stm32f4 can have up to 16 channels */ -+/* stm32f4 can have up to 19 channels (incl. 16 external sources) */ - static const struct stm32_adc_info stm32f4_adc_info = { -- .max_channels = 16, -+ .max_channels = 19, - .resolutions = stm32f4_adc_resolutions, - .num_res = ARRAY_SIZE(stm32f4_adc_resolutions), - }; -@@ -281,25 +304,58 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = { - - /* STM32F4 external trigger sources for all instances */ - static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { -- { TIM1_CH1, STM32_EXT0 }, -- { TIM1_CH2, STM32_EXT1 }, -- { TIM1_CH3, STM32_EXT2 }, -- { TIM2_CH2, STM32_EXT3 }, -- { TIM2_CH3, STM32_EXT4 }, -- { TIM2_CH4, STM32_EXT5 }, -- { TIM2_TRGO, STM32_EXT6 }, -- { TIM3_CH1, STM32_EXT7 }, -- { TIM3_TRGO, STM32_EXT8 }, -- { TIM4_CH4, STM32_EXT9 }, -- { TIM5_CH1, STM32_EXT10 }, -- { TIM5_CH2, STM32_EXT11 }, -- { TIM5_CH3, STM32_EXT12 }, -- { TIM8_CH1, STM32_EXT13 }, -- { TIM8_TRGO, STM32_EXT14 }, -+ { TIM1_CH1, STM32_EXT0, 0, TRG_REGULAR }, -+ { TIM1_CH2, STM32_EXT1, 0, TRG_REGULAR }, -+ { TIM1_CH3, STM32_EXT2, 0, TRG_REGULAR }, -+ { TIM2_CH2, STM32_EXT3, 0, TRG_REGULAR }, -+ { TIM2_CH3, STM32_EXT4, 0, TRG_REGULAR }, -+ { TIM2_CH4, STM32_EXT5, 0, TRG_REGULAR }, -+ { TIM2_TRGO, STM32_EXT6, STM32_EXT3, TRG_BOTH }, -+ { TIM3_CH1, STM32_EXT7, 0, TRG_REGULAR }, -+ { TIM3_TRGO, STM32_EXT8, 0, TRG_REGULAR }, -+ { TIM4_CH4, STM32_EXT9, 0, TRG_REGULAR }, -+ { TIM5_CH1, STM32_EXT10, 0, TRG_REGULAR }, -+ { TIM5_CH2, STM32_EXT11, 0, TRG_REGULAR }, -+ { TIM5_CH3, STM32_EXT12, 0, TRG_REGULAR }, -+ { TIM8_CH1, STM32_EXT13, 0, TRG_REGULAR }, -+ { TIM8_TRGO, STM32_EXT14, 0, TRG_REGULAR }, -+ { TIM1_CH4, 0, STM32_EXT0, TRG_INJECTED }, -+ { TIM1_TRGO, 0, STM32_EXT1, TRG_INJECTED }, -+ { TIM2_CH1, 0, STM32_EXT2, TRG_INJECTED }, -+ { TIM3_CH2, 0, STM32_EXT4, TRG_INJECTED }, -+ { TIM3_CH4, 0, STM32_EXT5, TRG_INJECTED }, -+ { TIM4_CH1, 0, STM32_EXT6, TRG_INJECTED }, -+ { TIM4_CH2, 0, STM32_EXT7, TRG_INJECTED }, -+ { TIM4_CH3, 0, STM32_EXT8, TRG_INJECTED }, -+ { TIM4_TRGO, 0, STM32_EXT9, TRG_INJECTED }, -+ { TIM5_CH4, 0, STM32_EXT10, TRG_INJECTED }, -+ { TIM5_TRGO, 0, STM32_EXT11, TRG_INJECTED }, -+ { TIM8_CH2, 0, STM32_EXT12, TRG_INJECTED }, -+ { TIM8_CH3, 0, STM32_EXT13, TRG_INJECTED }, -+ { TIM8_CH4, 0, STM32_EXT14, TRG_INJECTED }, - {}, /* sentinel */ - }; - - /** -+ * stm32f4_jsq - describe injected sequence register: -+ * - JL: injected sequence len -+ * - JSQ4..SQ1: sequence entries -+ * When JL == 3, ADC converts JSQ1, JSQ2, JSQ3, JSQ4 -+ * When JL == 2, ADC converts JSQ2, JSQ3, JSQ4 -+ * When JL == 1, ADC converts JSQ3, JSQ4 -+ * When JL == 0, ADC converts JSQ4 -+ */ -+static const struct stm32_adc_regs stm32f4_jsq[STM32_ADC_MAX_JSQ + 1] = { -+ /* JL: len bit field description to be kept as first element */ -+ { STM32F4_ADC_JSQR, GENMASK(21, 20), 20 }, -+ /* JSQ4..JSQ1 registers & bit fields (reg, mask, shift) */ -+ { STM32F4_ADC_JSQR, GENMASK(19, 15), 15 }, -+ { STM32F4_ADC_JSQR, GENMASK(14, 10), 10 }, -+ { STM32F4_ADC_JSQR, GENMASK(9, 5), 5 }, -+ { STM32F4_ADC_JSQR, GENMASK(4, 0), 0 }, -+}; -+ -+/** - * stm32f4_smp_bits[] - describe sampling time register index & bit fields - * Sorted so it can be indexed by channel number. - */ -@@ -332,17 +388,46 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { - 3, 15, 28, 56, 84, 112, 144, 480, - }; - -+static const struct stm32_adc_awd_reginfo stm32f4_awd_reginfo = { -+ .reg = STM32F4_ADC_CR1, -+ .en_bits = STM32F4_AWDSGL | STM32F4_AWDEN, -+ .jen_bits = STM32F4_AWDSGL | STM32F4_JAWDEN, -+ .awdch_mask = STM32F4_AWDCH_MASK, -+ .awdch_shift = STM32F4_AWDCH_SHIFT, -+ .htr = STM32F4_ADC_HTR, -+ .ltr = STM32F4_ADC_LTR, -+ .ier_msk = STM32F4_AWDIE, -+ .isr_msk = STM32F4_AWD, -+}; -+ - static const struct stm32_adc_regspec stm32f4_adc_regspec = { - .dr = STM32F4_ADC_DR, -+ .jdr = { -+ STM32F4_ADC_JDR1, -+ STM32F4_ADC_JDR2, -+ STM32F4_ADC_JDR3, -+ STM32F4_ADC_JDR4, -+ }, - .ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE }, -+ .ier_jeoc = { STM32F4_ADC_CR1, STM32F4_JEOCIE }, -+ .ier_ovr = { STM32F4_ADC_CR1, STM32F4_OVRIE }, - .isr_eoc = { STM32F4_ADC_SR, STM32F4_EOC }, -+ .isr_jeoc = { STM32F4_ADC_SR, STM32F4_JEOC }, -+ .isr_ovr = { STM32F4_ADC_SR, STM32F4_OVR }, - .sqr = stm32f4_sq, -+ .jsqr = stm32f4_jsq, - .exten = { STM32F4_ADC_CR2, STM32F4_EXTEN_MASK, STM32F4_EXTEN_SHIFT }, - .extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK, - STM32F4_EXTSEL_SHIFT }, -+ .jexten = { STM32F4_ADC_CR2, STM32F4_JEXTEN_MASK, -+ STM32F4_JEXTEN_SHIFT }, -+ .jextsel = { STM32F4_ADC_CR2, STM32F4_JEXTSEL_MASK, -+ STM32F4_JEXTSEL_SHIFT }, - .res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT }, - .smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 }, - .smp_bits = stm32f4_smp_bits, -+ .awd_reginfo = &stm32f4_awd_reginfo, -+ .num_awd = 1, - }; - - static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { -@@ -367,26 +452,41 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { - { STM32H7_ADC_SQR4, GENMASK(10, 6), 6 }, - }; - -+static const struct stm32_adc_regs stm32h7_jsq[STM32_ADC_MAX_JSQ + 1] = { -+ /* JL: len bit field description to be kept as first element */ -+ { STM32H7_ADC_JSQR, GENMASK(1, 0), 0 }, -+ /* JSQ1..JSQ4 registers & bit fields (reg, mask, shift) */ -+ { STM32H7_ADC_JSQR, GENMASK(13, 9), 9 }, -+ { STM32H7_ADC_JSQR, GENMASK(19, 15), 15 }, -+ { STM32H7_ADC_JSQR, GENMASK(25, 21), 21 }, -+ { STM32H7_ADC_JSQR, GENMASK(31, 27), 27 }, -+}; -+ - /* STM32H7 external trigger sources for all instances */ - static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { -- { TIM1_CH1, STM32_EXT0 }, -- { TIM1_CH2, STM32_EXT1 }, -- { TIM1_CH3, STM32_EXT2 }, -- { TIM2_CH2, STM32_EXT3 }, -- { TIM3_TRGO, STM32_EXT4 }, -- { TIM4_CH4, STM32_EXT5 }, -- { TIM8_TRGO, STM32_EXT7 }, -- { TIM8_TRGO2, STM32_EXT8 }, -- { TIM1_TRGO, STM32_EXT9 }, -- { TIM1_TRGO2, STM32_EXT10 }, -- { TIM2_TRGO, STM32_EXT11 }, -- { TIM4_TRGO, STM32_EXT12 }, -- { TIM6_TRGO, STM32_EXT13 }, -- { TIM15_TRGO, STM32_EXT14 }, -- { TIM3_CH4, STM32_EXT15 }, -- { LPTIM1_OUT, STM32_EXT18 }, -- { LPTIM2_OUT, STM32_EXT19 }, -- { LPTIM3_OUT, STM32_EXT20 }, -+ { TIM1_CH1, STM32_EXT0, 0, TRG_REGULAR }, -+ { TIM1_CH2, STM32_EXT1, 0, TRG_REGULAR }, -+ { TIM1_CH3, STM32_EXT2, 0, TRG_REGULAR }, -+ { TIM2_CH2, STM32_EXT3, 0, TRG_REGULAR }, -+ { TIM3_TRGO, STM32_EXT4, STM32_EXT12, TRG_BOTH }, -+ { TIM4_CH4, STM32_EXT5, 0, TRG_REGULAR }, -+ { TIM8_TRGO, STM32_EXT7, STM32_EXT9, TRG_BOTH }, -+ { TIM8_TRGO2, STM32_EXT8, STM32_EXT10, TRG_BOTH }, -+ { TIM1_TRGO, STM32_EXT9, STM32_EXT0, TRG_BOTH }, -+ { TIM1_TRGO2, STM32_EXT10, STM32_EXT8, TRG_BOTH }, -+ { TIM2_TRGO, STM32_EXT11, STM32_EXT2, TRG_BOTH }, -+ { TIM4_TRGO, STM32_EXT12, STM32_EXT5, TRG_BOTH }, -+ { TIM6_TRGO, STM32_EXT13, STM32_EXT14, TRG_BOTH }, -+ { TIM15_TRGO, STM32_EXT14, STM32_EXT15, TRG_BOTH }, -+ { TIM3_CH4, STM32_EXT15, STM32_EXT4, TRG_BOTH }, -+ { LPTIM1_OUT, STM32_EXT18, STM32_EXT18, TRG_BOTH }, -+ { LPTIM2_OUT, STM32_EXT19, STM32_EXT19, TRG_BOTH }, -+ { LPTIM3_OUT, STM32_EXT20, STM32_EXT20, TRG_BOTH }, -+ { TIM1_CH4, 0, STM32_EXT1, TRG_INJECTED }, -+ { TIM2_CH1, 0, STM32_EXT3, TRG_INJECTED }, -+ { TIM8_CH4, 0, STM32_EXT7, TRG_INJECTED }, -+ { TIM3_CH3, 0, STM32_EXT11, TRG_INJECTED }, -+ { TIM3_CH1, 0, STM32_EXT13, TRG_INJECTED }, - {}, - }; - -@@ -424,17 +524,72 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { - 1, 2, 8, 16, 32, 64, 387, 810, - }; - -+/** -+ * stm32h7_awd_reginfo[] - Analog watchdog description. -+ * -+ * two watchdog types are found in stm32h7 ADC: -+ * - AWD1 has en_bits, and can select either a single or all channel(s) -+ * - AWD2 & AWD3 are enabled by channel mask (in AWDxCR) -+ * Remaining is similar (high/low threshold regs, ier/isr regs & mask) -+ */ -+static const struct stm32_adc_awd_reginfo stm32h7_awd_reginfo[] = { -+ { -+ /* AWD1: has en_bits, configure it to guard one channel */ -+ .reg = STM32H7_ADC_CFGR, -+ .en_bits = STM32H7_AWD1SGL | STM32H7_AWD1EN, -+ .jen_bits = STM32H7_AWD1SGL | STM32H7_JAWD1EN, -+ .awdch_mask = STM32H7_AWD1CH_MASK, -+ .awdch_shift = STM32H7_AWD1CH_SHIFT, -+ .htr = STM32H7_ADC_HTR1, -+ .ltr = STM32H7_ADC_LTR1, -+ .ier_msk = STM32H7_AWD1IE, -+ .isr_msk = STM32H7_AWD1, -+ }, { -+ /* AWD2 uses channel mask in AWD2CR register */ -+ .reg = STM32H7_ADC_AWD2CR, -+ .htr = STM32H7_ADC_HTR2, -+ .ltr = STM32H7_ADC_LTR2, -+ .ier_msk = STM32H7_AWD2IE, -+ .isr_msk = STM32H7_AWD2, -+ }, { -+ /* AWD3 uses channel mask in AWD3CR register */ -+ .reg = STM32H7_ADC_AWD3CR, -+ .htr = STM32H7_ADC_HTR3, -+ .ltr = STM32H7_ADC_LTR3, -+ .ier_msk = STM32H7_AWD3IE, -+ .isr_msk = STM32H7_AWD3, -+ }, -+}; -+ - static const struct stm32_adc_regspec stm32h7_adc_regspec = { - .dr = STM32H7_ADC_DR, -+ .jdr = { -+ STM32H7_ADC_JDR1, -+ STM32H7_ADC_JDR2, -+ STM32H7_ADC_JDR3, -+ STM32H7_ADC_JDR4, -+ }, - .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, -+ .ier_jeoc = { STM32H7_ADC_IER, STM32H7_JEOSIE }, -+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE }, - .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC }, -+ .isr_jeoc = { STM32H7_ADC_ISR, STM32H7_JEOS }, -+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR }, - .sqr = stm32h7_sq, -+ .jsqr = stm32h7_jsq, - .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT }, - .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, - STM32H7_EXTSEL_SHIFT }, -+ .jexten = { STM32H7_ADC_JSQR, STM32H7_JEXTEN_MASK, -+ STM32H7_JEXTEN_SHIFT }, -+ .jextsel = { STM32H7_ADC_JSQR, STM32H7_JEXTSEL_MASK, -+ STM32H7_JEXTSEL_SHIFT }, - .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, - .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, - .smp_bits = stm32h7_smp_bits, -+ .write_one_to_clear = true, -+ .awd_reginfo = stm32h7_awd_reginfo, -+ .num_awd = ARRAY_SIZE(stm32h7_awd_reginfo), - }; - - /** -@@ -490,8 +645,12 @@ static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits) - */ - static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) - { -- stm32_adc_set_bits(adc, adc->cfg->regs->ier_eoc.reg, -- adc->cfg->regs->ier_eoc.mask); -+ if (adc->injected) -+ stm32_adc_set_bits(adc, adc->cfg->regs->ier_jeoc.reg, -+ adc->cfg->regs->ier_jeoc.mask); -+ else -+ stm32_adc_set_bits(adc, adc->cfg->regs->ier_eoc.reg, -+ adc->cfg->regs->ier_eoc.mask); - }; - - /** -@@ -500,8 +659,30 @@ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) - */ - static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) - { -- stm32_adc_clr_bits(adc, adc->cfg->regs->ier_eoc.reg, -- adc->cfg->regs->ier_eoc.mask); -+ if (adc->injected) -+ stm32_adc_clr_bits(adc, adc->cfg->regs->ier_jeoc.reg, -+ adc->cfg->regs->ier_jeoc.mask); -+ else -+ stm32_adc_clr_bits(adc, adc->cfg->regs->ier_eoc.reg, -+ adc->cfg->regs->ier_eoc.mask); -+} -+ -+static void stm32_adc_ovr_irq_enable(struct stm32_adc *adc) -+{ -+ if (adc->injected) -+ return; -+ -+ stm32_adc_set_bits(adc, adc->cfg->regs->ier_ovr.reg, -+ adc->cfg->regs->ier_ovr.mask); -+} -+ -+static void stm32_adc_ovr_irq_disable(struct stm32_adc *adc) -+{ -+ if (adc->injected) -+ return; -+ -+ stm32_adc_clr_bits(adc, adc->cfg->regs->ier_ovr.reg, -+ adc->cfg->regs->ier_ovr.mask); - } - - static void stm32_adc_set_res(struct stm32_adc *adc) -@@ -514,6 +695,57 @@ static void stm32_adc_set_res(struct stm32_adc *adc) - stm32_adc_writel(adc, res->reg, val); - } - -+static int stm32_adc_hw_stop(struct device *dev) -+{ -+ struct stm32_adc *adc = dev_get_drvdata(dev); -+ -+ if (adc->cfg->unprepare) -+ adc->cfg->unprepare(adc); -+ -+ if (adc->clk) -+ clk_disable_unprepare(adc->clk); -+ -+ return 0; -+} -+ -+static int stm32_adc_hw_start(struct device *dev) -+{ -+ struct stm32_adc *adc = dev_get_drvdata(dev); -+ int ret; -+ -+ if (adc->clk) { -+ ret = clk_prepare_enable(adc->clk); -+ if (ret) -+ return ret; -+ } -+ -+ stm32_adc_set_res(adc); -+ -+ if (adc->cfg->prepare) { -+ ret = adc->cfg->prepare(adc); -+ if (ret) -+ goto err_clk_dis; -+ } -+ -+ return 0; -+ -+err_clk_dis: -+ if (adc->clk) -+ clk_disable_unprepare(adc->clk); -+ -+ return ret; -+} -+ -+static bool stm32f4_adc_is_started(struct stm32_adc *adc) -+{ -+ u32 val = stm32_adc_readl(adc, STM32F4_ADC_SR); -+ -+ if (adc->injected) -+ return !!(val & STM32F4_JSTRT); -+ else -+ return !!(val & STM32F4_STRT); -+} -+ - /** - * stm32f4_adc_start_conv() - Start conversions for regular channels. - * @adc: stm32 adc instance -@@ -526,30 +758,80 @@ static void stm32_adc_set_res(struct stm32_adc *adc) - */ - static void stm32f4_adc_start_conv(struct stm32_adc *adc, bool dma) - { -+ u32 trig_msk, start_msk; -+ - stm32_adc_set_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); - -- if (dma) -+ if (!adc->injected && dma) - stm32_adc_set_bits(adc, STM32F4_ADC_CR2, - STM32F4_DMA | STM32F4_DDS); - -- stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_EOCS | STM32F4_ADON); -+ if (!(stm32_adc_readl(adc, STM32F4_ADC_CR2) & STM32F4_ADON)) { -+ stm32_adc_set_bits(adc, STM32F4_ADC_CR2, -+ STM32F4_EOCS | STM32F4_ADON); - -- /* Wait for Power-up time (tSTAB from datasheet) */ -- usleep_range(2, 3); -+ /* Wait for Power-up time (tSTAB from datasheet) */ -+ usleep_range(2, 3); -+ } -+ -+ if (adc->injected) { -+ trig_msk = STM32F4_JEXTEN_MASK; -+ start_msk = STM32F4_JSWSTART; -+ } else { -+ trig_msk = STM32F4_EXTEN_MASK; -+ start_msk = STM32F4_SWSTART; -+ } - - /* Software start ? (e.g. trigger detection disabled ?) */ -- if (!(stm32_adc_readl(adc, STM32F4_ADC_CR2) & STM32F4_EXTEN_MASK)) -- stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_SWSTART); -+ if (!(stm32_adc_readl(adc, STM32F4_ADC_CR2) & trig_msk)) -+ stm32_adc_set_bits(adc, STM32F4_ADC_CR2, start_msk); - } - - static void stm32f4_adc_stop_conv(struct stm32_adc *adc) - { -- stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK); -- stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_STRT); -+ u32 val; -+ -+ if (adc->injected) { -+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_JEXTEN_MASK); -+ stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_JSTRT); -+ } else { -+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK); -+ stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_STRT); -+ } -+ -+ /* Disable adc when all triggered conversion have been disabled */ -+ val = stm32_adc_readl(adc, STM32F4_ADC_CR2); -+ val &= STM32F4_EXTEN_MASK | STM32F4_JEXTEN_MASK; -+ if (!val) { -+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); -+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_ADON); -+ } -+ -+ if (!adc->injected) -+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, -+ STM32F4_DMA | STM32F4_DDS); -+} -+ -+static bool stm32h7_adc_is_enabled(struct stm32_adc *adc) -+{ -+ return !!(stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_ADEN); -+} -+ -+static bool stm32h7_adc_any_ongoing_conv(struct stm32_adc *adc) -+{ -+ u32 val = stm32_adc_readl(adc, STM32H7_ADC_CR); - -- stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); -- stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, -- STM32F4_ADON | STM32F4_DMA | STM32F4_DDS); -+ return !!(val & (STM32H7_ADSTART | STM32H7_JADSTART)); -+} -+ -+static bool stm32h7_adc_is_started(struct stm32_adc *adc) -+{ -+ u32 val = stm32_adc_readl(adc, STM32H7_ADC_CR); -+ -+ if (adc->injected) -+ return !!(val & STM32H7_JADSTART); -+ else -+ return !!(val & STM32H7_ADSTART); - } - - static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) -@@ -558,6 +840,11 @@ static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) - unsigned long flags; - u32 val; - -+ if (adc->injected) { -+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_JADSTART); -+ return; -+ } -+ - if (dma) - dmngt = STM32H7_DMNGT_DMA_CIRC; - else -@@ -578,6 +865,16 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) - int ret; - u32 val; - -+ if (adc->injected) { -+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_JADSTP); -+ ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -+ !(val & (STM32H7_JADSTART)), -+ 100, STM32_ADC_TIMEOUT_US); -+ if (ret) -+ dev_warn(&indio_dev->dev, "stop failed\n"); -+ return; -+ } -+ - stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTP); - - ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -@@ -595,6 +892,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) - int ret; - u32 val; - -+ /* Is ADC already up ? */ -+ if (stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_ADVREGEN) -+ return 0; -+ - /* Exit deep power down, then enable ADC voltage regulator */ - stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); - stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN); -@@ -621,6 +922,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) - - static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) - { -+ /* Check there is no regular or injected on-going conversions */ -+ if (stm32h7_adc_any_ongoing_conv(adc)) -+ return; -+ - stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); - - /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ -@@ -633,6 +938,9 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) - int ret; - u32 val; - -+ if (stm32h7_adc_is_enabled(adc)) -+ return 0; -+ - stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); - - /* Poll for ADRDY to be set (after adc startup time) */ -@@ -656,6 +964,10 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) - int ret; - u32 val; - -+ /* Check there is no regular or injected on-going conversions */ -+ if (stm32h7_adc_any_ongoing_conv(adc)) -+ return; -+ - /* Disable ADC and wait until it's effectively disabled */ - stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS); - ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -@@ -668,18 +980,15 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) - /** - * stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result - * @adc: stm32 adc instance -+ * Note: Must be called once ADC is enabled, so LINCALRDYW[1..6] are writable - */ - static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) - { - struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct stm32_adc_calib *cal = &adc->common->cal[adc->id]; - int i, ret; - u32 lincalrdyw_mask, val; - -- /* Enable adc so LINCALRDYW1..6 bits are writable */ -- ret = stm32h7_adc_enable(adc); -- if (ret) -- return ret; -- - /* Read linearity calibration */ - lincalrdyw_mask = STM32H7_LINCALRDYW6; - for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { -@@ -692,27 +1001,25 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) - 100, STM32_ADC_TIMEOUT_US); - if (ret) { - dev_err(&indio_dev->dev, "Failed to read calfact\n"); -- goto disable; -+ return ret; - } - - val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); -- adc->cal.lincalfact[i] = (val & STM32H7_LINCALFACT_MASK); -- adc->cal.lincalfact[i] >>= STM32H7_LINCALFACT_SHIFT; -+ cal->lincalfact[i] = (val & STM32H7_LINCALFACT_MASK); -+ cal->lincalfact[i] >>= STM32H7_LINCALFACT_SHIFT; - - lincalrdyw_mask >>= 1; - } - - /* Read offset calibration */ - val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT); -- adc->cal.calfact_s = (val & STM32H7_CALFACT_S_MASK); -- adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT; -- adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK); -- adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT; -+ cal->calfact_s = (val & STM32H7_CALFACT_S_MASK); -+ cal->calfact_s >>= STM32H7_CALFACT_S_SHIFT; -+ cal->calfact_d = (val & STM32H7_CALFACT_D_MASK); -+ cal->calfact_d >>= STM32H7_CALFACT_D_SHIFT; -+ cal->calibrated = true; - --disable: -- stm32h7_adc_disable(adc); -- -- return ret; -+ return 0; - } - - /** -@@ -723,11 +1030,16 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) - static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) - { - struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct stm32_adc_calib *cal = &adc->common->cal[adc->id]; - int i, ret; - u32 lincalrdyw_mask, val; - -- val = (adc->cal.calfact_s << STM32H7_CALFACT_S_SHIFT) | -- (adc->cal.calfact_d << STM32H7_CALFACT_D_SHIFT); -+ /* Check there is no regular or injected on-going conversions */ -+ if (stm32h7_adc_any_ongoing_conv(adc)) -+ return 0; -+ -+ val = (cal->calfact_s << STM32H7_CALFACT_S_SHIFT) | -+ (cal->calfact_d << STM32H7_CALFACT_D_SHIFT); - stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val); - - lincalrdyw_mask = STM32H7_LINCALRDYW6; -@@ -737,7 +1049,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) - * Write CALFACT2, and set LINCALRDYW[6..1] bit to trigger - * data write. Then poll to wait for complete transfer. - */ -- val = adc->cal.lincalfact[i] << STM32H7_LINCALFACT_SHIFT; -+ val = cal->lincalfact[i] << STM32H7_LINCALFACT_SHIFT; - stm32_adc_writel(adc, STM32H7_ADC_CALFACT2, val); - stm32_adc_set_bits(adc, STM32H7_ADC_CR, lincalrdyw_mask); - ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -@@ -764,7 +1076,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) - return ret; - } - val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); -- if (val != adc->cal.lincalfact[i] << STM32H7_LINCALFACT_SHIFT) { -+ if (val != cal->lincalfact[i] << STM32H7_LINCALFACT_SHIFT) { - dev_err(&indio_dev->dev, "calfact not consistent\n"); - return -EIO; - } -@@ -789,19 +1101,19 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) - #define STM32H7_ADC_CALIB_TIMEOUT_US 100000 - - /** -- * stm32h7_adc_selfcalib() - Procedure to calibrate ADC (from power down) -+ * stm32h7_adc_selfcalib() - Procedure to calibrate ADC - * @adc: stm32 adc instance -- * Exit from power down, calibrate ADC, then return to power down. -+ * Note: Must be called once ADC is out of power down. - */ - static int stm32h7_adc_selfcalib(struct stm32_adc *adc) - { - struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct stm32_adc_calib *cal = &adc->common->cal[adc->id]; - int ret; - u32 val; - -- ret = stm32h7_adc_exit_pwr_down(adc); -- if (ret) -- return ret; -+ if (cal->calibrated) -+ return cal->calibrated; - - /* - * Select calibration mode: -@@ -818,7 +1130,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) - STM32H7_ADC_CALIB_TIMEOUT_US); - if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); -- goto pwr_dwn; -+ goto out; - } - - /* -@@ -835,18 +1147,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) - STM32H7_ADC_CALIB_TIMEOUT_US); - if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); -- goto pwr_dwn; -+ goto out; - } - -+out: - stm32_adc_clr_bits(adc, STM32H7_ADC_CR, - STM32H7_ADCALDIF | STM32H7_ADCALLIN); - -- /* Read calibration result for future reference */ -- ret = stm32h7_adc_read_selfcalib(adc); -- --pwr_dwn: -- stm32h7_adc_enter_pwr_down(adc); -- - return ret; - } - -@@ -863,23 +1170,43 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) - */ - static int stm32h7_adc_prepare(struct stm32_adc *adc) - { -- int ret; -+ u32 *difsel = &adc->common->difsel[adc->id]; -+ u32 *pcsel = &adc->common->pcsel[adc->id]; -+ int calib, ret; -+ -+ /* protect race between regular/injected prepare, unprepare */ -+ mutex_lock(&adc->common->inj[adc->id]); -+ adc->common->prepcnt[adc->id]++; -+ if (adc->common->prepcnt[adc->id] > 1) { -+ mutex_unlock(&adc->common->inj[adc->id]); -+ return 0; -+ } - - ret = stm32h7_adc_exit_pwr_down(adc); - if (ret) -- return ret; -+ goto unlock; -+ -+ ret = stm32h7_adc_selfcalib(adc); -+ if (ret < 0) -+ goto pwr_dwn; -+ calib = ret; - -- stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); -+ stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, *difsel); - - ret = stm32h7_adc_enable(adc); - if (ret) - goto pwr_dwn; - -- ret = stm32h7_adc_restore_selfcalib(adc); -+ /* Either restore or read calibration result for future reference */ -+ if (calib) -+ ret = stm32h7_adc_restore_selfcalib(adc); -+ else -+ ret = stm32h7_adc_read_selfcalib(adc); - if (ret) - goto disable; - -- stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel); -+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, *pcsel); -+ mutex_unlock(&adc->common->inj[adc->id]); - - return 0; - -@@ -887,39 +1214,196 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) - stm32h7_adc_disable(adc); - pwr_dwn: - stm32h7_adc_enter_pwr_down(adc); -+unlock: -+ adc->common->prepcnt[adc->id]--; -+ mutex_unlock(&adc->common->inj[adc->id]); - - return ret; - } - - static void stm32h7_adc_unprepare(struct stm32_adc *adc) - { -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ -+ mutex_lock(&adc->common->inj[adc->id]); -+ adc->common->prepcnt[adc->id]--; -+ if (adc->common->prepcnt[adc->id] > 0) { -+ mutex_unlock(&adc->common->inj[adc->id]); -+ return; -+ } -+ -+ if (adc->common->prepcnt[adc->id] < 0) -+ dev_err(&indio_dev->dev, "Unbalanced (un)prepare\n"); - stm32h7_adc_disable(adc); - stm32h7_adc_enter_pwr_down(adc); -+ mutex_unlock(&adc->common->inj[adc->id]); -+} -+ -+/** -+ * stm32_adc_find_unused_awd() - Find an unused analog watchdog -+ * @adc: stm32 adc instance -+ * -+ * Loop for all AWD to find a free AWD. -+ * Returns free AWD index or busy error. -+ */ -+static int stm32_adc_find_unused_awd(struct stm32_adc *adc) -+{ -+ const struct stm32_adc_awd_reginfo *awd_reginfo = -+ adc->cfg->regs->awd_reginfo; -+ u32 val, mask; -+ int i; -+ -+ /* find unused AWD, either use en bits or channel mask */ -+ for (i = 0; i < adc->cfg->regs->num_awd; i++) { -+ val = stm32_adc_readl(adc, awd_reginfo[i].reg); -+ mask = awd_reginfo[i].en_bits | awd_reginfo[i].jen_bits; -+ if (mask && !(val & mask)) -+ break; -+ if (!mask && !val) -+ break; -+ } -+ -+ if (i >= adc->cfg->regs->num_awd) -+ return -EBUSY; -+ -+ return i; - } - - /** -- * stm32_adc_conf_scan_seq() - Build regular channels scan sequence -+ * stm32_adc_awd_clear() - Disable analog watchdog for one adc -+ * @adc: stm32 adc instance -+ * -+ * Mask awd interrupts, disable awd. -+ */ -+static void stm32_adc_awd_clear(struct stm32_adc *adc) -+{ -+ int i; -+ u32 en_bits, ier = adc->cfg->regs->ier_eoc.reg; -+ struct stm32_adc_evt *evt; -+ const struct stm32_adc_awd_reginfo *awd_reginfo = -+ adc->cfg->regs->awd_reginfo; -+ -+ list_for_each_entry(evt, &adc->evt_list, list) { -+ if (!evt->set) -+ continue; -+ -+ i = evt->awd_id; -+ -+ /* Disable AWD interrupt */ -+ stm32_adc_clr_bits(adc, ier, awd_reginfo[i].ier_msk); -+ -+ /* Disable AWD: either use en bits and channel num, or mask */ -+ en_bits = awd_reginfo[i].en_bits | awd_reginfo[i].jen_bits; -+ if (en_bits) -+ stm32_adc_clr_bits(adc, awd_reginfo[i].reg, en_bits); -+ else -+ stm32_adc_writel(adc, awd_reginfo[i].reg, 0); -+ -+ adc->awd_mask &= ~awd_reginfo[i].isr_msk; -+ evt->set = false; -+ } -+} -+ -+/** -+ * stm32_adc_awd_set() - Set analog watchdog -+ * @adc: stm32 adc instance -+ * -+ * Set analog watchdog registers based on pre-built event list. -+ * -+ * Two watchdog types can be found in stm32 ADC: -+ * - 1st type can be used either on all channels, or on one channel. Choice -+ * is made to assing it to one channel only. It is enabled with enable bits -+ * and channel number. -+ * - 2nd type uses channel mask (choice to assign it to one channel only). -+ * In both case, set high & low threshold. Also unmask interrupt. -+ */ -+static int stm32_adc_awd_set(struct stm32_adc *adc) -+{ -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ int i; -+ struct stm32_adc_evt *evt; -+ const struct stm32_adc_awd_reginfo *awd_reginfo = -+ adc->cfg->regs->awd_reginfo; -+ u32 val, ier = adc->cfg->regs->ier_eoc.reg; -+ -+ list_for_each_entry(evt, &adc->evt_list, list) { -+ if (!evt->enabled) -+ continue; -+ -+ i = stm32_adc_find_unused_awd(adc); -+ if (i < 0) { -+ stm32_adc_awd_clear(adc); -+ return i; -+ } -+ -+ evt->awd_id = i; -+ evt->set = true; -+ dev_dbg(&indio_dev->dev, "%s chan%d htr:%d ltr:%d\n", -+ __func__, evt->chan->channel, evt->hthresh, -+ evt->lthresh); -+ -+ stm32_adc_writel(adc, awd_reginfo[i].htr, evt->hthresh); -+ stm32_adc_writel(adc, awd_reginfo[i].ltr, evt->lthresh); -+ -+ /* Enable AWD: either use en bits and channel num, or mask */ -+ if (awd_reginfo[i].en_bits | awd_reginfo[i].jen_bits) { -+ u32 mask = awd_reginfo[i].awdch_mask; -+ u32 shift = awd_reginfo[i].awdch_shift; -+ -+ val = stm32_adc_readl(adc, awd_reginfo[i].reg); -+ val &= ~mask; -+ val |= (evt->chan->channel << shift) & mask; -+ -+ if (adc->injected) -+ val |= awd_reginfo[i].jen_bits; -+ else -+ val |= awd_reginfo[i].en_bits; -+ stm32_adc_writel(adc, awd_reginfo[i].reg, val); -+ } else { -+ stm32_adc_writel(adc, awd_reginfo[i].reg, -+ BIT(evt->chan->channel)); -+ } -+ -+ /* Enable AWD interrupt */ -+ adc->awd_mask |= awd_reginfo[i].isr_msk; -+ stm32_adc_set_bits(adc, ier, awd_reginfo[i].ier_msk); -+ } -+ -+ return 0; -+} -+ -+/** -+ * stm32_adc_conf_scan_seq() - Build channels scan sequence - * @indio_dev: IIO device - * @scan_mask: channels to be converted - * - * Conversion sequence : - * Apply sampling time settings for all channels. - * Configure ADC scan sequence based on selected channels in scan_mask. -- * Add channels to SQR registers, from scan_mask LSB to MSB, then -+ * Add channels to (J)SQR registers, from scan_mask LSB to MSB, then - * program sequence len. - */ - static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, - const unsigned long *scan_mask) - { - struct stm32_adc *adc = iio_priv(indio_dev); -- const struct stm32_adc_regs *sqr = adc->cfg->regs->sqr; -+ u32 *smpr_val = adc->common->smpr_val[adc->id]; -+ const struct stm32_adc_regs *sqr; - const struct iio_chan_spec *chan; - u32 val, bit; -- int i = 0; -+ int sq_max, i = 0; -+ -+ if (adc->injected) { -+ sqr = adc->cfg->regs->jsqr; -+ sq_max = STM32_ADC_MAX_JSQ; -+ } else { -+ sqr = adc->cfg->regs->sqr; -+ sq_max = STM32_ADC_MAX_SQ; -+ } - - /* Apply sampling time settings */ -- stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]); -- stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]); -+ stm32_adc_writel(adc, adc->cfg->regs->smpr[0], smpr_val[0]); -+ stm32_adc_writel(adc, adc->cfg->regs->smpr[1], smpr_val[1]); - - for_each_set_bit(bit, scan_mask, indio_dev->masklength) { - chan = indio_dev->channels + bit; -@@ -928,11 +1412,12 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, - * sequence, starting with SQ1. - */ - i++; -- if (i > STM32_ADC_MAX_SQ) -+ if (i > sq_max) - return -EINVAL; - -- dev_dbg(&indio_dev->dev, "%s chan %d to SQ%d\n", -- __func__, chan->channel, i); -+ dev_dbg(&indio_dev->dev, "%s chan %d to %s%d\n", -+ __func__, chan->channel, adc->injected ? "JSQ" : "SQ", -+ i); - - val = stm32_adc_readl(adc, sqr[i].reg); - val &= ~sqr[i].mask; -@@ -962,18 +1447,36 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, - struct iio_trigger *trig) - { - struct stm32_adc *adc = iio_priv(indio_dev); -+ struct stm32_adc_trig_info *trinfo; -+ struct iio_trigger *tr; - int i; - - /* lookup triggers registered by stm32 timer trigger driver */ - for (i = 0; adc->cfg->trigs[i].name; i++) { -+ trinfo = &adc->cfg->trigs[i]; - /** - * Checking both stm32 timer trigger type and trig name - * should be safe against arbitrary trigger names. - */ - if ((is_stm32_timer_trigger(trig) || - is_stm32_lptim_trigger(trig)) && -- !strcmp(adc->cfg->trigs[i].name, trig->name)) { -- return adc->cfg->trigs[i].extsel; -+ !strcmp(trinfo->name, trig->name)) { -+ if (adc->injected && (trinfo->flags & TRG_INJECTED)) -+ return trinfo->jextsel; -+ -+ if (!adc->injected && (trinfo->flags & TRG_REGULAR)) -+ return trinfo->extsel; -+ } -+ } -+ -+ /* loop for triggers registered by stm32-adc-core */ -+ list_for_each_entry(tr, &adc->common->extrig_list, alloc_list) { -+ if (tr == trig) { -+ trinfo = iio_trigger_get_drvdata(trig); -+ if (adc->injected && (trinfo->flags & TRG_INJECTED)) -+ return trinfo->jextsel; -+ if (!adc->injected && (trinfo->flags & TRG_REGULAR)) -+ return trinfo->extsel; - } - } - -@@ -993,10 +1496,24 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, - struct iio_trigger *trig) - { - struct stm32_adc *adc = iio_priv(indio_dev); -- u32 val, extsel = 0, exten = STM32_EXTEN_SWTRIG; -+ u32 val, extsel = 0, exten = STM32_EXTEN_SWTRIG, reg, mask, -+ exten_shift, extsel_shift; - unsigned long flags; - int ret; - -+ if (adc->injected) { -+ reg = adc->cfg->regs->jexten.reg; -+ mask = adc->cfg->regs->jexten.mask | -+ adc->cfg->regs->jextsel.mask; -+ exten_shift = adc->cfg->regs->jexten.shift; -+ extsel_shift = adc->cfg->regs->jextsel.shift; -+ } else { -+ reg = adc->cfg->regs->exten.reg; -+ mask = adc->cfg->regs->exten.mask | adc->cfg->regs->extsel.mask; -+ exten_shift = adc->cfg->regs->exten.shift; -+ extsel_shift = adc->cfg->regs->extsel.shift; -+ } -+ - if (trig) { - ret = stm32_adc_get_trig_extsel(indio_dev, trig); - if (ret < 0) -@@ -1008,11 +1525,9 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, - } - - spin_lock_irqsave(&adc->lock, flags); -- val = stm32_adc_readl(adc, adc->cfg->regs->exten.reg); -- val &= ~(adc->cfg->regs->exten.mask | adc->cfg->regs->extsel.mask); -- val |= exten << adc->cfg->regs->exten.shift; -- val |= extsel << adc->cfg->regs->extsel.shift; -- stm32_adc_writel(adc, adc->cfg->regs->exten.reg, val); -+ val = stm32_adc_readl(adc, reg) & ~mask; -+ val |= (exten << exten_shift) | (extsel << extsel_shift); -+ stm32_adc_writel(adc, reg, val); - spin_unlock_irqrestore(&adc->lock, flags); - - return 0; -@@ -1065,36 +1580,47 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, - int *res) - { - struct stm32_adc *adc = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; - const struct stm32_adc_regspec *regs = adc->cfg->regs; -+ u32 *smpr_val = adc->common->smpr_val[adc->id]; -+ const struct stm32_adc_regs *sqr; - long timeout; - u32 val; - int ret; - - reinit_completion(&adc->completion); - -+ adc->num_conv = 1; - adc->bufi = 0; - -- if (adc->cfg->prepare) { -- ret = adc->cfg->prepare(adc); -- if (ret) -- return ret; -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; - } - - /* Apply sampling time settings */ -- stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]); -- stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]); -+ stm32_adc_writel(adc, regs->smpr[0], smpr_val[0]); -+ stm32_adc_writel(adc, regs->smpr[1], smpr_val[1]); -+ -+ if (adc->injected) -+ sqr = regs->jsqr; -+ else -+ sqr = regs->sqr; - - /* Program chan number in regular sequence (SQ1) */ -- val = stm32_adc_readl(adc, regs->sqr[1].reg); -- val &= ~regs->sqr[1].mask; -- val |= chan->channel << regs->sqr[1].shift; -- stm32_adc_writel(adc, regs->sqr[1].reg, val); -+ val = stm32_adc_readl(adc, sqr[1].reg) & ~sqr[1].mask; -+ val |= chan->channel << sqr[1].shift; -+ stm32_adc_writel(adc, sqr[1].reg, val); - - /* Set regular sequence len (0 for 1 conversion) */ -- stm32_adc_clr_bits(adc, regs->sqr[0].reg, regs->sqr[0].mask); -+ stm32_adc_clr_bits(adc, sqr[0].reg, sqr[0].mask); - - /* Trigger detection disabled (conversion can be launched in SW) */ -- stm32_adc_clr_bits(adc, regs->exten.reg, regs->exten.mask); -+ if (adc->injected) -+ stm32_adc_clr_bits(adc, regs->jexten.reg, regs->jexten.mask); -+ else -+ stm32_adc_clr_bits(adc, regs->exten.reg, regs->exten.mask); - - stm32_adc_conv_irq_enable(adc); - -@@ -1115,8 +1641,9 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, - - stm32_adc_conv_irq_disable(adc); - -- if (adc->cfg->unprepare) -- adc->cfg->unprepare(adc); -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - - return ret; - } -@@ -1163,14 +1690,72 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, - } - } - -+static irqreturn_t stm32_adc_threaded_isr(int irq, void *data) -+{ -+ struct stm32_adc *adc = data; -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct stm32_adc_evt *evt; -+ const struct stm32_adc_regspec *regs = adc->cfg->regs; -+ const struct stm32_adc_awd_reginfo *awd_reginfo = regs->awd_reginfo; -+ u32 ier = regs->ier_eoc.reg, isr = regs->isr_eoc.reg; -+ u32 status = stm32_adc_readl(adc, isr); -+ irqreturn_t ret = IRQ_NONE; -+ -+ /* Handle analog watchdog events */ -+ list_for_each_entry(evt, &adc->evt_list, list) { -+ if (!evt->set || !(status & awd_reginfo[evt->awd_id].isr_msk)) -+ continue; -+ -+ /* We don't know whether it is a upper or lower threshold. */ -+ iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(evt->chan->type, -+ evt->chan->channel, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_EITHER), -+ iio_get_time_ns(indio_dev)); -+ -+ /* clear analog watchdog flag */ -+ if (regs->write_one_to_clear) -+ stm32_adc_set_bits(adc, isr, -+ awd_reginfo[evt->awd_id].isr_msk); -+ else -+ stm32_adc_clr_bits(adc, isr, -+ awd_reginfo[evt->awd_id].isr_msk); -+ -+ /* re-enable current awd interrupt */ -+ stm32_adc_set_bits(adc, ier, awd_reginfo[evt->awd_id].ier_msk); -+ -+ ret = IRQ_HANDLED; -+ } -+ -+ return ret; -+} -+ - static irqreturn_t stm32_adc_isr(int irq, void *data) - { - struct stm32_adc *adc = data; - struct iio_dev *indio_dev = iio_priv_to_dev(adc); - const struct stm32_adc_regspec *regs = adc->cfg->regs; -+ const struct stm32_adc_awd_reginfo *awd_reginfo = regs->awd_reginfo; - u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); -+ u32 ier = adc->cfg->regs->ier_eoc.reg; -+ irqreturn_t ret = IRQ_NONE; -+ int i; -+ -+ if (!adc->injected && (status & regs->isr_ovr.mask)) { -+ /* -+ * Overrun occured on regular conversions. Can't recover easily -+ * especially in scan mode: data for wrong channel may be read. -+ * Then, unconditionally disable interrupts to stop processing -+ * data, and lazily print error message (once). -+ */ -+ stm32_adc_ovr_irq_disable(adc); -+ stm32_adc_conv_irq_disable(adc); -+ dev_err(&indio_dev->dev, "Overrun interrupt, stopping.\n"); -+ return IRQ_HANDLED; -+ } - -- if (status & regs->isr_eoc.mask) { -+ if (!adc->injected && (status & regs->isr_eoc.mask)) { - /* Reading DR also clears EOC status flag */ - adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr); - if (iio_buffer_enabled(indio_dev)) { -@@ -1182,10 +1767,48 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) - } else { - complete(&adc->completion); - } -- return IRQ_HANDLED; -+ ret = IRQ_HANDLED; - } - -- return IRQ_NONE; -+ if (adc->injected && (status & regs->isr_jeoc.mask)) { -+ int i; -+ -+ if (regs->write_one_to_clear) -+ stm32_adc_writel(adc, regs->isr_jeoc.reg, -+ regs->isr_jeoc.mask); -+ else -+ stm32_adc_writel(adc, regs->isr_jeoc.reg, -+ ~regs->isr_jeoc.mask); -+ -+ for (i = 0; i < adc->num_conv; i++) { -+ adc->buffer[i] = stm32_adc_readw(adc, regs->jdr[i]); -+ adc->bufi++; -+ } -+ -+ if (iio_buffer_enabled(indio_dev)) { -+ stm32_adc_conv_irq_disable(adc); -+ iio_trigger_poll(indio_dev->trig); -+ } else { -+ complete(&adc->completion); -+ } -+ ret = IRQ_HANDLED; -+ } -+ -+ /* only check AWD assigned to this ADC (e.g. regular or injected) */ -+ status &= adc->awd_mask; -+ if (status) { -+ for (i = 0; i < adc->cfg->regs->num_awd; i++) { -+ /* mask current awd interrupt */ -+ if (status & awd_reginfo[i].isr_msk) -+ stm32_adc_clr_bits(adc, ier, -+ awd_reginfo[i].ier_msk); -+ } -+ -+ /* AWD has detected an event, need to wake IRQ thread */ -+ ret = IRQ_WAKE_THREAD; -+ } -+ -+ return ret; - } - - /** -@@ -1224,13 +1847,169 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) - { - struct stm32_adc *adc = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; - int ret; - -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ - adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); - - ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); -- if (ret) -- return ret; -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ -+ return ret; -+} -+ -+/* -+ * stm32 awd monitors specified channel(s) are within window range. -+ * Define events here as high/low thresholds, with a common enable for -+ * both directions. There is no way to know from interrupt flags, which -+ * direction an event occurred. It's up to upper layers then to check -+ * value. -+ */ -+static const struct iio_event_spec stm32_adc_events[] = { -+ { -+ .type = IIO_EV_TYPE_THRESH, -+ .dir = IIO_EV_DIR_RISING, -+ .mask_separate = BIT(IIO_EV_INFO_VALUE), -+ }, { -+ .type = IIO_EV_TYPE_THRESH, -+ .dir = IIO_EV_DIR_FALLING, -+ .mask_separate = BIT(IIO_EV_INFO_VALUE), -+ }, { -+ .type = IIO_EV_TYPE_THRESH, -+ .dir = IIO_EV_DIR_EITHER, -+ .mask_separate = BIT(IIO_EV_INFO_ENABLE), -+ }, -+}; -+ -+static int stm32_adc_read_event_config(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ struct stm32_adc_evt *evt; -+ -+ list_for_each_entry(evt, &adc->evt_list, list) -+ if (evt->chan == chan) -+ return evt->enabled; -+ -+ return 0; -+} -+ -+static int stm32_adc_write_event_config(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ int state) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ struct stm32_adc_evt *evt; -+ bool found = false; -+ int i = 0; -+ -+ /* AWD can only be configured before starting conversions */ -+ if (adc->cfg->is_started(adc)) -+ return -EBUSY; -+ -+ list_for_each_entry(evt, &adc->evt_list, list) { -+ if (evt->chan == chan) { -+ found = true; -+ evt->enabled = !!state; -+ } -+ -+ /* number of enabled AWD for this adc instance */ -+ if (evt->enabled) -+ i++; -+ -+ /* unique event per AWD: don't exceed number of AWD */ -+ if (i > adc->cfg->regs->num_awd) -+ goto err_busy; -+ } -+ -+ /* In case no threshold have been configured, can't enable evt */ -+ if (!found) -+ return -EINVAL; -+ -+ return 0; -+ -+err_busy: -+ dev_err(&indio_dev->dev, "Number of awd exceeded\n"); -+ -+ list_for_each_entry(evt, &adc->evt_list, list) -+ if (evt->chan == chan) -+ evt->enabled = false; -+ -+ return -EBUSY; -+} -+ -+static int stm32_adc_read_thresh(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ enum iio_event_info info, int *val, -+ int *val2) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ struct stm32_adc_evt *evt; -+ -+ *val = 0; -+ -+ list_for_each_entry(evt, &adc->evt_list, list) { -+ if (evt->chan == chan) { -+ if (dir == IIO_EV_DIR_RISING) -+ *val = evt->hthresh; -+ else -+ *val = evt->lthresh; -+ break; -+ } -+ } -+ -+ return IIO_VAL_INT; -+} -+ -+static int stm32_adc_write_thresh(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ enum iio_event_info info, int val, -+ int val2) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ struct stm32_adc_evt *evt; -+ unsigned long flags; -+ -+ if (adc->cfg->is_started(adc)) -+ return -EBUSY; -+ -+ /* Look for existing evt for this channel */ -+ list_for_each_entry(evt, &adc->evt_list, list) -+ if (evt->chan == chan) -+ goto found; -+ -+ /* Allocate new event: up to num_channels evts */ -+ evt = devm_kzalloc(&indio_dev->dev, sizeof(*evt), GFP_KERNEL); -+ if (!evt) -+ return -ENOMEM; -+ -+ evt->chan = chan; -+ -+ spin_lock_irqsave(&adc->lock, flags); -+ list_add_tail(&evt->list, &adc->evt_list); -+ spin_unlock_irqrestore(&adc->lock, flags); -+ -+found: -+ if (dir == IIO_EV_DIR_RISING) -+ evt->hthresh = val; -+ else -+ evt->lthresh = val; - - return 0; - } -@@ -1262,12 +2041,24 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, - unsigned *readval) - { - struct stm32_adc *adc = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; -+ int ret; -+ -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } - - if (!readval) - stm32_adc_writel(adc, reg, writeval); - else - *readval = stm32_adc_readl(adc, reg); - -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ - return 0; - } - -@@ -1276,6 +2067,10 @@ static const struct iio_info stm32_adc_iio_info = { - .validate_trigger = stm32_adc_validate_trigger, - .hwfifo_set_watermark = stm32_adc_set_watermark, - .update_scan_mode = stm32_adc_update_scan_mode, -+ .read_event_config = &stm32_adc_read_event_config, -+ .write_event_config = &stm32_adc_write_event_config, -+ .read_event_value = stm32_adc_read_thresh, -+ .write_event_value = stm32_adc_write_thresh, - .debugfs_reg_access = stm32_adc_debugfs_reg_access, - .of_xlate = stm32_adc_of_xlate, - }; -@@ -1305,11 +2100,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) - return 0; - } - -+static void stm32_adc_dma_irq_work(struct irq_work *work) -+{ -+ struct stm32_adc *adc = container_of(work, struct stm32_adc, work); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ -+ /* -+ * iio_trigger_poll calls generic_handle_irq(). So, it requires hard -+ * irq context, and cannot be called directly from dma callback, -+ * dma cb has to schedule this work instead. -+ */ -+ iio_trigger_poll(indio_dev->trig); -+} -+ - static void stm32_adc_dma_buffer_done(void *data) - { - struct iio_dev *indio_dev = data; -+ struct stm32_adc *adc = iio_priv(indio_dev); - -- iio_trigger_poll_chained(indio_dev->trig); -+ /* -+ * Invoques iio_trigger_poll() from hard irq context: We can't -+ * call iio_trigger_poll() nor iio_trigger_poll_chained() -+ * directly from DMA callback (under tasklet e.g. softirq). -+ * They require respectively HW IRQ and threaded IRQ context -+ * as it might sleep. -+ */ -+ irq_work_queue(&adc->work); - } - - static int stm32_adc_dma_start(struct iio_dev *indio_dev) -@@ -1350,21 +2166,28 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) - return 0; - } - --static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) -+static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) - { - struct stm32_adc *adc = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; - int ret; - -- if (adc->cfg->prepare) { -- ret = adc->cfg->prepare(adc); -- if (ret) -- return ret; -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ -+ ret = stm32_adc_awd_set(adc); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Failed to configure awd\n"); -+ goto err_pm_put; - } - - ret = stm32_adc_set_trig(indio_dev, indio_dev->trig); - if (ret) { - dev_err(&indio_dev->dev, "Can't set trigger\n"); -- goto err_unprepare; -+ goto err_clr_awd; - } - - ret = stm32_adc_dma_start(indio_dev); -@@ -1373,13 +2196,11 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) - goto err_clr_trig; - } - -- ret = iio_triggered_buffer_postenable(indio_dev); -- if (ret < 0) -- goto err_stop_dma; -- - /* Reset adc buffer index */ - adc->bufi = 0; - -+ stm32_adc_ovr_irq_enable(adc); -+ - if (!adc->dma_chan) - stm32_adc_conv_irq_enable(adc); - -@@ -1387,39 +2208,68 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) - - return 0; - --err_stop_dma: -- if (adc->dma_chan) -- dmaengine_terminate_all(adc->dma_chan); - err_clr_trig: - stm32_adc_set_trig(indio_dev, NULL); --err_unprepare: -- if (adc->cfg->unprepare) -- adc->cfg->unprepare(adc); -+err_clr_awd: -+ stm32_adc_awd_clear(adc); -+err_pm_put: -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - - return ret; - } - --static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) -+static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) - { -- struct stm32_adc *adc = iio_priv(indio_dev); - int ret; - -+ ret = iio_triggered_buffer_postenable(indio_dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = __stm32_adc_buffer_postenable(indio_dev); -+ if (ret < 0) -+ iio_triggered_buffer_predisable(indio_dev); -+ -+ return ret; -+} -+ -+static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev) -+{ -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; -+ - adc->cfg->stop_conv(adc); - if (!adc->dma_chan) - stm32_adc_conv_irq_disable(adc); - -- ret = iio_triggered_buffer_predisable(indio_dev); -- if (ret < 0) -- dev_err(&indio_dev->dev, "predisable failed\n"); -+ stm32_adc_ovr_irq_disable(adc); - -- if (adc->dma_chan) -+ if (adc->dma_chan) { - dmaengine_terminate_sync(adc->dma_chan); -+ irq_work_sync(&adc->work); -+ } - - if (stm32_adc_set_trig(indio_dev, NULL)) - dev_err(&indio_dev->dev, "Can't clear trigger\n"); - -- if (adc->cfg->unprepare) -- adc->cfg->unprepare(adc); -+ stm32_adc_awd_clear(adc); -+ -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+} -+ -+static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) -+{ -+ int ret; -+ -+ __stm32_adc_buffer_predisable(indio_dev); -+ -+ ret = iio_triggered_buffer_predisable(indio_dev); -+ if (ret < 0) -+ dev_err(&indio_dev->dev, "predisable failed\n"); - - return ret; - } -@@ -1504,6 +2354,7 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev) - static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) - { - const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel]; -+ u32 *smpr_val = adc->common->smpr_val[adc->id]; - u32 period_ns, shift = smpr->shift, mask = smpr->mask; - unsigned int smp, r = smpr->reg; - -@@ -1516,7 +2367,7 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) - smp = STM32_ADC_MAX_SMP; - - /* pre-build sampling time registers (e.g. smpr1, smpr2) */ -- adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift); -+ smpr_val[r] = (smpr_val[r] & ~mask) | (smp << shift); - } - - static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, -@@ -1525,6 +2376,8 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, - { - struct stm32_adc *adc = iio_priv(indio_dev); - char *name = adc->chan_name[vinp]; -+ u32 *difsel = &adc->common->difsel[adc->id]; -+ u32 *pcsel = &adc->common->pcsel[adc->id]; - - chan->type = IIO_VOLTAGE; - chan->channel = vinp; -@@ -1545,14 +2398,16 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, - chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res]; - chan->scan_type.storagebits = 16; - chan->ext_info = stm32_adc_ext_info; -+ chan->event_spec = stm32_adc_events; -+ chan->num_event_specs = ARRAY_SIZE(stm32_adc_events); - - /* pre-build selected channels mask */ -- adc->pcsel |= BIT(chan->channel); -+ *pcsel |= BIT(chan->channel); - if (differential) { - /* pre-build diff channels mask */ -- adc->difsel |= BIT(chan->channel); -+ *difsel |= BIT(chan->channel); - /* Also add negative input to pre-selected channels */ -- adc->pcsel |= BIT(chan->channel2); -+ *pcsel |= BIT(chan->channel2); - } - } - -@@ -1568,6 +2423,11 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) - int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; - u32 val, smp = 0; - -+ if (of_property_read_bool(node, "st,injected")) { -+ dev_dbg(&indio_dev->dev, "Configured to use injected\n"); -+ adc->injected = true; -+ } -+ - ret = of_property_count_u32_elems(node, "st,adc-channels"); - if (ret > adc_info->max_channels) { - dev_err(&indio_dev->dev, "Bad st,adc-channels?\n"); -@@ -1688,6 +2548,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev) - if (ret) - goto err_free; - -+ init_irq_work(&adc->work, stm32_adc_dma_irq_work); -+ - return 0; - - err_free: -@@ -1719,6 +2581,7 @@ static int stm32_adc_probe(struct platform_device *pdev) - init_completion(&adc->completion); - adc->cfg = (const struct stm32_adc_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; -+ INIT_LIST_HEAD(&adc->evt_list); - - indio_dev->name = dev_name(&pdev->dev); - indio_dev->dev.parent = &pdev->dev; -@@ -1729,10 +2592,18 @@ static int stm32_adc_probe(struct platform_device *pdev) - platform_set_drvdata(pdev, adc); - - ret = of_property_read_u32(pdev->dev.of_node, "reg", &adc->offset); -- if (ret != 0) { -+ if (ret != 0 || adc->offset >= STM32_ADCX_COMN_OFFSET) { - dev_err(&pdev->dev, "missing reg property\n"); - return -EINVAL; - } -+ adc->id = adc->offset / STM32_ADC_OFFSET; -+ -+ of_property_read_u32(pdev->dev.of_node, "st,trigger-polarity", -+ &adc->trigger_polarity); -+ if (adc->trigger_polarity >= ARRAY_SIZE(stm32_trig_pol_items)) { -+ dev_err(&pdev->dev, "Invalid st,trigger-polarity property\n"); -+ return -EINVAL; -+ } - - adc->irq = platform_get_irq(pdev, 0); - if (adc->irq < 0) { -@@ -1740,8 +2611,9 @@ static int stm32_adc_probe(struct platform_device *pdev) - return adc->irq; - } - -- ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr, -- 0, pdev->name, adc); -+ ret = devm_request_threaded_irq(&pdev->dev, adc->irq, stm32_adc_isr, -+ stm32_adc_threaded_isr, -+ 0, pdev->name, adc); - if (ret) { - dev_err(&pdev->dev, "failed to request IRQ\n"); - return ret; -@@ -1758,32 +2630,17 @@ static int stm32_adc_probe(struct platform_device *pdev) - } - } - -- if (adc->clk) { -- ret = clk_prepare_enable(adc->clk); -- if (ret < 0) { -- dev_err(&pdev->dev, "clk enable failed\n"); -- return ret; -- } -- } -- - ret = stm32_adc_of_get_resolution(indio_dev); - if (ret < 0) -- goto err_clk_disable; -- stm32_adc_set_res(adc); -- -- if (adc->cfg->selfcalib) { -- ret = adc->cfg->selfcalib(adc); -- if (ret) -- goto err_clk_disable; -- } -+ return ret; - - ret = stm32_adc_chan_of_init(indio_dev); - if (ret < 0) -- goto err_clk_disable; -+ return ret; - - ret = stm32_adc_dma_request(indio_dev); - if (ret < 0) -- goto err_clk_disable; -+ return ret; - - ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, -@@ -1794,15 +2651,36 @@ static int stm32_adc_probe(struct platform_device *pdev) - goto err_dma_disable; - } - -+ /* Get stm32-adc-core PM online */ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_enable(dev); -+ -+ ret = stm32_adc_hw_start(dev); -+ if (ret) -+ goto err_buffer_cleanup; -+ - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "iio dev register failed\n"); -- goto err_buffer_cleanup; -+ goto err_hw_stop; - } - -+ pm_runtime_mark_last_busy(dev->parent); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ - return 0; - -+err_hw_stop: -+ stm32_adc_hw_stop(dev); -+ - err_buffer_cleanup: -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); - iio_triggered_buffer_cleanup(indio_dev); - - err_dma_disable: -@@ -1812,9 +2690,6 @@ static int stm32_adc_probe(struct platform_device *pdev) - adc->rx_buf, adc->rx_dma_buf); - dma_release_channel(adc->dma_chan); - } --err_clk_disable: -- if (adc->clk) -- clk_disable_unprepare(adc->clk); - - return ret; - } -@@ -1824,7 +2699,12 @@ static int stm32_adc_remove(struct platform_device *pdev) - struct stm32_adc *adc = platform_get_drvdata(pdev); - struct iio_dev *indio_dev = iio_priv_to_dev(adc); - -+ pm_runtime_get_sync(&pdev->dev); - iio_device_unregister(indio_dev); -+ stm32_adc_hw_stop(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); - iio_triggered_buffer_cleanup(indio_dev); - if (adc->dma_chan) { - dma_free_coherent(adc->dma_chan->device->dev, -@@ -1832,12 +2712,62 @@ static int stm32_adc_remove(struct platform_device *pdev) - adc->rx_buf, adc->rx_dma_buf); - dma_release_channel(adc->dma_chan); - } -- if (adc->clk) -- clk_disable_unprepare(adc->clk); - - return 0; - } - -+#if defined(CONFIG_PM_SLEEP) -+static int stm32_adc_suspend(struct device *dev) -+{ -+ struct stm32_adc *adc = dev_get_drvdata(dev); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ -+ if (iio_buffer_enabled(indio_dev)) -+ __stm32_adc_buffer_predisable(indio_dev); -+ -+ return pm_runtime_force_suspend(dev); -+} -+ -+static int stm32_adc_resume(struct device *dev) -+{ -+ struct stm32_adc *adc = dev_get_drvdata(dev); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ int ret; -+ -+ ret = pm_runtime_force_resume(dev); -+ if (ret < 0) -+ return ret; -+ -+ if (!iio_buffer_enabled(indio_dev)) -+ return 0; -+ -+ ret = stm32_adc_update_scan_mode(indio_dev, -+ indio_dev->active_scan_mask); -+ if (ret < 0) -+ return ret; -+ -+ return __stm32_adc_buffer_postenable(indio_dev); -+} -+#endif -+ -+#if defined(CONFIG_PM) -+static int stm32_adc_runtime_suspend(struct device *dev) -+{ -+ return stm32_adc_hw_stop(dev); -+} -+ -+static int stm32_adc_runtime_resume(struct device *dev) -+{ -+ return stm32_adc_hw_start(dev); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_adc_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume) -+ SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume, -+ NULL) -+}; -+ - static const struct stm32_adc_cfg stm32f4_adc_cfg = { - .regs = &stm32f4_adc_regspec, - .adc_info = &stm32f4_adc_info, -@@ -1846,18 +2776,19 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { - .start_conv = stm32f4_adc_start_conv, - .stop_conv = stm32f4_adc_stop_conv, - .smp_cycles = stm32f4_adc_smp_cycles, -+ .is_started = stm32f4_adc_is_started, - }; - - static const struct stm32_adc_cfg stm32h7_adc_cfg = { - .regs = &stm32h7_adc_regspec, - .adc_info = &stm32h7_adc_info, - .trigs = stm32h7_adc_trigs, -- .selfcalib = stm32h7_adc_selfcalib, - .start_conv = stm32h7_adc_start_conv, - .stop_conv = stm32h7_adc_stop_conv, - .prepare = stm32h7_adc_prepare, - .unprepare = stm32h7_adc_unprepare, - .smp_cycles = stm32h7_adc_smp_cycles, -+ .is_started = stm32h7_adc_is_started, - }; - - static const struct stm32_adc_cfg stm32mp1_adc_cfg = { -@@ -1865,12 +2796,12 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { - .adc_info = &stm32h7_adc_info, - .trigs = stm32h7_adc_trigs, - .has_vregready = true, -- .selfcalib = stm32h7_adc_selfcalib, - .start_conv = stm32h7_adc_start_conv, - .stop_conv = stm32h7_adc_stop_conv, - .prepare = stm32h7_adc_prepare, - .unprepare = stm32h7_adc_unprepare, - .smp_cycles = stm32h7_adc_smp_cycles, -+ .is_started = stm32h7_adc_is_started, - }; - - static const struct of_device_id stm32_adc_of_match[] = { -@@ -1887,6 +2818,7 @@ static struct platform_driver stm32_adc_driver = { - .driver = { - .name = "stm32-adc", - .of_match_table = stm32_adc_of_match, -+ .pm = &stm32_adc_pm_ops, - }, - }; - module_platform_driver(stm32_adc_driver); -diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c -index f5586dd..034f919 100644 ---- a/drivers/iio/adc/stm32-dfsdm-adc.c -+++ b/drivers/iio/adc/stm32-dfsdm-adc.c -@@ -10,8 +10,14 @@ - #include - #include - #include -+#include - #include - #include -+#include -+#include -+#include -+#include -+#include - #include - #include - #include -@@ -34,9 +40,21 @@ - #define DFSDM_MAX_INT_OVERSAMPLING 256 - #define DFSDM_MAX_FL_OVERSAMPLING 1024 - --/* Max sample resolutions */ --#define DFSDM_MAX_RES BIT(31) --#define DFSDM_DATA_RES BIT(23) -+/* Limit filter output resolution to 31 bits. (i.e. sample range is +/-2^30) */ -+#define DFSDM_DATA_MAX BIT(30) -+/* -+ * Data are output as two’s complement data in a 24 bit field. -+ * Data from filters are in the range +/-2^(n-1) -+ * 2^(n-1) maximum positive value cannot be coded in 2's complement n bits -+ * An extra bit is required to avoid wrap-around of the binary code for 2^(n-1) -+ * So, the resolution of samples from filter is actually limited to 23 bits -+ */ -+#define DFSDM_DATA_RES 24 -+ -+/* Filter configuration */ -+#define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \ -+ DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \ -+ DFSDM_CR1_JSCAN_MASK) - - enum sd_converter_type { - DFSDM_AUDIO, -@@ -50,16 +68,26 @@ struct stm32_dfsdm_dev_data { - const struct regmap_config *regmap_cfg; - }; - -+struct stm32_dfsdm_sd_chan_info { -+ int scale_val; -+ int scale_val2; -+ int offset; -+ unsigned int differential; -+}; -+ - struct stm32_dfsdm_adc { - struct stm32_dfsdm *dfsdm; - const struct stm32_dfsdm_dev_data *dev_data; - unsigned int fl_id; -+ unsigned int nconv; -+ unsigned long smask; - - /* ADC specific */ - unsigned int oversamp; - struct iio_hw_consumer *hwc; - struct completion completion; - u32 *buffer; -+ struct stm32_dfsdm_sd_chan_info *sd_chan; - - /* Audio specific */ - unsigned int spi_freq; /* SPI bus clock frequency */ -@@ -114,14 +142,70 @@ static int stm32_dfsdm_str2val(const char *str, - return -EINVAL; - } - --static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, -- unsigned int fast, unsigned int oversamp) -+/** -+ * struct stm32_dfsdm_trig_info - DFSDM trigger info -+ * @name: name of the trigger, corresponding to its source -+ * @jextsel: trigger signal selection -+ */ -+struct stm32_dfsdm_trig_info { -+ const char *name; -+ unsigned int jextsel; -+}; -+ -+/* hardware injected trigger enable, edge selection */ -+enum stm32_dfsdm_jexten { -+ STM32_DFSDM_JEXTEN_DISABLED, -+ STM32_DFSDM_JEXTEN_RISING_EDGE, -+ STM32_DFSDM_JEXTEN_FALLING_EDGE, -+ STM32_DFSDM_EXTEN_BOTH_EDGES, -+}; -+ -+static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = { -+ { TIM1_TRGO, 0 }, -+ { TIM1_TRGO2, 1 }, -+ { TIM8_TRGO, 2 }, -+ { TIM8_TRGO2, 3 }, -+ { TIM3_TRGO, 4 }, -+ { TIM4_TRGO, 5 }, -+ { TIM16_OC1, 6 }, -+ { TIM6_TRGO, 7 }, -+ { TIM7_TRGO, 8 }, -+ { LPTIM1_OUT, 26 }, -+ { LPTIM2_OUT, 27 }, -+ { LPTIM3_OUT, 28 }, -+ {}, -+}; -+ -+static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev, -+ struct iio_trigger *trig) -+{ -+ int i; -+ -+ /* lookup triggers registered by stm32 timer trigger driver */ -+ for (i = 0; stm32_dfsdm_trigs[i].name; i++) { -+ /** -+ * Checking both stm32 timer trigger type and trig name -+ * should be safe against arbitrary trigger names. -+ */ -+ if ((is_stm32_timer_trigger(trig) || -+ is_stm32_lptim_trigger(trig)) && -+ !strcmp(stm32_dfsdm_trigs[i].name, trig->name)) { -+ return stm32_dfsdm_trigs[i].jextsel; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl, -+ unsigned int fast, unsigned int oversamp) - { - unsigned int i, d, fosr, iosr; -- u64 res; -- s64 delta; -+ u64 res, max; -+ int bits, shift; - unsigned int m = 1; /* multiplication factor */ - unsigned int p = fl->ford; /* filter order (ford) */ -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fast]; - - pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp); - /* -@@ -140,11 +224,8 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, - - /* - * Look for filter and integrator oversampling ratios which allows -- * to reach 24 bits data output resolution. -- * Leave as soon as if exact resolution if reached. -- * Otherwise the higher resolution below 32 bits is kept. -+ * to maximize data output resolution. - */ -- fl->res = 0; - for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) { - for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) { - if (fast) -@@ -169,50 +250,128 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, - res = fosr; - for (i = p - 1; i > 0; i--) { - res = res * (u64)fosr; -- if (res > DFSDM_MAX_RES) -+ if (res > DFSDM_DATA_MAX) - break; - } -- if (res > DFSDM_MAX_RES) -+ if (res > DFSDM_DATA_MAX) - continue; -+ - res = res * (u64)m * (u64)iosr; -- if (res > DFSDM_MAX_RES) -+ if (res > DFSDM_DATA_MAX) - continue; - -- delta = res - DFSDM_DATA_RES; -- -- if (res >= fl->res) { -- fl->res = res; -- fl->fosr = fosr; -- fl->iosr = iosr; -- fl->fast = fast; -- pr_debug("%s: fosr = %d, iosr = %d\n", -- __func__, fl->fosr, fl->iosr); -+ if (res >= flo->res) { -+ flo->res = res; -+ flo->fosr = fosr; -+ flo->iosr = iosr; -+ -+ bits = fls(flo->res); -+ /* 8 LBSs in data register contain chan info */ -+ max = flo->res << 8; -+ -+ /* if resolution is not a power of two */ -+ if (flo->res > BIT(bits - 1)) -+ bits++; -+ else -+ max--; -+ -+ shift = DFSDM_DATA_RES - bits; -+ /* -+ * Compute right/left shift -+ * Right shift is performed by hardware -+ * when transferring samples to data register. -+ * Left shift is done by software on buffer -+ */ -+ if (shift > 0) { -+ /* Resolution is lower than 24 bits */ -+ flo->rshift = 0; -+ flo->lshift = shift; -+ } else { -+ /* -+ * If resolution is 24 bits or more, -+ * max positive value may be ambiguous -+ * (equal to max negative value as sign -+ * bit is dropped). -+ * Reduce resolution to 23 bits (rshift) -+ * to keep the sign on bit 23 and treat -+ * saturation before rescaling on 24 -+ * bits (lshift). -+ */ -+ flo->rshift = 1 - shift; -+ flo->lshift = 1; -+ max >>= flo->rshift; -+ } -+ flo->max = (s32)max; -+ -+ pr_debug("%s: fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n", -+ __func__, fast, flo->fosr, flo->iosr, -+ flo->res, bits, flo->rshift, -+ flo->lshift); - } -- -- if (!delta) -- return 0; - } - } - -- if (!fl->res) -+ if (!flo->res) - return -EINVAL; - - return 0; - } - --static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm, -- unsigned int ch_id) -+static int stm32_dfsdm_compute_all_osrs(struct iio_dev *indio_dev, -+ unsigned int oversamp) - { -- return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), -- DFSDM_CHCFGR1_CHEN_MASK, -- DFSDM_CHCFGR1_CHEN(1)); -+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; -+ int ret0, ret1; -+ -+ memset(&fl->flo[0], 0, sizeof(fl->flo[0])); -+ memset(&fl->flo[1], 0, sizeof(fl->flo[1])); -+ -+ ret0 = stm32_dfsdm_compute_osrs(fl, 0, oversamp); -+ ret1 = stm32_dfsdm_compute_osrs(fl, 1, oversamp); -+ if (ret0 < 0 && ret1 < 0) { -+ dev_err(&indio_dev->dev, -+ "Filter parameters not found: errors %d/%d\n", -+ ret0, ret1); -+ return -EINVAL; -+ } -+ -+ return 0; - } - --static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, -- unsigned int ch_id) -+static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc) - { -- regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), -- DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0)); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct regmap *regmap = adc->dfsdm->regmap; -+ const struct iio_chan_spec *chan; -+ unsigned int bit; -+ int ret; -+ -+ for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { -+ chan = indio_dev->channels + bit; -+ ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), -+ DFSDM_CHCFGR1_CHEN_MASK, -+ DFSDM_CHCFGR1_CHEN(1)); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void stm32_dfsdm_stop_channel(struct stm32_dfsdm_adc *adc) -+{ -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct regmap *regmap = adc->dfsdm->regmap; -+ const struct iio_chan_spec *chan; -+ unsigned int bit; -+ -+ for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { -+ chan = indio_dev->channels + bit; -+ regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), -+ DFSDM_CHCFGR1_CHEN_MASK, -+ DFSDM_CHCFGR1_CHEN(0)); -+ } - } - - static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, -@@ -237,9 +396,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, - DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); - } - --static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, -- unsigned int fl_id) -+static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc, -+ unsigned int fl_id, -+ struct iio_trigger *trig) - { -+ struct stm32_dfsdm *dfsdm = adc->dfsdm; - int ret; - - /* Enable filter */ -@@ -248,7 +409,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, - if (ret < 0) - return ret; - -- /* Start conversion */ -+ /* Nothing more to do for injected (scan mode/triggered) conversions */ -+ if (adc->nconv > 1 || trig) -+ return 0; -+ -+ /* Software start (single or continuous) regular conversion */ - return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), - DFSDM_CR1_RSWSTART_MASK, - DFSDM_CR1_RSWSTART(1)); -@@ -262,22 +427,101 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, - DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); - } - --static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, -- unsigned int fl_id, unsigned int ch_id) -+static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc, -+ unsigned int fl_id, -+ struct iio_trigger *trig) - { -- struct regmap *regmap = dfsdm->regmap; -- struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id]; -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct regmap *regmap = adc->dfsdm->regmap; -+ u32 jextsel = 0, jexten = STM32_DFSDM_JEXTEN_DISABLED; -+ int ret; -+ -+ if (trig) { -+ ret = stm32_dfsdm_get_jextsel(indio_dev, trig); -+ if (ret < 0) -+ return ret; -+ -+ /* set trigger source and polarity (default to rising edge) */ -+ jextsel = ret; -+ jexten = STM32_DFSDM_JEXTEN_RISING_EDGE; -+ } -+ -+ ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), -+ DFSDM_CR1_JEXTSEL_MASK | DFSDM_CR1_JEXTEN_MASK, -+ DFSDM_CR1_JEXTSEL(jextsel) | -+ DFSDM_CR1_JEXTEN(jexten)); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static int stm32_dfsdm_channels_configure(struct stm32_dfsdm_adc *adc, -+ unsigned int fl_id, -+ struct iio_trigger *trig) -+{ -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct regmap *regmap = adc->dfsdm->regmap; -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id]; -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[0]; -+ const struct iio_chan_spec *chan; -+ unsigned int bit; -+ int ret; -+ -+ fl->fast = 0; -+ -+ /* -+ * In continuous mode, use fast mode configuration, -+ * if it provides a better resolution. -+ */ -+ if (adc->nconv == 1 && !trig && -+ (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)) { -+ if (fl->flo[1].res >= fl->flo[0].res) { -+ fl->fast = 1; -+ flo = &fl->flo[1]; -+ } -+ } -+ -+ if (!flo->res) -+ return -EINVAL; -+ -+ for_each_set_bit(bit, &adc->smask, -+ sizeof(adc->smask) * BITS_PER_BYTE) { -+ chan = indio_dev->channels + bit; -+ -+ ret = regmap_update_bits(regmap, -+ DFSDM_CHCFGR2(chan->channel), -+ DFSDM_CHCFGR2_DTRBS_MASK, -+ DFSDM_CHCFGR2_DTRBS(flo->rshift)); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc, -+ unsigned int fl_id, -+ struct iio_trigger *trig) -+{ -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ struct regmap *regmap = adc->dfsdm->regmap; -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id]; -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; -+ u32 cr1; -+ const struct iio_chan_spec *chan; -+ unsigned int bit, jchg = 0; - int ret; - - /* Average integrator oversampling */ - ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK, -- DFSDM_FCR_IOSR(fl->iosr - 1)); -+ DFSDM_FCR_IOSR(flo->iosr - 1)); - if (ret) - return ret; - - /* Filter order and Oversampling */ - ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK, -- DFSDM_FCR_FOSR(fl->fosr - 1)); -+ DFSDM_FCR_FOSR(flo->fosr - 1)); - if (ret) - return ret; - -@@ -286,15 +530,74 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, - if (ret) - return ret; - -- /* No scan mode supported for the moment */ -- ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, -- DFSDM_CR1_RCH(ch_id)); -+ ret = stm32_dfsdm_filter_set_trig(adc, fl_id, trig); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), -+ DFSDM_CR1_FAST_MASK, -+ DFSDM_CR1_FAST(fl->fast)); - if (ret) - return ret; - -- return regmap_update_bits(regmap, DFSDM_CR1(fl_id), -- DFSDM_CR1_RSYNC_MASK, -- DFSDM_CR1_RSYNC(fl->sync_mode)); -+ /* -+ * DFSDM modes configuration W.R.T audio/iio type modes -+ * ---------------------------------------------------------------- -+ * Modes | regular | regular | injected | injected | -+ * | | continuous | | + scan | -+ * --------------|---------|--------------|----------|------------| -+ * single conv | x | | | | -+ * (1 chan) | | | | | -+ * --------------|---------|--------------|----------|------------| -+ * 1 Audio chan | | sample freq | | | -+ * | | or sync_mode | | | -+ * --------------|---------|--------------|----------|------------| -+ * 1 IIO chan | | sample freq | trigger | | -+ * | | or sync_mode | | | -+ * --------------|---------|--------------|----------|------------| -+ * 2+ IIO chans | | | | trigger or | -+ * | | | | sync_mode | -+ * ---------------------------------------------------------------- -+ */ -+ if (adc->nconv == 1 && !trig) { -+ bit = __ffs(adc->smask); -+ chan = indio_dev->channels + bit; -+ -+ /* Use regular conversion for single channel without trigger */ -+ cr1 = DFSDM_CR1_RCH(chan->channel); -+ -+ /* Continuous conversions triggered by SPI clock in buffer mode */ -+ if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE) -+ cr1 |= DFSDM_CR1_RCONT(1); -+ -+ cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode); -+ } else { -+ /* Use injected conversion for multiple channels */ -+ for_each_set_bit(bit, &adc->smask, -+ sizeof(adc->smask) * BITS_PER_BYTE) { -+ chan = indio_dev->channels + bit; -+ jchg |= BIT(chan->channel); -+ } -+ ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg); -+ if (ret < 0) -+ return ret; -+ -+ /* Use scan mode for multiple channels */ -+ cr1 = DFSDM_CR1_JSCAN(!!(adc->nconv > 1)); -+ -+ /* -+ * Continuous conversions not supported in injected mode, -+ * either use: -+ * - conversions in sync with filter 0 -+ * - triggered conversions -+ */ -+ if (!fl->sync_mode && !trig) -+ return -EINVAL; -+ cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode); -+ } -+ -+ return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK, -+ cr1); - } - - static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, -@@ -378,13 +681,36 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, - return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); - } - -+static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev, -+ unsigned int sample_freq, -+ unsigned int spi_freq) -+{ -+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ unsigned int oversamp; -+ int ret; -+ -+ oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq); -+ if (spi_freq % sample_freq) -+ dev_dbg(&indio_dev->dev, -+ "Rate not accurate. requested (%u), actual (%u)\n", -+ sample_freq, spi_freq / oversamp); -+ -+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, oversamp); -+ if (ret < 0) -+ return ret; -+ -+ adc->sample_freq = spi_freq / oversamp; -+ adc->oversamp = oversamp; -+ -+ return 0; -+} -+ - static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, - uintptr_t priv, - const struct iio_chan_spec *chan, - const char *buf, size_t len) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; - struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; - unsigned int sample_freq = adc->sample_freq; - unsigned int spi_freq; -@@ -403,17 +729,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, - return -EINVAL; - - if (sample_freq) { -- if (spi_freq % sample_freq) -- dev_warn(&indio_dev->dev, -- "Sampling rate not accurate (%d)\n", -- spi_freq / (spi_freq / sample_freq)); -- -- ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq)); -- if (ret < 0) { -- dev_err(&indio_dev->dev, -- "No filter parameters that match!\n"); -+ ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq); -+ if (ret < 0) - return ret; -- } - } - adc->spi_freq = spi_freq; - -@@ -421,72 +739,48 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, - } - - static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, -- const struct iio_chan_spec *chan, -- bool dma) -+ struct iio_trigger *trig) - { - struct regmap *regmap = adc->dfsdm->regmap; - int ret; -- unsigned int dma_en = 0, cont_en = 0; - -- ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel); -+ ret = stm32_dfsdm_channels_configure(adc, adc->fl_id, trig); - if (ret < 0) - return ret; - -- ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, -- chan->channel); -- if (ret < 0) -- goto stop_channels; -- -- if (dma) { -- /* Enable DMA transfer*/ -- dma_en = DFSDM_CR1_RDMAEN(1); -- /* Enable conversion triggered by SPI clock*/ -- cont_en = DFSDM_CR1_RCONT(1); -- } -- /* Enable DMA transfer*/ -- ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RDMAEN_MASK, dma_en); -+ ret = stm32_dfsdm_start_channel(adc); - if (ret < 0) -- goto stop_channels; -+ return ret; - -- /* Enable conversion triggered by SPI clock*/ -- ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RCONT_MASK, cont_en); -+ ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, trig); - if (ret < 0) - goto stop_channels; - -- ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); -+ ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig); - if (ret < 0) -- goto stop_channels; -+ goto filter_unconfigure; - - return 0; - --stop_channels: -+filter_unconfigure: - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RDMAEN_MASK, 0); -- -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RCONT_MASK, 0); -- stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); -+ DFSDM_CR1_CFG_MASK, 0); -+stop_channels: -+ stm32_dfsdm_stop_channel(adc); - - return ret; - } - --static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc, -- const struct iio_chan_spec *chan) -+static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) - { - struct regmap *regmap = adc->dfsdm->regmap; - - stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); - -- /* Clean conversion options */ - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RDMAEN_MASK, 0); -+ DFSDM_CR1_CFG_MASK, 0); - -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RCONT_MASK, 0); -- -- stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); -+ stm32_dfsdm_stop_channel(adc); - } - - static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, -@@ -494,6 +788,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; -+ unsigned int rx_buf_sz = DFSDM_DMA_BUFFER_SIZE; - - /* - * DMA cyclic transfers are used, buffer is split into two periods. -@@ -502,7 +797,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, - * - one buffer (period) driver pushed to ASoC side. - */ - watermark = min(watermark, val * (unsigned int)(sizeof(u32))); -- adc->buf_sz = watermark * 2; -+ adc->buf_sz = min(rx_buf_sz, watermark * 2 * adc->nconv); - - return 0; - } -@@ -532,13 +827,67 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) - return 0; - } - --static void stm32_dfsdm_audio_dma_buffer_done(void *data) -+static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc, -+ s32 *buffer) -+{ -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; -+ unsigned int i = adc->nconv; -+ s32 *ptr = buffer; -+ -+ while (i--) { -+ /* Mask 8 LSB that contains the channel ID */ -+ *ptr &= 0xFFFFFF00; -+ /* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */ -+ if (*ptr > flo->max) -+ *ptr -= 1; -+ /* -+ * Samples from filter are retrieved with 23 bits resolution -+ * or less. Shift left to align MSB on 24 bits. -+ */ -+ *ptr <<= flo->lshift; -+ -+ ptr++; -+ } -+} -+ -+static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p) -+{ -+ struct iio_poll_func *pf = p; -+ struct iio_dev *indio_dev = pf->indio_dev; -+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ int available = stm32_dfsdm_adc_dma_residue(adc); -+ -+ while (available >= indio_dev->scan_bytes) { -+ s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi]; -+ -+ stm32_dfsdm_process_data(adc, buffer); -+ -+ iio_push_to_buffers_with_timestamp(indio_dev, buffer, -+ pf->timestamp); -+ available -= indio_dev->scan_bytes; -+ adc->bufi += indio_dev->scan_bytes; -+ if (adc->bufi >= adc->buf_sz) -+ adc->bufi = 0; -+ } -+ -+ iio_trigger_notify_done(indio_dev->trig); -+ -+ return IRQ_HANDLED; -+} -+ -+static void stm32_dfsdm_dma_buffer_done(void *data) - { - struct iio_dev *indio_dev = data; - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - int available = stm32_dfsdm_adc_dma_residue(adc); - size_t old_pos; - -+ if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) { -+ iio_trigger_poll_chained(indio_dev->trig); -+ return; -+ } -+ - /* - * FIXME: In Kernel interface does not support cyclic DMA buffer,and - * offers only an interface to push data samples per samples. -@@ -553,10 +902,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) - old_pos = adc->bufi; - - while (available >= indio_dev->scan_bytes) { -- u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi]; -+ s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi]; -+ -+ stm32_dfsdm_process_data(adc, buffer); - -- /* Mask 8 LSB that contains the channel ID */ -- *buffer = (*buffer & 0xFFFFFF00) << 8; - available -= indio_dev->scan_bytes; - adc->bufi += indio_dev->scan_bytes; - if (adc->bufi >= adc->buf_sz) { -@@ -566,6 +915,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) - adc->bufi = 0; - old_pos = 0; - } -+ /* regular iio buffer without trigger */ -+ if (adc->dev_data->type == DFSDM_IIO) -+ iio_push_to_buffers(indio_dev, buffer); - } - if (adc->cb) - adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, -@@ -575,6 +927,15 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) - static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ /* -+ * The DFSDM supports half-word transfers. However, for 16 bits record, -+ * 4 bytes buswidth is kept, to avoid losing samples LSBs when left -+ * shift is required. -+ */ -+ struct dma_slave_config config = { -+ .src_addr = (dma_addr_t)adc->dfsdm->phys_base, -+ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, -+ }; - struct dma_async_tx_descriptor *desc; - dma_cookie_t cookie; - int ret; -@@ -585,6 +946,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) - dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, - adc->buf_sz, adc->buf_sz / 2); - -+ if (adc->nconv == 1 && !indio_dev->trig) -+ config.src_addr += DFSDM_RDATAR(adc->fl_id); -+ else -+ config.src_addr += DFSDM_JDATAR(adc->fl_id); -+ ret = dmaengine_slave_config(adc->dma_chan, &config); -+ if (ret) -+ return ret; -+ - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(adc->dma_chan, - adc->dma_buf, -@@ -594,71 +963,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) - if (!desc) - return -EBUSY; - -- desc->callback = stm32_dfsdm_audio_dma_buffer_done; -+ desc->callback = stm32_dfsdm_dma_buffer_done; - desc->callback_param = indio_dev; - - cookie = dmaengine_submit(desc); - ret = dma_submit_error(cookie); -- if (ret) { -- dmaengine_terminate_all(adc->dma_chan); -- return ret; -- } -+ if (ret) -+ goto err_stop_dma; - - /* Issue pending DMA requests */ - dma_async_issue_pending(adc->dma_chan); - -+ if (adc->nconv == 1 && !indio_dev->trig) { -+ /* Enable regular DMA transfer*/ -+ ret = regmap_update_bits(adc->dfsdm->regmap, -+ DFSDM_CR1(adc->fl_id), -+ DFSDM_CR1_RDMAEN_MASK, -+ DFSDM_CR1_RDMAEN_MASK); -+ } else { -+ /* Enable injected DMA transfer*/ -+ ret = regmap_update_bits(adc->dfsdm->regmap, -+ DFSDM_CR1(adc->fl_id), -+ DFSDM_CR1_JDMAEN_MASK, -+ DFSDM_CR1_JDMAEN_MASK); -+ } -+ -+ if (ret < 0) -+ goto err_stop_dma; -+ - return 0; -+ -+err_stop_dma: -+ dmaengine_terminate_all(adc->dma_chan); -+ -+ return ret; - } - --static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) -+static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev) -+{ -+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ -+ if (!adc->dma_chan) -+ return; -+ -+ regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), -+ DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0); -+ dmaengine_terminate_all(adc->dma_chan); -+} -+ -+static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev, -+ const unsigned long *scan_mask) -+{ -+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ -+ adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength); -+ adc->smask = *scan_mask; -+ -+ dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask); -+ -+ return 0; -+} -+ -+static int __stm32_dfsdm_postenable(struct iio_dev *indio_dev) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- const struct iio_chan_spec *chan = &indio_dev->channels[0]; - int ret; - - /* Reset adc buffer index */ - adc->bufi = 0; - -+ if (adc->hwc) { -+ ret = iio_hw_consumer_enable(adc->hwc); -+ if (ret < 0) -+ return ret; -+ } -+ - ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); - if (ret < 0) -- return ret; -+ goto err_stop_hwc; - -- ret = stm32_dfsdm_start_conv(adc, chan, true); -+ ret = stm32_dfsdm_adc_dma_start(indio_dev); - if (ret) { -- dev_err(&indio_dev->dev, "Can't start conversion\n"); -+ dev_err(&indio_dev->dev, "Can't start DMA\n"); - goto stop_dfsdm; - } - -- if (adc->dma_chan) { -- ret = stm32_dfsdm_adc_dma_start(indio_dev); -- if (ret) { -- dev_err(&indio_dev->dev, "Can't start DMA\n"); -- goto err_stop_conv; -- } -+ ret = stm32_dfsdm_start_conv(adc, indio_dev->trig); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Can't start conversion\n"); -+ goto err_stop_dma; - } - - return 0; - --err_stop_conv: -- stm32_dfsdm_stop_conv(adc, chan); -+err_stop_dma: -+ stm32_dfsdm_adc_dma_stop(indio_dev); - stop_dfsdm: - stm32_dfsdm_stop_dfsdm(adc->dfsdm); -+err_stop_hwc: -+ if (adc->hwc) -+ iio_hw_consumer_disable(adc->hwc); - - return ret; - } - --static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) -+static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) -+{ -+ int ret; -+ -+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { -+ ret = iio_triggered_buffer_postenable(indio_dev); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = __stm32_dfsdm_postenable(indio_dev); -+ if (ret < 0) -+ goto err_predisable; -+ -+ return 0; -+ -+err_predisable: -+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) -+ iio_triggered_buffer_predisable(indio_dev); -+ -+ return ret; -+} -+ -+static void __stm32_dfsdm_predisable(struct iio_dev *indio_dev) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- const struct iio_chan_spec *chan = &indio_dev->channels[0]; - -- if (adc->dma_chan) -- dmaengine_terminate_all(adc->dma_chan); -+ stm32_dfsdm_stop_conv(adc); - -- stm32_dfsdm_stop_conv(adc, chan); -+ stm32_dfsdm_adc_dma_stop(indio_dev); - - stm32_dfsdm_stop_dfsdm(adc->dfsdm); - -+ if (adc->hwc) -+ iio_hw_consumer_disable(adc->hwc); -+} -+ -+static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) -+{ -+ __stm32_dfsdm_predisable(indio_dev); -+ -+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) -+ iio_triggered_buffer_predisable(indio_dev); -+ - return 0; - } - -@@ -736,7 +1188,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, - if (ret < 0) - goto stop_dfsdm; - -- ret = stm32_dfsdm_start_conv(adc, chan, false); -+ adc->nconv = 1; -+ adc->smask = BIT(chan->scan_index); -+ ret = stm32_dfsdm_start_conv(adc, NULL); - if (ret < 0) { - regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), - DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); -@@ -757,7 +1211,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, - else - ret = IIO_VAL_INT; - -- stm32_dfsdm_stop_conv(adc, chan); -+ stm32_dfsdm_stop_conv(adc); -+ -+ stm32_dfsdm_process_data(adc, res); - - stop_dfsdm: - stm32_dfsdm_stop_dfsdm(adc->dfsdm); -@@ -770,49 +1226,50 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, - int val, int val2, long mask) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; - struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; - unsigned int spi_freq; - int ret = -EINVAL; - -+ switch (ch->src) { -+ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: -+ spi_freq = adc->dfsdm->spi_master_freq; -+ break; -+ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: -+ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: -+ spi_freq = adc->dfsdm->spi_master_freq / 2; -+ break; -+ default: -+ spi_freq = adc->spi_freq; -+ } -+ - switch (mask) { - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -- ret = stm32_dfsdm_set_osrs(fl, 0, val); -- if (!ret) -- adc->oversamp = val; -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; - -+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, val); -+ if (!ret) { -+ dev_dbg(&indio_dev->dev, -+ "Sampling rate changed from (%u) to (%u)\n", -+ adc->sample_freq, spi_freq / val); -+ adc->oversamp = val; -+ adc->sample_freq = spi_freq / val; -+ } -+ iio_device_release_direct_mode(indio_dev); - return ret; - - case IIO_CHAN_INFO_SAMP_FREQ: - if (!val) - return -EINVAL; - -- switch (ch->src) { -- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: -- spi_freq = adc->dfsdm->spi_master_freq; -- break; -- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: -- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: -- spi_freq = adc->dfsdm->spi_master_freq / 2; -- break; -- default: -- spi_freq = adc->spi_freq; -- } -- -- if (spi_freq % val) -- dev_warn(&indio_dev->dev, -- "Sampling rate not accurate (%d)\n", -- spi_freq / (spi_freq / val)); -- -- ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val)); -- if (ret < 0) { -- dev_err(&indio_dev->dev, -- "Not able to find parameter that match!\n"); -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) - return ret; -- } -- adc->sample_freq = val; - -- return 0; -+ ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq); -+ iio_device_release_direct_mode(indio_dev); -+ return ret; - } - - return -EINVAL; -@@ -823,15 +1280,22 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, - int *val2, long mask) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- int ret; -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; -+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; -+ u32 max = flo->max << (flo->lshift - chan->scan_type.shift); -+ int ret, idx = chan->scan_index; - - switch (mask) { - case IIO_CHAN_INFO_RAW: -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; - ret = iio_hw_consumer_enable(adc->hwc); - if (ret < 0) { - dev_err(&indio_dev->dev, - "%s: IIO enable failed (channel %d)\n", - __func__, chan->channel); -+ iio_device_release_direct_mode(indio_dev); - return ret; - } - ret = stm32_dfsdm_single_conv(indio_dev, chan, val); -@@ -840,8 +1304,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, - dev_err(&indio_dev->dev, - "%s: Conversion failed (channel %d)\n", - __func__, chan->channel); -+ iio_device_release_direct_mode(indio_dev); - return ret; - } -+ iio_device_release_direct_mode(indio_dev); - return IIO_VAL_INT; - - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -@@ -853,20 +1319,63 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, - *val = adc->sample_freq; - - return IIO_VAL_INT; -+ -+ case IIO_CHAN_INFO_SCALE: -+ /* -+ * Scale is expressed in mV. -+ * When fast mode is disabled, actual resolution may be lower -+ * than 2^n, where n=realbits-1. -+ * This leads to underestimating input voltage. To -+ * compensate this deviation, the voltage reference can be -+ * corrected with a factor = realbits resolution / actual max -+ */ -+ *val = div_u64((u64)adc->sd_chan[idx].scale_val * -+ (u64)BIT(DFSDM_DATA_RES - 1), max); -+ *val2 = chan->scan_type.realbits; -+ if (adc->sd_chan[idx].differential) -+ *val *= 2; -+ return IIO_VAL_FRACTIONAL_LOG2; -+ -+ case IIO_CHAN_INFO_OFFSET: -+ /* -+ * DFSDM output data are in the range [-2^n,2^n-1], -+ * with n=realbits-1. -+ * - Differential modulator: -+ * Offset correspond to SD modulator offset. -+ * - Single ended modulator: -+ * Input is in [0V,Vref] range, where 0V corresponds to -2^n. -+ * Add 2^n to offset. (i.e. middle of input range) -+ * offset = offset(sd) * vref / res(sd) * max / vref. -+ */ -+ *val = div_u64((u64)max * adc->sd_chan[idx].offset, -+ BIT(adc->sd_chan[idx].scale_val2 - 1)); -+ if (!adc->sd_chan[idx].differential) -+ *val += max; -+ return IIO_VAL_INT; - } - - return -EINVAL; - } - -+static int stm32_dfsdm_validate_trigger(struct iio_dev *indio_dev, -+ struct iio_trigger *trig) -+{ -+ return stm32_dfsdm_get_jextsel(indio_dev, trig) < 0 ? -EINVAL : 0; -+} -+ - static const struct iio_info stm32_dfsdm_info_audio = { - .hwfifo_set_watermark = stm32_dfsdm_set_watermark, - .read_raw = stm32_dfsdm_read_raw, - .write_raw = stm32_dfsdm_write_raw, -+ .update_scan_mode = stm32_dfsdm_update_scan_mode, - }; - - static const struct iio_info stm32_dfsdm_info_adc = { -+ .hwfifo_set_watermark = stm32_dfsdm_set_watermark, - .read_raw = stm32_dfsdm_read_raw, - .write_raw = stm32_dfsdm_write_raw, -+ .update_scan_mode = stm32_dfsdm_update_scan_mode, -+ .validate_trigger = stm32_dfsdm_validate_trigger, - }; - - static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) -@@ -926,12 +1435,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) - static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -- struct dma_slave_config config = { -- .src_addr = (dma_addr_t)adc->dfsdm->phys_base + -- DFSDM_RDATAR(adc->fl_id), -- .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, -- }; -- int ret; - - adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); - if (!adc->dma_chan) -@@ -941,23 +1444,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) - DFSDM_DMA_BUFFER_SIZE, - &adc->dma_buf, GFP_KERNEL); - if (!adc->rx_buf) { -- ret = -ENOMEM; -- goto err_release; -+ dma_release_channel(adc->dma_chan); -+ return -ENOMEM; - } - -- ret = dmaengine_slave_config(adc->dma_chan, &config); -- if (ret) -- goto err_free; -+ indio_dev->modes |= INDIO_BUFFER_SOFTWARE; -+ indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; - - return 0; -- --err_free: -- dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE, -- adc->rx_buf, adc->dma_buf); --err_release: -- dma_release_channel(adc->dma_chan); -- -- return ret; - } - - static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, -@@ -977,8 +1471,11 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, - * IIO_CHAN_INFO_RAW: used to compute regular conversion - * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling - */ -- ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); -- ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); -+ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | -+ BIT(IIO_CHAN_INFO_SCALE) | -+ BIT(IIO_CHAN_INFO_OFFSET); -+ ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | -+ BIT(IIO_CHAN_INFO_SAMP_FREQ); - - if (adc->dev_data->type == DFSDM_AUDIO) { - ch->ext_info = dfsdm_adc_audio_ext_info; -@@ -986,7 +1483,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, - ch->scan_type.shift = 8; - } - ch->scan_type.sign = 's'; -- ch->scan_type.realbits = 24; -+ ch->scan_type.realbits = DFSDM_DATA_RES; - ch->scan_type.storagebits = 32; - - return stm32_dfsdm_chan_configure(adc->dfsdm, -@@ -1000,9 +1497,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) - struct stm32_dfsdm_channel *d_ch; - int ret; - -- indio_dev->modes |= INDIO_BUFFER_SOFTWARE; -- indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; -- - ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); - if (!ch) - return -ENOMEM; -@@ -1030,12 +1524,13 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - { - struct iio_chan_spec *ch; - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ struct iio_channel *channels, *chan; -+ struct stm32_dfsdm_sd_chan_info *sd_chan; - int num_ch; -- int ret, chan_idx; -+ int ret, chan_idx, val2; - - adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; -- ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0, -- adc->oversamp); -+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); - if (ret < 0) - return ret; - -@@ -1056,6 +1551,21 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - if (!ch) - return -ENOMEM; - -+ /* Get SD modulator channels */ -+ channels = iio_channel_get_all(&indio_dev->dev); -+ if (IS_ERR(channels)) { -+ dev_err(&indio_dev->dev, "Failed to get channel %ld\n", -+ PTR_ERR(channels)); -+ return PTR_ERR(channels); -+ } -+ chan = &channels[0]; -+ -+ adc->sd_chan = devm_kzalloc(&indio_dev->dev, -+ sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL); -+ if (!adc->sd_chan) -+ return -ENOMEM; -+ sd_chan = adc->sd_chan; -+ - for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { - ch[chan_idx].scan_index = chan_idx; - ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); -@@ -1063,6 +1573,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - dev_err(&indio_dev->dev, "Channels init failed\n"); - return ret; - } -+ -+ if (!chan->indio_dev) -+ return -EINVAL; -+ -+ ret = iio_read_channel_scale(chan, &sd_chan->scale_val, -+ &sd_chan->scale_val2); -+ if (ret < 0) { -+ dev_err(&indio_dev->dev, -+ "Failed to get channel %d scale\n", chan_idx); -+ return ret; -+ } -+ -+ if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) { -+ ret = iio_read_channel_offset(chan, &sd_chan->offset, -+ &val2); -+ if (ret < 0) { -+ dev_err(&indio_dev->dev, -+ "Failed to get channel %d offset\n", -+ chan_idx); -+ return ret; -+ } -+ } -+ -+ sd_chan->differential = chan->channel->differential; -+ -+ dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d", -+ chan_idx, chan->channel->differential ? -+ "differential" : "single-ended", -+ sd_chan->scale_val, sd_chan->offset); -+ -+ chan++; -+ sd_chan++; - } - - indio_dev->num_channels = num_ch; -@@ -1070,6 +1612,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - - init_completion(&adc->completion); - -+ /* Optionally request DMA */ -+ if (stm32_dfsdm_dma_request(indio_dev)) { -+ dev_dbg(&indio_dev->dev, "No DMA support\n"); -+ return 0; -+ } -+ -+ ret = iio_triggered_buffer_setup(indio_dev, -+ &iio_pollfunc_store_time, -+ &stm32_dfsdm_adc_trigger_handler, -+ &stm32_dfsdm_buffer_setup_ops); -+ if (ret) { -+ stm32_dfsdm_dma_release(indio_dev); -+ dev_err(&indio_dev->dev, "buffer setup failed\n"); -+ return ret; -+ } -+ -+ /* lptimer/timer hardware triggers */ -+ indio_dev->modes |= INDIO_HARDWARE_TRIGGERED; -+ - return 0; - } - -@@ -1117,7 +1678,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) - - iio->dev.parent = dev; - iio->dev.of_node = np; -- iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; -+ iio->modes = INDIO_DIRECT_MODE; - - platform_set_drvdata(pdev, adc); - -@@ -1209,10 +1770,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) - return 0; - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_dfsdm_adc_suspend(struct device *dev) -+{ -+ struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ -+ if (iio_buffer_enabled(indio_dev)) -+ __stm32_dfsdm_predisable(indio_dev); -+ -+ return 0; -+} -+static int stm32_dfsdm_adc_resume(struct device *dev) -+{ -+ struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); -+ struct iio_dev *indio_dev = iio_priv_to_dev(adc); -+ const struct iio_chan_spec *chan; -+ struct stm32_dfsdm_channel *ch; -+ int i, ret; -+ -+ /* restore channels configuration */ -+ for (i = 0; i < indio_dev->num_channels; i++) { -+ chan = indio_dev->channels + i; -+ ch = &adc->dfsdm->ch_list[chan->channel]; -+ ret = stm32_dfsdm_chan_configure(adc->dfsdm, ch); -+ if (ret) -+ return ret; -+ } -+ -+ if (iio_buffer_enabled(indio_dev)) -+ __stm32_dfsdm_postenable(indio_dev); -+ -+ return 0; -+} -+#endif -+static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops, -+ stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume); -+ - static struct platform_driver stm32_dfsdm_adc_driver = { - .driver = { - .name = "stm32-dfsdm-adc", - .of_match_table = stm32_dfsdm_adc_match, -+ .pm = &stm32_dfsdm_adc_pm_ops, - }, - .probe = stm32_dfsdm_adc_probe, - .remove = stm32_dfsdm_adc_remove, -diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c -index 9416306..9609515 100644 ---- a/drivers/iio/adc/stm32-dfsdm-core.c -+++ b/drivers/iio/adc/stm32-dfsdm-core.c -@@ -12,6 +12,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - -@@ -90,6 +92,36 @@ struct dfsdm_priv { - struct clk *aclk; /* audio clock */ - }; - -+static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm) -+{ -+ return container_of(dfsdm, struct dfsdm_priv, dfsdm); -+} -+ -+static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm) -+{ -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); -+ int ret; -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret || !priv->aclk) -+ return ret; -+ -+ ret = clk_prepare_enable(priv->aclk); -+ if (ret) -+ clk_disable_unprepare(priv->clk); -+ -+ return ret; -+} -+ -+static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) -+{ -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); -+ -+ if (priv->aclk) -+ clk_disable_unprepare(priv->aclk); -+ clk_disable_unprepare(priv->clk); -+} -+ - /** - * stm32_dfsdm_start_dfsdm - start global dfsdm interface. - * -@@ -98,24 +130,17 @@ struct dfsdm_priv { - */ - int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) - { -- struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); - struct device *dev = &priv->pdev->dev; - unsigned int clk_div = priv->spi_clk_out_div, clk_src; - int ret; - - if (atomic_inc_return(&priv->n_active_ch) == 1) { -- ret = clk_prepare_enable(priv->clk); -+ ret = pm_runtime_get_sync(dev); - if (ret < 0) { -- dev_err(dev, "Failed to start clock\n"); -+ pm_runtime_put_noidle(dev); - goto error_ret; - } -- if (priv->aclk) { -- ret = clk_prepare_enable(priv->aclk); -- if (ret < 0) { -- dev_err(dev, "Failed to start audio clock\n"); -- goto disable_clk; -- } -- } - - /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ - clk_src = priv->aclk ? 1 : 0; -@@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) - DFSDM_CHCFGR1_CKOUTSRC_MASK, - DFSDM_CHCFGR1_CKOUTSRC(clk_src)); - if (ret < 0) -- goto disable_aclk; -+ goto pm_put; - - /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ - ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), - DFSDM_CHCFGR1_CKOUTDIV_MASK, - DFSDM_CHCFGR1_CKOUTDIV(clk_div)); - if (ret < 0) -- goto disable_aclk; -+ goto pm_put; - - /* Global enable of DFSDM interface */ - ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), - DFSDM_CHCFGR1_DFSDMEN_MASK, - DFSDM_CHCFGR1_DFSDMEN(1)); - if (ret < 0) -- goto disable_aclk; -+ goto pm_put; - } - - dev_dbg(dev, "%s: n_active_ch %d\n", __func__, -@@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) - - return 0; - --disable_aclk: -- clk_disable_unprepare(priv->aclk); --disable_clk: -- clk_disable_unprepare(priv->clk); -- -+pm_put: -+ pm_runtime_put_sync(dev); - error_ret: - atomic_dec(&priv->n_active_ch); - -@@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); - */ - int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) - { -- struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); - int ret; - - if (atomic_dec_and_test(&priv->n_active_ch)) { -@@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) - if (ret < 0) - return ret; - -- clk_disable_unprepare(priv->clk); -- if (priv->aclk) -- clk_disable_unprepare(priv->aclk); -+ pm_runtime_put_sync(&priv->pdev->dev); - } - dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, - atomic_read(&priv->n_active_ch)); -@@ -247,13 +267,18 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, - return 0; - } - -- priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; -+ priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem); -+ -+ /* round up divider when clkout isn't accurate (e.g. !rem) */ -+ if (priv->spi_clk_out_div && !rem) -+ priv->spi_clk_out_div--; -+ - if (!priv->spi_clk_out_div) { - /* spi_clk_out_div == 0 means ckout is OFF */ - dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); - return -EINVAL; - } -- priv->dfsdm.spi_master_freq = spi_freq; -+ priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1); - - if (rem) { - dev_warn(&pdev->dev, "SPI clock not accurate\n"); -@@ -322,14 +347,115 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, dfsdm); - -- return devm_of_platform_populate(&pdev->dev); -+ ret = stm32_dfsdm_clk_prepare_enable(dfsdm); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to start clock\n"); -+ return ret; -+ } -+ -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ -+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); -+ if (ret) -+ goto pm_put; -+ -+ pm_runtime_put(&pdev->dev); -+ -+ return 0; -+ -+pm_put: -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ stm32_dfsdm_clk_disable_unprepare(dfsdm); -+ -+ return ret; - } - -+static int stm32_dfsdm_core_remove(struct platform_device *pdev) -+{ -+ struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); -+ -+ pm_runtime_get_sync(&pdev->dev); -+ of_platform_depopulate(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ stm32_dfsdm_clk_disable_unprepare(dfsdm); -+ -+ return 0; -+} -+ -+#if defined CONFIG_PM_SLEEP -+static int stm32_dfsdm_core_suspend(struct device *dev) -+{ -+ struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); -+ int ret; -+ -+ ret = pm_runtime_force_suspend(dev); -+ if (ret) -+ return ret; -+ -+ /* Balance devm_regmap_init_mmio_clk() clk_prepare() */ -+ clk_unprepare(priv->clk); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_dfsdm_core_resume(struct device *dev) -+{ -+ struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); -+ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare(priv->clk); -+ if (ret) -+ return ret; -+ -+ return pm_runtime_force_resume(dev); -+} -+#endif -+ -+#ifdef CONFIG_PM -+static int stm32_dfsdm_core_runtime_suspend(struct device *dev) -+{ -+ struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); -+ -+ stm32_dfsdm_clk_disable_unprepare(dfsdm); -+ -+ return 0; -+} -+ -+static int stm32_dfsdm_core_runtime_resume(struct device *dev) -+{ -+ struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); -+ -+ return stm32_dfsdm_clk_prepare_enable(dfsdm); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, -+ stm32_dfsdm_core_resume) -+ SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, -+ stm32_dfsdm_core_runtime_resume, -+ NULL) -+}; -+ - static struct platform_driver stm32_dfsdm_driver = { - .probe = stm32_dfsdm_probe, -+ .remove = stm32_dfsdm_core_remove, - .driver = { - .name = "stm32-dfsdm", - .of_match_table = stm32_dfsdm_of_match, -+ .pm = &stm32_dfsdm_core_pm_ops, - }, - }; - -diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h -index 8708394..5dbdae4 100644 ---- a/drivers/iio/adc/stm32-dfsdm.h -+++ b/drivers/iio/adc/stm32-dfsdm.h -@@ -243,19 +243,33 @@ enum stm32_dfsdm_sinc_order { - }; - - /** -- * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter -+ * struct stm32_dfsdm_filter_osr - DFSDM filter settings linked to oversampling - * @iosr: integrator oversampling - * @fosr: filter oversampling -- * @ford: filter order -+ * @rshift: output sample right shift (hardware shift) -+ * @lshift: output sample left shift (software shift) - * @res: output sample resolution -+ * @max: output sample maximum positive value -+ */ -+struct stm32_dfsdm_filter_osr { -+ unsigned int iosr; -+ unsigned int fosr; -+ unsigned int rshift; -+ unsigned int lshift; -+ u64 res; -+ s32 max; -+}; -+ -+/** -+ * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter -+ * @ford: filter order -+ * @flo: filter oversampling data table indexed by fast mode flag - * @sync_mode: filter synchronized with filter 0 - * @fast: filter fast mode - */ - struct stm32_dfsdm_filter { -- unsigned int iosr; -- unsigned int fosr; - enum stm32_dfsdm_sinc_order ford; -- u64 res; -+ struct stm32_dfsdm_filter_osr flo[2]; - unsigned int sync_mode; - unsigned int fast; - }; -diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c -index 42fb8ba..2a49cce0e 100644 ---- a/drivers/iio/counter/stm32-lptimer-cnt.c -+++ b/drivers/iio/counter/stm32-lptimer-cnt.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - - struct stm32_lptim_cnt { -@@ -23,6 +24,7 @@ struct stm32_lptim_cnt { - u32 preset; - u32 polarity; - u32 quadrature_mode; -+ bool enabled; - }; - - static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) -@@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, - - if (!enable) { - clk_disable(priv->clk); -+ priv->enabled = false; - return 0; - } - -@@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, - regmap_write(priv->regmap, STM32_LPTIM_CR, 0); - return ret; - } -+ priv->enabled = true; - - /* Start LP timer in continuous mode */ - return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, -@@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) - return devm_iio_device_register(&pdev->dev, indio_dev); - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_lptim_cnt_suspend(struct device *dev) -+{ -+ struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ /* Only take care of enabled counter: don't disturb other MFD child */ -+ if (priv->enabled) { -+ ret = stm32_lptim_setup(priv, 0); -+ if (ret) -+ return ret; -+ -+ ret = stm32_lptim_set_enable_state(priv, 0); -+ if (ret) -+ return ret; -+ -+ /* Force enable state for later resume */ -+ priv->enabled = true; -+ } -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_lptim_cnt_resume(struct device *dev) -+{ -+ struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; -+ -+ if (priv->enabled) { -+ priv->enabled = false; -+ ret = stm32_lptim_setup(priv, 1); -+ if (ret) -+ return ret; -+ -+ ret = stm32_lptim_set_enable_state(priv, 1); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend, -+ stm32_lptim_cnt_resume); -+ - static const struct of_device_id stm32_lptim_cnt_of_match[] = { - { .compatible = "st,stm32-lptimer-counter", }, - {}, -@@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = { - .driver = { - .name = "stm32-lptimer-counter", - .of_match_table = stm32_lptim_cnt_of_match, -+ .pm = &stm32_lptim_cnt_pm_ops, - }, - }; - module_platform_driver(stm32_lptim_cnt_driver); -diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c -index d0fb312..280322b 100644 ---- a/drivers/iio/dac/stm32-dac-core.c -+++ b/drivers/iio/dac/stm32-dac-core.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -50,6 +51,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = { - .max_register = 0x3fc, - }; - -+static int stm32_dac_core_hw_start(struct device *dev) -+{ -+ struct stm32_dac_common *common = dev_get_drvdata(dev); -+ struct stm32_dac_priv *priv = to_stm32_dac_priv(common); -+ int ret; -+ -+ ret = regulator_enable(priv->vref); -+ if (ret < 0) { -+ dev_err(dev, "vref enable failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(priv->pclk); -+ if (ret < 0) { -+ dev_err(dev, "pclk enable failed: %d\n", ret); -+ goto err_regulator_disable; -+ } -+ -+ return 0; -+ -+err_regulator_disable: -+ regulator_disable(priv->vref); -+ -+ return ret; -+} -+ -+static void stm32_dac_core_hw_stop(struct device *dev) -+{ -+ struct stm32_dac_common *common = dev_get_drvdata(dev); -+ struct stm32_dac_priv *priv = to_stm32_dac_priv(common); -+ -+ clk_disable_unprepare(priv->pclk); -+ regulator_disable(priv->vref); -+} -+ - static int stm32_dac_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -66,6 +102,8 @@ static int stm32_dac_probe(struct platform_device *pdev) - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; -+ platform_set_drvdata(pdev, &priv->common); -+ - cfg = (const struct stm32_dac_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; - -@@ -74,11 +112,19 @@ static int stm32_dac_probe(struct platform_device *pdev) - if (IS_ERR(mmio)) - return PTR_ERR(mmio); - -- regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg); -+ regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio, -+ &stm32_dac_regmap_cfg); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - priv->common.regmap = regmap; - -+ priv->pclk = devm_clk_get(dev, "pclk"); -+ if (IS_ERR(priv->pclk)) { -+ ret = PTR_ERR(priv->pclk); -+ dev_err(dev, "pclk get failed\n"); -+ return ret; -+ } -+ - priv->vref = devm_regulator_get(dev, "vref"); - if (IS_ERR(priv->vref)) { - ret = PTR_ERR(priv->vref); -@@ -86,33 +132,22 @@ static int stm32_dac_probe(struct platform_device *pdev) - return ret; - } - -- ret = regulator_enable(priv->vref); -- if (ret < 0) { -- dev_err(dev, "vref enable failed\n"); -- return ret; -- } -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ -+ ret = stm32_dac_core_hw_start(dev); -+ if (ret) -+ goto err_pm_stop; - - ret = regulator_get_voltage(priv->vref); - if (ret < 0) { - dev_err(dev, "vref get voltage failed, %d\n", ret); -- goto err_vref; -+ goto err_hw_stop; - } - priv->common.vref_mv = ret / 1000; - dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv); - -- priv->pclk = devm_clk_get(dev, "pclk"); -- if (IS_ERR(priv->pclk)) { -- ret = PTR_ERR(priv->pclk); -- dev_err(dev, "pclk get failed\n"); -- goto err_vref; -- } -- -- ret = clk_prepare_enable(priv->pclk); -- if (ret < 0) { -- dev_err(dev, "pclk enable failed\n"); -- goto err_vref; -- } -- - priv->rst = devm_reset_control_get_exclusive(dev, NULL); - if (!IS_ERR(priv->rst)) { - reset_control_assert(priv->rst); -@@ -128,39 +163,83 @@ static int stm32_dac_probe(struct platform_device *pdev) - priv->common.hfsel ? - STM32H7_DAC_CR_HFSEL : 0); - if (ret) -- goto err_pclk; -+ goto err_hw_stop; - } - -- platform_set_drvdata(pdev, &priv->common); - - ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev); - if (ret < 0) { - dev_err(dev, "failed to populate DT children\n"); -- goto err_pclk; -+ goto err_hw_stop; - } - -+ pm_runtime_put(dev); -+ - return 0; - --err_pclk: -- clk_disable_unprepare(priv->pclk); --err_vref: -- regulator_disable(priv->vref); -+err_hw_stop: -+ stm32_dac_core_hw_stop(dev); -+err_pm_stop: -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); - - return ret; - } - - static int stm32_dac_remove(struct platform_device *pdev) - { -- struct stm32_dac_common *common = platform_get_drvdata(pdev); -+ pm_runtime_get_sync(&pdev->dev); -+ of_platform_depopulate(&pdev->dev); -+ stm32_dac_core_hw_stop(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_PM_SLEEP) -+static int stm32_dac_core_resume(struct device *dev) -+{ -+ struct stm32_dac_common *common = dev_get_drvdata(dev); - struct stm32_dac_priv *priv = to_stm32_dac_priv(common); -+ int ret; - -- of_platform_depopulate(&pdev->dev); -- clk_disable_unprepare(priv->pclk); -- regulator_disable(priv->vref); -+ /* Unconditionally restore hfsel (maybe lost under low power state) */ -+ if (priv->common.hfsel) { -+ ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR, -+ STM32H7_DAC_CR_HFSEL, -+ STM32H7_DAC_CR_HFSEL); -+ if (ret) -+ return ret; -+ } -+ -+ return pm_runtime_force_resume(dev); -+} -+#endif -+ -+#if defined(CONFIG_PM) -+static int stm32_dac_core_runtime_suspend(struct device *dev) -+{ -+ stm32_dac_core_hw_stop(dev); - - return 0; - } - -+static int stm32_dac_core_runtime_resume(struct device *dev) -+{ -+ return stm32_dac_core_hw_start(dev); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_dac_core_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) -+ SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, -+ stm32_dac_core_runtime_resume, -+ NULL) -+}; -+ - static const struct stm32_dac_cfg stm32h7_dac_cfg = { - .has_hfsel = true, - }; -@@ -182,6 +261,7 @@ static struct platform_driver stm32_dac_driver = { - .driver = { - .name = "stm32-dac-core", - .of_match_table = stm32_dac_of_match, -+ .pm = &stm32_dac_core_pm_ops, - }, - }; - module_platform_driver(stm32_dac_driver); -diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c -index cce26a3..0a8abc5 100644 ---- a/drivers/iio/dac/stm32-dac.c -+++ b/drivers/iio/dac/stm32-dac.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "stm32-dac-core.h" - -@@ -20,6 +21,8 @@ - #define STM32_DAC_CHANNEL_2 2 - #define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1) - -+#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000 -+ - /** - * struct stm32_dac - private data of DAC driver - * @common: reference to DAC common data -@@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, - bool enable) - { - struct stm32_dac *dac = iio_priv(indio_dev); -+ struct device *dev = indio_dev->dev.parent; - u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2; - u32 en = enable ? msk : 0; - int ret; - -+ /* already enabled / disabled ? */ -+ mutex_lock(&indio_dev->mlock); -+ ret = stm32_dac_is_enabled(indio_dev, ch); -+ if (ret < 0 || enable == !!ret) { -+ mutex_unlock(&indio_dev->mlock); -+ return ret < 0 ? ret : 0; -+ } -+ -+ if (enable) { -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ mutex_unlock(&indio_dev->mlock); -+ return ret; -+ } -+ } -+ - ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en); -+ mutex_unlock(&indio_dev->mlock); - if (ret < 0) { - dev_err(&indio_dev->dev, "%s failed\n", en ? - "Enable" : "Disable"); -- return ret; -+ goto err_put_pm; - } - - /* -@@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, - if (en && dac->common->hfsel) - udelay(1); - -+ if (!enable) { -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ } -+ - return 0; -+ -+err_put_pm: -+ if (enable) { -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ } -+ -+ return ret; - } - - static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val) -@@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev) - static int stm32_dac_probe(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; - struct iio_dev *indio_dev; - struct stm32_dac *dac; - int ret; -@@ -296,9 +332,63 @@ static int stm32_dac_probe(struct platform_device *pdev) - if (ret < 0) - return ret; - -- return devm_iio_device_register(&pdev->dev, indio_dev); -+ /* Get stm32-dac-core PM online */ -+ pm_runtime_get_noresume(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_enable(dev); -+ -+ ret = iio_device_register(indio_dev); -+ if (ret) -+ goto err_pm_put; -+ -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ -+ return 0; -+ -+err_pm_put: -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); -+ -+ return ret; - } - -+static int stm32_dac_remove(struct platform_device *pdev) -+{ -+ struct iio_dev *indio_dev = platform_get_drvdata(pdev); -+ -+ pm_runtime_get_sync(&pdev->dev); -+ iio_device_unregister(indio_dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_PM_SLEEP) -+static int stm32_dac_suspend(struct device *dev) -+{ -+ struct iio_dev *indio_dev = dev_get_drvdata(dev); -+ int channel = indio_dev->channels[0].channel; -+ int ret; -+ -+ /* Ensure DAC is disabled before suspend */ -+ ret = stm32_dac_is_enabled(indio_dev, channel); -+ if (ret) -+ return ret < 0 ? ret : -EBUSY; -+ -+ return pm_runtime_force_suspend(dev); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_dac_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume) -+}; -+ - static const struct of_device_id stm32_dac_of_match[] = { - { .compatible = "st,stm32-dac", }, - {}, -@@ -307,9 +397,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); - - static struct platform_driver stm32_dac_driver = { - .probe = stm32_dac_probe, -+ .remove = stm32_dac_remove, - .driver = { - .name = "stm32-dac", - .of_match_table = stm32_dac_of_match, -+ .pm = &stm32_dac_pm_ops, - }, - }; - module_platform_driver(stm32_dac_driver); -diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c -index ccf1ce6..4a4ce3c 100644 ---- a/drivers/iio/trigger/stm32-timer-trigger.c -+++ b/drivers/iio/trigger/stm32-timer-trigger.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -79,10 +80,20 @@ struct stm32_timer_trigger { - struct device *dev; - struct regmap *regmap; - struct clk *clk; -+ bool clk_enabled; - u32 max_arr; - const void *triggers; - const void *valids; - bool has_trgo2; -+ struct mutex lock; /* concurrent sysfs configuration */ -+ unsigned int freq; -+ bool counter_en; -+ u32 cr1; -+ u32 cr2; -+ u32 psc; -+ u32 arr; -+ u32 cnt; -+ u32 smcr; - }; - - struct stm32_timer_trigger_cfg { -@@ -106,7 +117,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, - { - unsigned long long prd, div; - int prescaler = 0; -- u32 ccer, cr1; -+ u32 ccer; - - /* Period and prescaler values depends of clock rate */ - div = (unsigned long long)clk_get_rate(priv->clk); -@@ -136,9 +147,11 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, - if (ccer & TIM_CCER_CCXE) - return -EBUSY; - -- regmap_read(priv->regmap, TIM_CR1, &cr1); -- if (!(cr1 & TIM_CR1_CEN)) -+ mutex_lock(&priv->lock); -+ if (!priv->clk_enabled) { -+ priv->clk_enabled = true; - clk_enable(priv->clk); -+ } - - regmap_write(priv->regmap, TIM_PSC, prescaler); - regmap_write(priv->regmap, TIM_ARR, prd - 1); -@@ -157,30 +170,41 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, - - /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); -+ mutex_unlock(&priv->lock); - - return 0; - } - --static void stm32_timer_stop(struct stm32_timer_trigger *priv) -+static void stm32_timer_stop(struct stm32_timer_trigger *priv, -+ struct iio_trigger *trig) - { -- u32 ccer, cr1; -+ u32 ccer; - - regmap_read(priv->regmap, TIM_CCER, &ccer); - if (ccer & TIM_CCER_CCXE) - return; - -- regmap_read(priv->regmap, TIM_CR1, &cr1); -- if (cr1 & TIM_CR1_CEN) -- clk_disable(priv->clk); -- -+ mutex_lock(&priv->lock); - /* Stop timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); - regmap_write(priv->regmap, TIM_PSC, 0); - regmap_write(priv->regmap, TIM_ARR, 0); - -+ /* Force disable master mode */ -+ if (stm32_timer_is_trgo2_name(trig->name)) -+ regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); -+ else -+ regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0); -+ - /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); -+ -+ if (priv->clk_enabled) { -+ priv->clk_enabled = false; -+ clk_disable(priv->clk); -+ } -+ mutex_unlock(&priv->lock); - } - - static ssize_t stm32_tt_store_frequency(struct device *dev, -@@ -197,12 +221,13 @@ static ssize_t stm32_tt_store_frequency(struct device *dev, - return ret; - - if (freq == 0) { -- stm32_timer_stop(priv); -+ stm32_timer_stop(priv, trig); - } else { - ret = stm32_timer_start(priv, trig, freq); - if (ret) - return ret; - } -+ priv->freq = freq; - - return len; - } -@@ -295,11 +320,15 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, - for (i = 0; i <= master_mode_max; i++) { - if (!strncmp(master_mode_table[i], buf, - strlen(master_mode_table[i]))) { -+ mutex_lock(&priv->lock); -+ if (!priv->clk_enabled) { -+ /* Clock should be enabled first */ -+ priv->clk_enabled = true; -+ clk_enable(priv->clk); -+ } - regmap_update_bits(priv->regmap, TIM_CR2, mask, - i << shift); -- /* Make sure that registers are updated */ -- regmap_update_bits(priv->regmap, TIM_EGR, -- TIM_EGR_UG, TIM_EGR_UG); -+ mutex_unlock(&priv->lock); - return len; - } - } -@@ -437,7 +466,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, - int val, int val2, long mask) - { - struct stm32_timer_trigger *priv = iio_priv(indio_dev); -- u32 dat; - - switch (mask) { - case IIO_CHAN_INFO_RAW: -@@ -448,19 +476,24 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, - return -EINVAL; - - case IIO_CHAN_INFO_ENABLE: -+ mutex_lock(&priv->lock); - if (val) { -- regmap_read(priv->regmap, TIM_CR1, &dat); -- if (!(dat & TIM_CR1_CEN)) -+ if (!priv->clk_enabled) { -+ priv->clk_enabled = true; - clk_enable(priv->clk); -+ } - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - TIM_CR1_CEN); - } else { -- regmap_read(priv->regmap, TIM_CR1, &dat); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - 0); -- if (dat & TIM_CR1_CEN) -+ if (priv->clk_enabled) { -+ priv->clk_enabled = false; - clk_disable(priv->clk); -+ } - } -+ priv->counter_en = !!val; -+ mutex_unlock(&priv->lock); - return 0; - } - -@@ -556,7 +589,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, - { - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - int sms = stm32_enable_mode2sms(mode); -- u32 val; - - if (sms < 0) - return sms; -@@ -564,11 +596,12 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, - * Triggered mode sets CEN bit automatically by hardware. So, first - * enable counter clock, so it can use it. Keeps it in sync with CEN. - */ -- if (sms == 6) { -- regmap_read(priv->regmap, TIM_CR1, &val); -- if (!(val & TIM_CR1_CEN)) -- clk_enable(priv->clk); -+ mutex_lock(&priv->lock); -+ if (sms == 6 && !priv->clk_enabled) { -+ clk_enable(priv->clk); -+ priv->clk_enabled = true; - } -+ mutex_unlock(&priv->lock); - - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); - -@@ -836,6 +869,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) - priv->triggers = triggers_table[index]; - priv->valids = cfg->valids_table[index]; - stm32_timer_detect_trgo2(priv); -+ mutex_init(&priv->lock); - - ret = stm32_setup_iio_triggers(priv); - if (ret) -@@ -846,6 +880,91 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) - return 0; - } - -+static int stm32_timer_trigger_remove(struct platform_device *pdev) -+{ -+ struct stm32_timer_trigger *priv = platform_get_drvdata(pdev); -+ u32 val; -+ -+ /* Check if nobody else use the timer, then disable it */ -+ regmap_read(priv->regmap, TIM_CCER, &val); -+ if (!(val & TIM_CCER_CCXE)) -+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); -+ -+ if (priv->clk_enabled) -+ clk_disable(priv->clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_tt_suspend(struct device *dev) -+{ -+ struct stm32_timer_trigger *priv = dev_get_drvdata(dev); -+ -+ /* Disable the timer */ -+ if (priv->freq) -+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); -+ /* Register contents may be lost depending on low power mode. */ -+ regmap_read(priv->regmap, TIM_CR1, &priv->cr1); -+ regmap_read(priv->regmap, TIM_CR2, &priv->cr2); -+ regmap_read(priv->regmap, TIM_PSC, &priv->psc); -+ regmap_read(priv->regmap, TIM_ARR, &priv->arr); -+ regmap_read(priv->regmap, TIM_CNT, &priv->cnt); -+ regmap_read(priv->regmap, TIM_SMCR, &priv->smcr); -+ -+ if (priv->clk_enabled) -+ clk_disable(priv->clk); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_tt_resume(struct device *dev) -+{ -+ struct stm32_timer_trigger *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; -+ -+ if (priv->clk_enabled) { -+ ret = clk_enable(priv->clk); -+ if (ret) -+ return ret; -+ } -+ -+ /* restore master/slave modes */ -+ regmap_write(priv->regmap, TIM_SMCR, priv->smcr); -+ regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS | TIM_CR2_MMS2, -+ priv->cr2); -+ -+ if (priv->freq) { -+ /* restore sampling_frequency (trgo / trgo2 triggers) */ -+ regmap_write(priv->regmap, TIM_PSC, priv->psc); -+ regmap_write(priv->regmap, TIM_ARR, priv->arr); -+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, -+ TIM_CR1_ARPE); -+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, -+ TIM_EGR_UG); -+ } -+ -+ if (priv->counter_en) { -+ /* restore counter value, count_direction */ -+ regmap_write(priv->regmap, TIM_CNT, priv->cnt); -+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_DIR, -+ priv->cr1); -+ } -+ -+ if (priv->freq || priv->counter_en) -+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, -+ TIM_CR1_CEN); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_tt_pm_ops, stm32_tt_suspend, stm32_tt_resume); -+ - static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = { - .valids_table = valids_table, - .num_valids_table = ARRAY_SIZE(valids_table), -@@ -870,9 +989,11 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match); - - static struct platform_driver stm32_timer_trigger_driver = { - .probe = stm32_timer_trigger_probe, -+ .remove = stm32_timer_trigger_remove, - .driver = { - .name = "stm32-timer-trigger", - .of_match_table = stm32_trig_of_match, -+ .pm = &stm32_tt_pm_ops, - }, - }; - module_platform_driver(stm32_timer_trigger_driver); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch deleted file mode 100644 index 4ef2646..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch +++ /dev/null @@ -1,1166 +0,0 @@ -From b9a72771779e960b3ddf14d372ed6484cba99cbc Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:41 +0100 -Subject: [PATCH 12/31] ARM stm32mp1 r3 INPUT IRQ Mailbox - ---- - drivers/input/misc/Kconfig | 11 ++ - drivers/input/misc/Makefile | 2 + - drivers/input/misc/stpmic1_onkey.c | 198 +++++++++++++++++++ - drivers/input/touchscreen/edt-ft5x06.c | 24 ++- - drivers/input/touchscreen/goodix.c | 24 +++ - drivers/irqchip/irq-stm32-exti.c | 339 +++++++++++++++++++++++++++------ - drivers/mailbox/mailbox-test.c | 12 +- - drivers/mailbox/stm32-ipcc.c | 4 +- - kernel/irq/internals.h | 4 - - kernel/irq/manage.c | 75 ++------ - 10 files changed, 563 insertions(+), 130 deletions(-) - create mode 100644 drivers/input/misc/stpmic1_onkey.c - -diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index ca59a2b..279fb02 100644 ---- a/drivers/input/misc/Kconfig -+++ b/drivers/input/misc/Kconfig -@@ -851,4 +851,15 @@ config INPUT_SC27XX_VIBRA - To compile this driver as a module, choose M here. The module will - be called sc27xx_vibra. - -+config INPUT_STPMIC1_ONKEY -+ tristate "STPMIC1 PMIC Onkey support" -+ depends on MFD_STPMIC1 -+ help -+ Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey -+ can be used to wakeup from low power modes and force a shut-down on -+ long press. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called stpmic1_onkey. -+ - endif -diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index 9d0f9d1..1b44202 100644 ---- a/drivers/input/misc/Makefile -+++ b/drivers/input/misc/Makefile -@@ -71,6 +71,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o - obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o - obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o - obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o -+obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o - obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o - obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o - obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o -@@ -81,3 +82,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o - obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o - obj-$(CONFIG_INPUT_YEALINK) += yealink.o - obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o -+ -diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c -new file mode 100644 -index 0000000..7b49c99 ---- /dev/null -+++ b/drivers/input/misc/stpmic1_onkey.c -@@ -0,0 +1,198 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2018 -+// Author: Pascal Paillet for STMicroelectronics. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * struct stpmic1_onkey - OnKey data -+ * @input_dev: pointer to input device -+ * @irq_falling: irq that we are hooked on to -+ * @irq_rising: irq that we are hooked on to -+ */ -+struct stpmic1_onkey { -+ struct input_dev *input_dev; -+ int irq_falling; -+ int irq_rising; -+}; -+ -+static irqreturn_t onkey_falling_irq(int irq, void *ponkey) -+{ -+ struct stpmic1_onkey *onkey = ponkey; -+ struct input_dev *input_dev = onkey->input_dev; -+ -+ input_report_key(input_dev, KEY_POWER, 1); -+ pm_wakeup_event(input_dev->dev.parent, 0); -+ input_sync(input_dev); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t onkey_rising_irq(int irq, void *ponkey) -+{ -+ struct stpmic1_onkey *onkey = ponkey; -+ struct input_dev *input_dev = onkey->input_dev; -+ -+ input_report_key(input_dev, KEY_POWER, 0); -+ pm_wakeup_event(input_dev->dev.parent, 0); -+ input_sync(input_dev); -+ -+ return IRQ_HANDLED; -+} -+ -+static int stpmic1_onkey_probe(struct platform_device *pdev) -+{ -+ struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent); -+ struct device *dev = &pdev->dev; -+ struct input_dev *input_dev; -+ struct stpmic1_onkey *onkey; -+ unsigned int val, reg = 0; -+ int error; -+ -+ onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); -+ if (!onkey) -+ return -ENOMEM; -+ -+ onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling"); -+ if (onkey->irq_falling < 0) { -+ dev_err(dev, "failed: request IRQ onkey-falling %d\n", -+ onkey->irq_falling); -+ return onkey->irq_falling; -+ } -+ -+ onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising"); -+ if (onkey->irq_rising < 0) { -+ dev_err(dev, "failed: request IRQ onkey-rising %d\n", -+ onkey->irq_rising); -+ return onkey->irq_rising; -+ } -+ -+ if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { -+ if (val > 0 && val <= 16) { -+ dev_dbg(dev, "power-off-time=%d seconds\n", val); -+ reg |= PONKEY_PWR_OFF; -+ reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK); -+ } else { -+ dev_err(dev, "power-off-time-sec out of range\n"); -+ return -EINVAL; -+ } -+ } -+ -+ if (device_property_present(dev, "st,onkey-clear-cc-flag")) -+ reg |= PONKEY_CC_FLAG_CLEAR; -+ -+ error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR, -+ PONKEY_TURNOFF_MASK, reg); -+ if (error) { -+ dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error); -+ return error; -+ } -+ -+ if (device_property_present(dev, "st,onkey-pu-inactive")) { -+ error = regmap_update_bits(pmic->regmap, PADS_PULL_CR, -+ PONKEY_PU_INACTIVE, -+ PONKEY_PU_INACTIVE); -+ if (error) { -+ dev_err(dev, "ONKEY Pads configuration failed: %d\n", -+ error); -+ return error; -+ } -+ } -+ -+ input_dev = devm_input_allocate_device(dev); -+ if (!input_dev) { -+ dev_err(dev, "Can't allocate Pwr Onkey Input Device\n"); -+ return -ENOMEM; -+ } -+ -+ input_dev->name = "pmic_onkey"; -+ input_dev->phys = "pmic_onkey/input0"; -+ -+ input_set_capability(input_dev, EV_KEY, KEY_POWER); -+ -+ onkey->input_dev = input_dev; -+ -+ /* interrupt is nested in a thread */ -+ error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL, -+ onkey_falling_irq, IRQF_ONESHOT, -+ dev_name(dev), onkey); -+ if (error) { -+ dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error); -+ return error; -+ } -+ -+ error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL, -+ onkey_rising_irq, IRQF_ONESHOT, -+ dev_name(dev), onkey); -+ if (error) { -+ dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error); -+ return error; -+ } -+ -+ error = input_register_device(input_dev); -+ if (error) { -+ dev_err(dev, "Can't register power button: %d\n", error); -+ return error; -+ } -+ -+ platform_set_drvdata(pdev, onkey); -+ device_init_wakeup(dev, true); -+ -+ return 0; -+} -+ -+static int __maybe_unused stpmic1_onkey_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); -+ -+ if (device_may_wakeup(dev)) { -+ enable_irq_wake(onkey->irq_falling); -+ enable_irq_wake(onkey->irq_rising); -+ } -+ return 0; -+} -+ -+static int __maybe_unused stpmic1_onkey_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); -+ -+ if (device_may_wakeup(dev)) { -+ disable_irq_wake(onkey->irq_falling); -+ disable_irq_wake(onkey->irq_rising); -+ } -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm, -+ stpmic1_onkey_suspend, -+ stpmic1_onkey_resume); -+ -+static const struct of_device_id of_stpmic1_onkey_match[] = { -+ { .compatible = "st,stpmic1-onkey" }, -+ { }, -+}; -+ -+MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match); -+ -+static struct platform_driver stpmic1_onkey_driver = { -+ .probe = stpmic1_onkey_probe, -+ .driver = { -+ .name = "stpmic1_onkey", -+ .of_match_table = of_match_ptr(of_stpmic1_onkey_match), -+ .pm = &stpmic1_onkey_pm, -+ }, -+}; -+module_platform_driver(stpmic1_onkey_driver); -+ -+MODULE_DESCRIPTION("Onkey driver for STPMIC1"); -+MODULE_AUTHOR("Pascal Paillet "); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 1e18ca0..745da4c 100644 ---- a/drivers/input/touchscreen/edt-ft5x06.c -+++ b/drivers/input/touchscreen/edt-ft5x06.c -@@ -39,6 +39,8 @@ - #include - #include - #include -+#include -+ - - #define WORK_REGISTER_THRESHOLD 0x00 - #define WORK_REGISTER_REPORT_RATE 0x08 -@@ -968,6 +970,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - { - const struct edt_i2c_chip_data *chip_data; - struct edt_ft5x06_ts_data *tsdata; -+ struct mipi_dsi_device *panel; -+ struct device_node *np; - struct input_dev *input; - unsigned long irq_flags; - int error; -@@ -1033,7 +1037,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - - error = edt_ft5x06_ts_identify(client, tsdata, fw_version); - if (error) { -- dev_err(&client->dev, "touchscreen probe failed\n"); -+ dev_dbg(&client->dev, "touchscreen probe failed\n"); - return error; - } - -@@ -1105,6 +1109,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, - tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, - tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); - -+ np = of_parse_phandle(client->dev.of_node, "panel", 0); -+ if (np) { -+ panel = of_find_mipi_dsi_device_by_node(np); -+ of_node_put(np); -+ if (!panel) -+ return -ENOENT; -+ -+ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | -+ DL_FLAG_AUTOREMOVE_SUPPLIER); -+ put_device(&panel->dev); -+ } -+ - return 0; - } - -@@ -1152,11 +1168,16 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { - .max_support_points = 2, - }; - -+static const struct edt_i2c_chip_data edt_ft6336_data = { -+ .max_support_points = 2, -+}; -+ - static const struct i2c_device_id edt_ft5x06_ts_id[] = { - { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, - { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, - /* Note no edt- prefix for compatibility with the ft6236.c driver */ - { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, -+ { .name = "ft6336", .driver_data = (long)&edt_ft6336_data }, - { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); -@@ -1169,6 +1190,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { - { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, - /* Note focaltech vendor prefix for compatibility with ft6236.c */ - { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, -+ { .compatible = "focaltech,ft6336", .data = &edt_ft6336_data }, - { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); -diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c -index b20ba65..c196423 100644 ---- a/drivers/input/touchscreen/goodix.c -+++ b/drivers/input/touchscreen/goodix.c -@@ -25,8 +25,10 @@ - #include - #include - #include -+#include - #include - #include -+#include - #include - #include - #include -@@ -366,6 +368,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts) - - static int goodix_request_irq(struct goodix_ts_data *ts) - { -+ int gpio; -+ -+ gpio = desc_to_gpio(ts->gpiod_int); -+ -+ if (gpio_is_valid(gpio)) -+ ts->client->irq = gpio_to_irq(gpio); -+ - return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, - NULL, goodix_ts_irq_handler, - ts->irq_flags, ts->client->name, ts); -@@ -774,6 +783,8 @@ static int goodix_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { - struct goodix_ts_data *ts; -+ struct mipi_dsi_device *panel; -+ struct device_node *np; - int error; - - dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); -@@ -842,6 +853,17 @@ static int goodix_ts_probe(struct i2c_client *client, - return error; - } - -+ np = of_parse_phandle(client->dev.of_node, "panel", 0); -+ if (np) { -+ panel = of_find_mipi_dsi_device_by_node(np); -+ of_node_put(np); -+ if (!panel) -+ return -ENOENT; -+ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | -+ DL_FLAG_AUTOREMOVE_SUPPLIER); -+ put_device(&panel->dev); -+ } -+ - return 0; - } - -@@ -896,6 +918,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) - * sooner, delay 58ms here. - */ - msleep(58); -+ - return 0; - } - -@@ -958,6 +981,7 @@ static const struct of_device_id goodix_of_match[] = { - { .compatible = "goodix,gt9271" }, - { .compatible = "goodix,gt928" }, - { .compatible = "goodix,gt967" }, -+ { .compatible = "goodix,gt9147",}, - { } - }; - MODULE_DEVICE_TABLE(of, goodix_of_match); -diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 97b27f3..8e5a31b 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -6,20 +6,27 @@ - */ - - #include -+#include -+#include - #include - #include - #include - #include - #include - #include -+#include - #include - #include -+#include - #include - - #include - - #define IRQS_PER_BANK 32 - -+#define HWSPNLCK_TIMEOUT 1000 /* usec */ -+#define HWSPNLCK_RETRY_DELAY 100 /* usec */ -+ - struct stm32_exti_bank { - u32 imr_ofst; - u32 emr_ofst; -@@ -58,6 +65,7 @@ struct stm32_exti_host_data { - void __iomem *base; - struct stm32_exti_chip_data *chips_data; - const struct stm32_exti_drv_data *drv_data; -+ struct hwspinlock *hwlock; - }; - - static struct stm32_exti_host_data *stm32_host_data; -@@ -269,6 +277,42 @@ static int stm32_exti_set_type(struct irq_data *d, - return 0; - } - -+static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) -+{ -+ int ret, timeout = 0; -+ -+ if (!chip_data->host_data->hwlock) -+ return 0; -+ -+ /* -+ * Use the x_raw API since we are under spin_lock protection. -+ * Do not use the x_timeout API because we are under irq_disable -+ * mode (see __setup_irq()) -+ */ -+ do { -+ ret = hwspin_trylock_raw(chip_data->host_data->hwlock); -+ if (!ret) -+ return 0; -+ -+ udelay(HWSPNLCK_RETRY_DELAY); -+ timeout += HWSPNLCK_RETRY_DELAY; -+ } while (timeout < HWSPNLCK_TIMEOUT); -+ -+ if (ret == -EBUSY) -+ ret = -ETIMEDOUT; -+ -+ if (ret) -+ pr_err("%s can't get hwspinlock (%d)\n", __func__, ret); -+ -+ return ret; -+} -+ -+static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) -+{ -+ if (chip_data->host_data->hwlock) -+ hwspin_unlock_raw(chip_data->host_data->hwlock); -+} -+ - static int stm32_irq_set_type(struct irq_data *d, unsigned int type) - { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); -@@ -279,21 +323,26 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) - - irq_gc_lock(gc); - -+ err = stm32_exti_hwspin_lock(chip_data); -+ if (err) -+ goto unlock; -+ - rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); - ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); - - err = stm32_exti_set_type(d, type, &rtsr, &ftsr); -- if (err) { -- irq_gc_unlock(gc); -- return err; -- } -+ if (err) -+ goto unspinlock; - - irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); - irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); - -+unspinlock: -+ stm32_exti_hwspin_unlock(chip_data); -+unlock: - irq_gc_unlock(gc); - -- return 0; -+ return err; - } - - static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data, -@@ -460,20 +509,30 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) - int err; - - raw_spin_lock(&chip_data->rlock); -+ -+ err = stm32_exti_hwspin_lock(chip_data); -+ if (err) -+ goto unlock; -+ - rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); - ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); - - err = stm32_exti_set_type(d, type, &rtsr, &ftsr); -- if (err) { -- raw_spin_unlock(&chip_data->rlock); -- return err; -- } -+ if (err) -+ goto unspinlock; - - writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); - writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); -+ -+unspinlock: -+ stm32_exti_hwspin_unlock(chip_data); -+unlock: - raw_spin_unlock(&chip_data->rlock); - -- return 0; -+ if (d->parent_data->chip) -+ irq_chip_set_type_parent(d, type); -+ -+ return err; - } - - static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) -@@ -490,6 +549,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) - - raw_spin_unlock(&chip_data->rlock); - -+ if (d->parent_data->chip) -+ irq_chip_set_wake_parent(d, on); -+ - return 0; - } - -@@ -499,11 +561,16 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, - if (d->parent_data->chip) - return irq_chip_set_affinity_parent(d, dest, force); - -- return -EINVAL; -+ return IRQ_SET_MASK_OK_DONE; - } - --#ifdef CONFIG_PM --static int stm32_exti_h_suspend(void) -+static void stm32_exti_h_ack(struct irq_data *d) -+{ -+ if (d->parent_data->chip) -+ irq_chip_ack_parent(d); -+} -+ -+static int __maybe_unused stm32_exti_h_suspend(void) - { - struct stm32_exti_chip_data *chip_data; - int i; -@@ -518,7 +585,7 @@ static int stm32_exti_h_suspend(void) - return 0; - } - --static void stm32_exti_h_resume(void) -+static void __maybe_unused stm32_exti_h_resume(void) - { - struct stm32_exti_chip_data *chip_data; - int i; -@@ -532,21 +599,42 @@ static void stm32_exti_h_resume(void) - } - - static struct syscore_ops stm32_exti_h_syscore_ops = { -+#ifdef CONFIG_PM_SLEEP - .suspend = stm32_exti_h_suspend, - .resume = stm32_exti_h_resume, -+#endif - }; - --static void stm32_exti_h_syscore_init(void) -+static void stm32_exti_h_syscore_init(struct stm32_exti_host_data *host_data) - { -+ stm32_host_data = host_data; - register_syscore_ops(&stm32_exti_h_syscore_ops); - } --#else --static inline void stm32_exti_h_syscore_init(void) {} --#endif -+ -+static void stm32_exti_h_syscore_deinit(void) -+{ -+ unregister_syscore_ops(&stm32_exti_h_syscore_ops); -+} -+ -+static int stm32_exti_request_resources(struct irq_data *d) -+{ -+ struct irq_chip *chip_parent = d->parent_data->chip; -+ -+ if (chip_parent && chip_parent->irq_request_resources) -+ return chip_parent->irq_request_resources(d->parent_data); -+ return 0; -+} -+ -+static void stm32_exti_release_resources(struct irq_data *d) -+{ -+ if (d->parent_data->chip && d->parent_data->chip->irq_release_resources) -+ d->parent_data->chip->irq_release_resources(d->parent_data); -+} - - static struct irq_chip stm32_exti_h_chip = { - .name = "stm32-exti-h", - .irq_eoi = stm32_exti_h_eoi, -+ .irq_ack = stm32_exti_h_ack, - .irq_mask = stm32_exti_h_mask, - .irq_unmask = stm32_exti_h_unmask, - .irq_retrigger = irq_chip_retrigger_hierarchy, -@@ -554,6 +642,8 @@ static struct irq_chip stm32_exti_h_chip = { - .irq_set_wake = stm32_exti_h_set_wake, - .flags = IRQCHIP_MASK_ON_SUSPEND, - .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? stm32_exti_h_set_affinity : NULL, -+ .irq_request_resources = stm32_exti_request_resources, -+ .irq_release_resources = stm32_exti_release_resources, - }; - - static int stm32_exti_h_domain_alloc(struct irq_domain *dm, -@@ -574,15 +664,29 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm, - irq_domain_set_hwirq_and_chip(dm, virq, hwirq, - &stm32_exti_h_chip, chip_data); - -- p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); -- if (p_irq >= 0) { -+ /* -+ * EXTI 55 to 60 are mapped to PWR interrupt controller. -+ * The hwirq translation is done diferently than for GIC. -+ */ -+ if (hwirq >= 55 && hwirq <= 60) { - p_fwspec.fwnode = dm->parent->fwnode; -- p_fwspec.param_count = 3; -- p_fwspec.param[0] = GIC_SPI; -- p_fwspec.param[1] = p_irq; -- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; -+ p_fwspec.param_count = 2; -+ p_fwspec.param[0] = hwirq - 55; -+ p_fwspec.param[1] = fwspec->param[1]; - - return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); -+ } else { -+ p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); -+ if (p_irq >= 0) { -+ p_fwspec.fwnode = dm->parent->fwnode; -+ p_fwspec.param_count = 3; -+ p_fwspec.param[0] = GIC_SPI; -+ p_fwspec.param[1] = p_irq; -+ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; -+ -+ return irq_domain_alloc_irqs_parent(dm, virq, 1, -+ &p_fwspec); -+ } - } - - return 0; -@@ -631,7 +735,6 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, - const struct stm32_exti_bank *stm32_bank; - struct stm32_exti_chip_data *chip_data; - void __iomem *base = h_data->base; -- u32 irqs_mask; - - stm32_bank = h_data->drv_data->exti_banks[bank_idx]; - chip_data = &h_data->chips_data[bank_idx]; -@@ -640,10 +743,6 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, - - raw_spin_lock_init(&chip_data->rlock); - -- /* Determine number of irqs supported */ -- writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); -- irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); -- - /* - * This IP has no reset, so after hot reboot we should - * clear registers to avoid residue -@@ -651,8 +750,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, - writel_relaxed(0, base + stm32_bank->imr_ofst); - writel_relaxed(0, base + stm32_bank->emr_ofst); - -- pr_info("%s: bank%d, External IRQs available:%#x\n", -- node->full_name, bank_idx, irqs_mask); -+ pr_info("%pOF: bank%d\n", node, bank_idx); - - return chip_data; - } -@@ -730,55 +828,182 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - return ret; - } - -+static int stm32_exti_h_translate(struct irq_domain *d, -+ struct irq_fwspec *fwspec, -+ unsigned long *out_hwirq, -+ unsigned int *out_type) -+{ -+ if (is_of_node(fwspec->fwnode)) { -+ if (fwspec->param_count != 2) -+ return -EINVAL; -+ -+ *out_hwirq = fwspec->param[0]; -+ *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ - static const struct irq_domain_ops stm32_exti_h_domain_ops = { - .alloc = stm32_exti_h_domain_alloc, - .free = irq_domain_free_irqs_common, -+ .translate = stm32_exti_h_translate, - }; - --static int --__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, -- struct device_node *node, -- struct device_node *parent) -+static void stm32_exti_remove_irq(void *data) - { -+ struct irq_domain *domain = data; -+ -+ irq_domain_remove(domain); -+} -+ -+static int stm32_exti_remove(struct platform_device *pdev) -+{ -+ stm32_exti_h_syscore_deinit(); -+ return 0; -+} -+ -+static int stm32_exti_probe(struct platform_device *pdev) -+{ -+ int ret, i; -+ u32 nirqs; -+ struct device *dev = &pdev->dev; -+ struct device_node *child, *np = dev->of_node; - struct irq_domain *parent_domain, *domain; - struct stm32_exti_host_data *host_data; -- int ret, i; -+ const struct stm32_exti_drv_data *drv_data; -+ struct resource *res; - -- parent_domain = irq_find_host(parent); -- if (!parent_domain) { -- pr_err("interrupt-parent not found\n"); -- return -EINVAL; -+ host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); -+ if (!host_data) -+ return -ENOMEM; -+ -+ /* check for optional hwspinlock which may be not available yet */ -+ ret = of_hwspin_lock_get_id(np, 0); -+ if (ret == -EPROBE_DEFER) -+ /* hwspinlock framework not yet ready */ -+ return ret; -+ -+ if (ret >= 0) { -+ host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret); -+ if (!host_data->hwlock) { -+ dev_err(dev, "Failed to request hwspinlock\n"); -+ return -EINVAL; -+ } -+ } else if (ret != -ENOENT) { -+ /* note: ENOENT is a valid case (means 'no hwspinlock') */ -+ dev_err(dev, "Failed to get hwspinlock\n"); -+ return ret; - } - -- host_data = stm32_exti_host_init(drv_data, node); -- if (!host_data) -+ /* initialize host_data */ -+ drv_data = of_device_get_match_data(dev); -+ if (!drv_data) { -+ dev_err(dev, "no of match data\n"); -+ return -ENODEV; -+ } -+ host_data->drv_data = drv_data; -+ -+ host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr, -+ sizeof(*host_data->chips_data), -+ GFP_KERNEL); -+ if (!host_data->chips_data) - return -ENOMEM; - -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ host_data->base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(host_data->base)) { -+ dev_err(dev, "Unable to map registers\n"); -+ return PTR_ERR(host_data->base); -+ } -+ - for (i = 0; i < drv_data->bank_nr; i++) -- stm32_exti_chip_init(host_data, i, node); -+ stm32_exti_chip_init(host_data, i, np); -+ -+ parent_domain = irq_find_host(of_irq_find_parent(np)); -+ if (!parent_domain) { -+ dev_err(dev, "GIC interrupt-parent not found\n"); -+ return -EINVAL; -+ } - - domain = irq_domain_add_hierarchy(parent_domain, 0, - drv_data->bank_nr * IRQS_PER_BANK, -- node, &stm32_exti_h_domain_ops, -+ np, &stm32_exti_h_domain_ops, - host_data); - - if (!domain) { -- pr_err("%s: Could not register exti domain.\n", node->name); -- ret = -ENOMEM; -- goto out_unmap; -+ dev_err(dev, "Could not register exti domain\n"); -+ return -ENOMEM; - } - -- stm32_exti_h_syscore_init(); -+ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain); -+ if (ret) -+ return ret; -+ -+ for_each_child_of_node(np, child) { -+ parent_domain = irq_find_host(of_irq_find_parent(child)); -+ if (!parent_domain) { -+ dev_err(dev, "child interrupt-parent not found\n"); -+ return -EINVAL; -+ } -+ -+ ret = of_property_read_u32(child, "st,irq-number", &nirqs); -+ if (ret || !nirqs) { -+ dev_err(dev, "Missing or bad irq-number property\n"); -+ return -EINVAL; -+ } -+ -+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs, -+ child, -+ &stm32_exti_h_domain_ops, -+ host_data); -+ if (!domain) { -+ dev_err(dev, "Could not register exti domain\n"); -+ return -ENOMEM; -+ } -+ -+ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, -+ domain); -+ if (ret) -+ return ret; -+ } -+ -+ stm32_exti_h_syscore_init(host_data); - - return 0; -+} - --out_unmap: -- iounmap(host_data->base); -- kfree(host_data->chips_data); -- kfree(host_data); -- return ret; -+/* platform driver only for MP1 */ -+static const struct of_device_id stm32_exti_ids[] = { -+ { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data}, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_exti_ids); -+ -+static struct platform_driver stm32_exti_driver = { -+ .probe = stm32_exti_probe, -+ .remove = stm32_exti_remove, -+ .driver = { -+ .name = "stm32_exti", -+ .of_match_table = stm32_exti_ids, -+ }, -+}; -+ -+static int __init stm32_exti_arch_init(void) -+{ -+ return platform_driver_register(&stm32_exti_driver); -+} -+ -+static void __exit stm32_exti_arch_exit(void) -+{ -+ return platform_driver_unregister(&stm32_exti_driver); - } - -+arch_initcall(stm32_exti_arch_init); -+module_exit(stm32_exti_arch_exit); -+ -+/* no platform driver for F4 and H7 */ - static int __init stm32f4_exti_of_init(struct device_node *np, - struct device_node *parent) - { -@@ -794,11 +1019,3 @@ static int __init stm32h7_exti_of_init(struct device_node *np, - } - - IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); -- --static int __init stm32mp1_exti_of_init(struct device_node *np, -- struct device_node *parent) --{ -- return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); --} -- --IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init); -diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c -index 129b365..4e4ac4b 100644 ---- a/drivers/mailbox/mailbox-test.c -+++ b/drivers/mailbox/mailbox-test.c -@@ -31,7 +31,6 @@ - (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) - - static bool mbox_data_ready; --static struct dentry *root_debugfs_dir; - - struct mbox_test_device { - struct device *dev; -@@ -45,6 +44,7 @@ struct mbox_test_device { - spinlock_t lock; - wait_queue_head_t waitq; - struct fasync_struct *async_queue; -+ struct dentry *root_debugfs_dir; - }; - - static ssize_t mbox_test_signal_write(struct file *filp, -@@ -262,16 +262,16 @@ static int mbox_test_add_debugfs(struct platform_device *pdev, - if (!debugfs_initialized()) - return 0; - -- root_debugfs_dir = debugfs_create_dir("mailbox", NULL); -- if (!root_debugfs_dir) { -+ tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL); -+ if (!tdev->root_debugfs_dir) { - dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n"); - return -EINVAL; - } - -- debugfs_create_file("message", 0600, root_debugfs_dir, -+ debugfs_create_file("message", 0600, tdev->root_debugfs_dir, - tdev, &mbox_test_message_ops); - -- debugfs_create_file("signal", 0200, root_debugfs_dir, -+ debugfs_create_file("signal", 0200, tdev->root_debugfs_dir, - tdev, &mbox_test_signal_ops); - - return 0; -@@ -418,7 +418,7 @@ static int mbox_test_remove(struct platform_device *pdev) - { - struct mbox_test_device *tdev = platform_get_drvdata(pdev); - -- debugfs_remove_recursive(root_debugfs_dir); -+ debugfs_remove_recursive(tdev->root_debugfs_dir); - - if (tdev->tx_channel) - mbox_free_channel(tdev->tx_channel); -diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c -index e313222..eaf4ea4 100644 ---- a/drivers/mailbox/stm32-ipcc.c -+++ b/drivers/mailbox/stm32-ipcc.c -@@ -296,8 +296,8 @@ static int stm32_ipcc_probe(struct platform_device *pdev) - dev_err(dev, "Failed to set wake up irq\n"); - goto err_init_wkp; - } -- } else { -- device_init_wakeup(dev, false); -+ /* disable the wakeup source, let the user enable it or not */ -+ device_set_wakeup_enable(dev, false); - } - - /* mailbox controller */ -diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h -index ea57f3d..c119aa1 100644 ---- a/kernel/irq/internals.h -+++ b/kernel/irq/internals.h -@@ -95,10 +95,6 @@ static inline void irq_mark_irq(unsigned int irq) { } - extern void irq_mark_irq(unsigned int irq); - #endif - --extern int __irq_get_irqchip_state(struct irq_data *data, -- enum irqchip_irq_state which, -- bool *state); -- - extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); - - irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags); -diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c -index 23bcfa7..f8214bb 100644 ---- a/kernel/irq/manage.c -+++ b/kernel/irq/manage.c -@@ -35,9 +35,8 @@ static int __init setup_forced_irqthreads(char *arg) - early_param("threadirqs", setup_forced_irqthreads); - #endif - --static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) -+static void __synchronize_hardirq(struct irq_desc *desc) - { -- struct irq_data *irqd = irq_desc_get_irq_data(desc); - bool inprogress; - - do { -@@ -53,20 +52,6 @@ static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) - /* Ok, that indicated we're done: double-check carefully. */ - raw_spin_lock_irqsave(&desc->lock, flags); - inprogress = irqd_irq_inprogress(&desc->irq_data); -- -- /* -- * If requested and supported, check at the chip whether it -- * is in flight at the hardware level, i.e. already pending -- * in a CPU and waiting for service and acknowledge. -- */ -- if (!inprogress && sync_chip) { -- /* -- * Ignore the return code. inprogress is only updated -- * when the chip supports it. -- */ -- __irq_get_irqchip_state(irqd, IRQCHIP_STATE_ACTIVE, -- &inprogress); -- } - raw_spin_unlock_irqrestore(&desc->lock, flags); - - /* Oops, that failed? */ -@@ -89,18 +74,13 @@ static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) - * Returns: false if a threaded handler is active. - * - * This function may be called - with care - from IRQ context. -- * -- * It does not check whether there is an interrupt in flight at the -- * hardware level, but not serviced yet, as this might deadlock when -- * called with interrupts disabled and the target CPU of the interrupt -- * is the current CPU. - */ - bool synchronize_hardirq(unsigned int irq) - { - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) { -- __synchronize_hardirq(desc, false); -+ __synchronize_hardirq(desc); - return !atomic_read(&desc->threads_active); - } - -@@ -118,17 +98,13 @@ EXPORT_SYMBOL(synchronize_hardirq); - * - * Can only be called from preemptible code as it might sleep when - * an interrupt thread is associated to @irq. -- * -- * It optionally makes sure (when the irq chip supports that method) -- * that the interrupt is not pending in any CPU and waiting for -- * service. - */ - void synchronize_irq(unsigned int irq) - { - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) { -- __synchronize_hardirq(desc, true); -+ __synchronize_hardirq(desc); - /* - * We made sure that no hardirq handler is - * running. Now verify that no threaded handlers are -@@ -1674,12 +1650,8 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id) - - unregister_handler_proc(irq, action); - -- /* -- * Make sure it's not being used on another CPU and if the chip -- * supports it also make sure that there is no (not yet serviced) -- * interrupt in flight at the hardware level. -- */ -- __synchronize_hardirq(desc, true); -+ /* Make sure it's not being used on another CPU: */ -+ synchronize_hardirq(irq); - - #ifdef CONFIG_DEBUG_SHIRQ - /* -@@ -2212,28 +2184,6 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler, - } - EXPORT_SYMBOL_GPL(__request_percpu_irq); - --int __irq_get_irqchip_state(struct irq_data *data, enum irqchip_irq_state which, -- bool *state) --{ -- struct irq_chip *chip; -- int err = -EINVAL; -- -- do { -- chip = irq_data_get_irq_chip(data); -- if (chip->irq_get_irqchip_state) -- break; --#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -- data = data->parent_data; --#else -- data = NULL; --#endif -- } while (data); -- -- if (data) -- err = chip->irq_get_irqchip_state(data, which, state); -- return err; --} -- - /** - * irq_get_irqchip_state - returns the irqchip state of a interrupt. - * @irq: Interrupt line that is forwarded to a VM -@@ -2252,6 +2202,7 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - { - struct irq_desc *desc; - struct irq_data *data; -+ struct irq_chip *chip; - unsigned long flags; - int err = -EINVAL; - -@@ -2261,7 +2212,19 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - - data = irq_desc_get_irq_data(desc); - -- err = __irq_get_irqchip_state(data, which, state); -+ do { -+ chip = irq_data_get_irq_chip(data); -+ if (chip->irq_get_irqchip_state) -+ break; -+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -+ data = data->parent_data; -+#else -+ data = NULL; -+#endif -+ } while (data); -+ -+ if (data) -+ err = chip->irq_get_irqchip_state(data, which, state); - - irq_put_desc_busunlock(desc, flags); - return err; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch deleted file mode 100644 index a4553cc..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch +++ /dev/null @@ -1,3559 +0,0 @@ -From 8e40238bdd44bb0088d19c053ab2261523c81637 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:41 +0100 -Subject: [PATCH 13/31] ARM stm32mp1 r3 MEDIA - ---- - Documentation/media/uapi/v4l/subdev-formats.rst | 107 +++ - drivers/media/i2c/Kconfig | 13 + - drivers/media/i2c/Makefile | 1 + - drivers/media/i2c/ov5640.c | 1000 +++++++++++++-------- - drivers/media/i2c/st-mipid02.c | 1076 +++++++++++++++++++++++ - drivers/media/platform/Kconfig | 2 +- - drivers/media/platform/stm32/stm32-cec.c | 96 +- - drivers/media/platform/stm32/stm32-dcmi.c | 366 ++++++-- - drivers/media/usb/uvc/uvc_queue.c | 15 +- - drivers/media/usb/uvc/uvc_v4l2.c | 11 +- - drivers/media/usb/uvc/uvcvideo.h | 2 + - drivers/media/v4l2-core/v4l2-fwnode.c | 3 + - include/uapi/linux/media-bus-format.h | 3 +- - 13 files changed, 2266 insertions(+), 429 deletions(-) - create mode 100644 drivers/media/i2c/st-mipid02.c - -diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst -index 8e73fcf..44f427c 100644 ---- a/Documentation/media/uapi/v4l/subdev-formats.rst -+++ b/Documentation/media/uapi/v4l/subdev-formats.rst -@@ -973,6 +973,113 @@ The following tables list existing packed RGB formats. - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` -+ * .. _MEDIA-BUS-FMT-BGR888-3X8: -+ -+ - MEDIA_BUS_FMT_BGR888_3X8 -+ - 0x101b -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - b\ :sub:`7` -+ - b\ :sub:`6` -+ - b\ :sub:`5` -+ - b\ :sub:`4` -+ - b\ :sub:`3` -+ - b\ :sub:`2` -+ - b\ :sub:`1` -+ - b\ :sub:`0` -+ * - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - g\ :sub:`7` -+ - g\ :sub:`6` -+ - g\ :sub:`5` -+ - g\ :sub:`4` -+ - g\ :sub:`3` -+ - g\ :sub:`2` -+ - g\ :sub:`1` -+ - g\ :sub:`0` -+ * - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - -+ - r\ :sub:`7` -+ - r\ :sub:`6` -+ - r\ :sub:`5` -+ - r\ :sub:`4` -+ - r\ :sub:`3` -+ - r\ :sub:`2` -+ - r\ :sub:`1` -+ - r\ :sub:`0` - * .. _MEDIA-BUS-FMT-GBR888-1X24: - - - MEDIA_BUS_FMT_GBR888_1X24 -diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 8b1ae1d..6a8e58d 100644 ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -1068,6 +1068,19 @@ config VIDEO_I2C - To compile this driver as a module, choose M here: the - module will be called video-i2c - -+config VIDEO_ST_MIPID02 -+ tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" -+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API -+ depends on MEDIA_CAMERA_SUPPORT -+ select V4L2_FWNODE -+ help -+ Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. -+ It is used to allow usage of CSI-2 sensor with PARALLEL port -+ controller. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called st-mipid02. -+ - endmenu - - menu "Sensors used on soc_camera driver" -diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile -index 520b3c3..051c68e 100644 ---- a/drivers/media/i2c/Makefile -+++ b/drivers/media/i2c/Makefile -@@ -108,5 +108,6 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o - obj-$(CONFIG_VIDEO_TC358743) += tc358743.o - obj-$(CONFIG_VIDEO_IMX258) += imx258.o - obj-$(CONFIG_VIDEO_IMX274) += imx274.o -+obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o - - obj-$(CONFIG_SDR_MAX2175) += max2175.o -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 2023df1..62269ac 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -66,6 +66,7 @@ - #define OV5640_REG_TIMING_VTS 0x380e - #define OV5640_REG_TIMING_TC_REG20 0x3820 - #define OV5640_REG_TIMING_TC_REG21 0x3821 -+#define OV5640_REG_DVP_PCLK_DIVIDER 0x3824 - #define OV5640_REG_AEC_CTRL00 0x3a00 - #define OV5640_REG_AEC_B50_STEP 0x3a08 - #define OV5640_REG_AEC_B60_STEP 0x3a0a -@@ -82,6 +83,9 @@ - #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c - #define OV5640_REG_FRAME_CTRL01 0x4202 - #define OV5640_REG_FORMAT_CONTROL00 0x4300 -+#define OV5640_REG_VFIFO_HSIZE 0x4602 -+#define OV5640_REG_VFIFO_VSIZE 0x4604 -+#define OV5640_REG_JPG_MODE_SELECT 0x4713 - #define OV5640_REG_POLARITY_CTRL00 0x4740 - #define OV5640_REG_MIPI_CTRL00 0x4800 - #define OV5640_REG_DEBUG_MODE 0x4814 -@@ -94,9 +98,6 @@ - #define OV5640_REG_SDE_CTRL5 0x5585 - #define OV5640_REG_AVG_READOUT 0x56a1 - --#define OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT 1 --#define OV5640_SCLK_ROOT_DIVIDER_DEFAULT 2 -- - enum ov5640_mode_id { - OV5640_MODE_QCIF_176_144 = 0, - OV5640_MODE_QVGA_320_240, -@@ -113,9 +114,19 @@ enum ov5640_mode_id { - enum ov5640_frame_rate { - OV5640_15_FPS = 0, - OV5640_30_FPS, -+ OV5640_60_FPS, - OV5640_NUM_FRAMERATES, - }; - -+enum ov5640_format_mux { -+ OV5640_FMT_MUX_YUV422 = 0, -+ OV5640_FMT_MUX_RGB, -+ OV5640_FMT_MUX_DITHER, -+ OV5640_FMT_MUX_RAW_DPC, -+ OV5640_FMT_MUX_SNR_RAW, -+ OV5640_FMT_MUX_RAW_CIP, -+}; -+ - struct ov5640_pixfmt { - u32 code; - u32 colorspace; -@@ -127,6 +138,10 @@ static const struct ov5640_pixfmt ov5640_formats[] = { - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, -+ { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, -+ { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, -+ { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, -+ { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, - }; - - /* -@@ -141,6 +156,7 @@ MODULE_PARM_DESC(virtual_channel, - static const int ov5640_framerates[] = { - [OV5640_15_FPS] = 15, - [OV5640_30_FPS] = 30, -+ [OV5640_60_FPS] = 60, - }; - - /* regulator supplies */ -@@ -202,6 +218,7 @@ struct ov5640_ctrls { - struct v4l2_ctrl *test_pattern; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; -+ struct v4l2_ctrl *link_freq; - }; - - struct ov5640_dev { -@@ -261,8 +278,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) - static const struct reg_value ov5640_init_setting_30fps_VGA[] = { - {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, - {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, -- {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, -- {0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0}, -+ {0x3630, 0x36, 0, 0}, - {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, - {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, - {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, -@@ -289,7 +305,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, - {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, - {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, -- {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, -+ {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, - {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, - {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, -@@ -344,66 +360,8 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { - {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, - }; - --static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = { -- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { -- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, -- {0x3035, 0x12, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_VGA_640_480[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -416,13 +374,13 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { -- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_XGA_1024_768[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -435,13 +393,12 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_QVGA_320_240[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -454,13 +411,12 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { -- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_QCIF_176_144[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -473,32 +429,12 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { -- {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_NTSC_720_480[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -511,32 +447,12 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { -- {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_PAL_720_576[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -549,33 +465,12 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = { -- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = { -- {0x3008, 0x42, 0, 0}, -- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, -+static const struct reg_value ov5640_setting_720P_1280_720[] = { -+ {0x3c07, 0x07, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -588,34 +483,13 @@ static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = { - {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, - {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, - {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, -- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0}, -- {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = { -- {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x31, 0, 0}, -- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, -- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, -- {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, -- {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, -- {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, -- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { -+static const struct reg_value ov5640_setting_1080P_1920_1080[] = { - {0x3008, 0x42, 0, 0}, -- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -628,10 +502,10 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0}, -- {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0x83, 0, 0}, -+ {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, - {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, -@@ -640,46 +514,12 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { - {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, - {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, - {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, -- {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, -- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, -+ {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, - {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, -- {0x3503, 0, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { -- {0x3008, 0x42, 0, 0}, -- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3814, 0x11, 0, 0}, -- {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -- {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, -- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, -- {0x3810, 0x00, 0, 0}, -- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, -- {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, -- {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, -- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, -- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, -- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, -- {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, -- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, -- {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, -- {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, -- {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, -- {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, -- {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, -- {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, -- {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, -- {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, -- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, -- {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { -- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, -+static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { -+ {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -692,9 +532,9 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, -- {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, -- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, -- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, -+ {0x4407, 0x04, 0, 0}, -+ {0x5001, 0x83, 0, 70}, - }; - - /* power-on sensor init reg table */ -@@ -705,79 +545,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = { - }; - - static const struct ov5640_mode_info --ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = { -- { -- {OV5640_MODE_QCIF_176_144, SUBSAMPLING, -- 176, 1896, 144, 984, -- ov5640_setting_15fps_QCIF_176_144, -- ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, -- {OV5640_MODE_QVGA_320_240, SUBSAMPLING, -- 320, 1896, 240, 984, -- ov5640_setting_15fps_QVGA_320_240, -- ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, -- {OV5640_MODE_VGA_640_480, SUBSAMPLING, -- 640, 1896, 480, 1080, -- ov5640_setting_15fps_VGA_640_480, -- ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, -- {OV5640_MODE_NTSC_720_480, SUBSAMPLING, -- 720, 1896, 480, 984, -- ov5640_setting_15fps_NTSC_720_480, -- ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, -- {OV5640_MODE_PAL_720_576, SUBSAMPLING, -- 720, 1896, 576, 984, -- ov5640_setting_15fps_PAL_720_576, -- ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, -- {OV5640_MODE_XGA_1024_768, SUBSAMPLING, -- 1024, 1896, 768, 1080, -- ov5640_setting_15fps_XGA_1024_768, -- ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, -- {OV5640_MODE_720P_1280_720, SUBSAMPLING, -- 1280, 1892, 720, 740, -- ov5640_setting_15fps_720P_1280_720, -- ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, -- {OV5640_MODE_1080P_1920_1080, SCALING, -- 1920, 2500, 1080, 1120, -- ov5640_setting_15fps_1080P_1920_1080, -- ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, -- {OV5640_MODE_QSXGA_2592_1944, SCALING, -- 2592, 2844, 1944, 1968, -- ov5640_setting_15fps_QSXGA_2592_1944, -- ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, -- }, { -- {OV5640_MODE_QCIF_176_144, SUBSAMPLING, -- 176, 1896, 144, 984, -- ov5640_setting_30fps_QCIF_176_144, -- ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, -- {OV5640_MODE_QVGA_320_240, SUBSAMPLING, -- 320, 1896, 240, 984, -- ov5640_setting_30fps_QVGA_320_240, -- ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, -- {OV5640_MODE_VGA_640_480, SUBSAMPLING, -- 640, 1896, 480, 1080, -- ov5640_setting_30fps_VGA_640_480, -- ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, -- {OV5640_MODE_NTSC_720_480, SUBSAMPLING, -- 720, 1896, 480, 984, -- ov5640_setting_30fps_NTSC_720_480, -- ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, -- {OV5640_MODE_PAL_720_576, SUBSAMPLING, -- 720, 1896, 576, 984, -- ov5640_setting_30fps_PAL_720_576, -- ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, -- {OV5640_MODE_XGA_1024_768, SUBSAMPLING, -- 1024, 1896, 768, 1080, -- ov5640_setting_30fps_XGA_1024_768, -- ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, -- {OV5640_MODE_720P_1280_720, SUBSAMPLING, -- 1280, 1892, 720, 740, -- ov5640_setting_30fps_720P_1280_720, -- ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, -- {OV5640_MODE_1080P_1920_1080, SCALING, -- 1920, 2500, 1080, 1120, -- ov5640_setting_30fps_1080P_1920_1080, -- ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, -- {OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0}, -- }, -+ov5640_mode_data[OV5640_NUM_MODES] = { -+ {OV5640_MODE_QCIF_176_144, SUBSAMPLING, -+ 176, 1896, 144, 984, -+ ov5640_setting_QCIF_176_144, -+ ARRAY_SIZE(ov5640_setting_QCIF_176_144)}, -+ {OV5640_MODE_QVGA_320_240, SUBSAMPLING, -+ 320, 1896, 240, 984, -+ ov5640_setting_QVGA_320_240, -+ ARRAY_SIZE(ov5640_setting_QVGA_320_240)}, -+ {OV5640_MODE_VGA_640_480, SUBSAMPLING, -+ 640, 1896, 480, 1080, -+ ov5640_setting_VGA_640_480, -+ ARRAY_SIZE(ov5640_setting_VGA_640_480)}, -+ {OV5640_MODE_NTSC_720_480, SUBSAMPLING, -+ 720, 1896, 480, 984, -+ ov5640_setting_NTSC_720_480, -+ ARRAY_SIZE(ov5640_setting_NTSC_720_480)}, -+ {OV5640_MODE_PAL_720_576, SUBSAMPLING, -+ 720, 1896, 576, 984, -+ ov5640_setting_PAL_720_576, -+ ARRAY_SIZE(ov5640_setting_PAL_720_576)}, -+ {OV5640_MODE_XGA_1024_768, SUBSAMPLING, -+ 1024, 1896, 768, 1080, -+ ov5640_setting_XGA_1024_768, -+ ARRAY_SIZE(ov5640_setting_XGA_1024_768)}, -+ {OV5640_MODE_720P_1280_720, SUBSAMPLING, -+ 1280, 1892, 720, 740, -+ ov5640_setting_720P_1280_720, -+ ARRAY_SIZE(ov5640_setting_720P_1280_720)}, -+ {OV5640_MODE_1080P_1920_1080, SCALING, -+ 1920, 2500, 1080, 1120, -+ ov5640_setting_1080P_1920_1080, -+ ARRAY_SIZE(ov5640_setting_1080P_1920_1080)}, -+ {OV5640_MODE_QSXGA_2592_1944, SCALING, -+ 2592, 2844, 1944, 1968, -+ ov5640_setting_QSXGA_2592_1944, -+ ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944)}, - }; - - static int ov5640_init_slave_id(struct ov5640_dev *sensor) -@@ -909,27 +713,389 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, - return ov5640_write_reg(sensor, reg, val); - } - --/* download ov5640 settings to sensor through i2c */ --static int ov5640_set_timings(struct ov5640_dev *sensor, -- const struct ov5640_mode_info *mode) -+/* -+ * After trying the various combinations, reading various -+ * documentations spreaded around the net, and from the various -+ * feedback, the clock tree is probably as follows: -+ * -+ * +--------------+ -+ * | Ext. Clock | -+ * +-+------------+ -+ * | +----------+ -+ * +->| PLL1 | - reg 0x3036, for the multiplier -+ * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider -+ * | +--------------+ -+ * +->| System Clock | - reg 0x3035, bits 4-7 -+ * +-+------------+ -+ * | +--------------+ -+ * +->| MIPI Divider | - reg 0x3035, bits 0-3 -+ * | +-+------------+ -+ * | +----------------> MIPI SCLK -+ * | + +-----+ -+ * | +->| / 2 |-------> MIPI BIT CLK -+ * | +-----+ -+ * | +--------------+ -+ * +->| PLL Root Div | - reg 0x3037, bit 4 -+ * +-+------------+ -+ * | +---------+ -+ * +->| Bit Div | - reg 0x3035, bits 0-3 -+ * +-+-------+ -+ * | +-------------+ -+ * +->| SCLK Div | - reg 0x3108, bits 0-1 -+ * | +-+-----------+ -+ * | +---------------> SCLK -+ * | +-------------+ -+ * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 -+ * | +-+-----------+ -+ * | +---------------> SCLK 2X -+ * | +-------------+ -+ * +->| PCLK Div | - reg 0x3108, bits 4-5 -+ * ++------------+ -+ * + +-----------+ -+ * +->| P_DIV | - reg 0x3035, bits 0-3 -+ * +-----+-----+ -+ * +------------> PCLK -+ * -+ * This is deviating from the datasheet at least for the register -+ * 0x3108, since it's said here that the PCLK would be clocked from -+ * the PLL. -+ * -+ * There seems to be also (unverified) constraints: -+ * - the PLL pre-divider output rate should be in the 4-27MHz range -+ * - the PLL multiplier output rate should be in the 500-1000MHz range -+ * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG -+ * -+ * In the two latter cases, these constraints are met since our -+ * factors are hardcoded. If we were to change that, we would need to -+ * take this into account. The only varying parts are the PLL -+ * multiplier and the system clock divider, which are shared between -+ * all these clocks so won't cause any issue. -+ */ -+ -+/* -+ * This is supposed to be ranging from 1 to 8, but the value is always -+ * set to 3 in the vendor kernels. -+ */ -+#define OV5640_PLL_PREDIV 3 -+ -+#define OV5640_PLL_MULT_MIN 4 -+#define OV5640_PLL_MULT_MAX 252 -+ -+/* -+ * This is supposed to be ranging from 1 to 16, but the value is -+ * always set to either 1 or 2 in the vendor kernels. -+ */ -+#define OV5640_SYSDIV_MIN 1 -+#define OV5640_SYSDIV_MAX 16 -+ -+/* -+ * Hardcode these values for scaler and non-scaler modes. -+ * FIXME: to be re-calcualted for 1 data lanes setups -+ */ -+#define OV5640_MIPI_DIV_PCLK 2 -+#define OV5640_MIPI_DIV_SCLK 1 -+ -+/* -+ * This is supposed to be ranging from 1 to 2, but the value is always -+ * set to 2 in the vendor kernels. -+ */ -+#define OV5640_PLL_ROOT_DIV 2 -+#define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) -+ -+/* -+ * We only supports 8-bit formats at the moment -+ */ -+#define OV5640_BIT_DIV 2 -+#define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 -+ -+/* -+ * This is supposed to be ranging from 1 to 8, but the value is always -+ * set to 2 in the vendor kernels. -+ */ -+#define OV5640_SCLK_ROOT_DIV 2 -+ -+/* -+ * This is hardcoded so that the consistency is maintained between SCLK and -+ * SCLK 2x. -+ */ -+#define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) -+ -+/* -+ * This is supposed to be ranging from 1 to 8, but the value is always -+ * set to 1 in the vendor kernels. -+ */ -+#define OV5640_PCLK_ROOT_DIV 1 -+#define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 -+ -+static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, -+ u8 pll_prediv, u8 pll_mult, -+ u8 sysdiv) -+{ -+ unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; -+ -+ /* PLL1 output cannot exceed 1GHz. */ -+ if (sysclk / 1000000 > 1000) -+ return 0; -+ -+ return sysclk / sysdiv; -+} -+ -+static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, -+ unsigned long rate, -+ u8 *pll_prediv, u8 *pll_mult, -+ u8 *sysdiv) -+{ -+ unsigned long best = ~0; -+ u8 best_sysdiv = 1, best_mult = 1; -+ u8 _sysdiv, _pll_mult; -+ -+ for (_sysdiv = OV5640_SYSDIV_MIN; -+ _sysdiv <= OV5640_SYSDIV_MAX; -+ _sysdiv++) { -+ for (_pll_mult = OV5640_PLL_MULT_MIN; -+ _pll_mult <= OV5640_PLL_MULT_MAX; -+ _pll_mult++) { -+ unsigned long _rate; -+ -+ /* -+ * The PLL multiplier cannot be odd if above -+ * 127. -+ */ -+ if (_pll_mult > 127 && (_pll_mult % 2)) -+ continue; -+ -+ _rate = ov5640_compute_sys_clk(sensor, -+ OV5640_PLL_PREDIV, -+ _pll_mult, _sysdiv); -+ -+ /* -+ * We have reached the maximum allowed PLL1 output, -+ * increase sysdiv. -+ */ -+ if (!rate) -+ break; -+ -+ /* -+ * Prefer rates above the expected clock rate than -+ * below, even if that means being less precise. -+ */ -+ if (_rate < rate) -+ continue; -+ -+ if (abs(rate - _rate) < abs(rate - best)) { -+ best = _rate; -+ best_sysdiv = _sysdiv; -+ best_mult = _pll_mult; -+ } -+ -+ if (_rate == rate) -+ goto out; -+ } -+ } -+ -+out: -+ *sysdiv = best_sysdiv; -+ *pll_prediv = OV5640_PLL_PREDIV; -+ *pll_mult = best_mult; -+ -+ return best; -+} -+ -+/* -+ * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values -+ * for the MIPI CSI-2 output. -+ * -+ * @rate: The requested bandwidth per lane in bytes per second. -+ * 'Bandwidth Per Lane' is calculated as: -+ * bpl = HTOT * VTOT * FPS * bpp / num_lanes; -+ * -+ * This function use the requested bandwidth to calculate: -+ * - sample_rate = bpl / (bpp / num_lanes); -+ * = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes); -+ * -+ * - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR) -+ * -+ * with these fixed parameters: -+ * PLL_RDIV = 2; -+ * BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5); -+ * PCLK_DIV = 1; -+ * -+ * The MIPI clock generation differs for modes that use the scaler and modes -+ * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI -+ * BIT CLk, and thus: -+ * -+ * - mipi_sclk = bpl / MIPI_DIV / 2; -+ * MIPI_DIV = 1; -+ * -+ * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated -+ * from the pixel clock, and thus: -+ * -+ * - sample_rate = bpl / (bpp / num_lanes); -+ * = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes); -+ * = bpl / (4 * MIPI_DIV / num_lanes); -+ * - MIPI_DIV = bpp / (4 * num_lanes); -+ * -+ * FIXME: this have been tested with 16bpp and 2 lanes setup only. -+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the -+ * above formula for setups with 1 lane or image formats with different bpp. -+ * -+ * FIXME: this deviates from the sensor manual documentation which is quite -+ * thin on the MIPI clock tree generation part. -+ */ -+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, -+ unsigned long rate) - { -+ const struct ov5640_mode_info *mode = sensor->current_mode; -+ u8 prediv, mult, sysdiv; -+ u8 mipi_div; - int ret; - -- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); -- if (ret < 0) -+ /* -+ * 1280x720 is reported to use 'SUBSAMPLING' only, -+ * but according to the sensor manual it goes through the -+ * scaler before subsampling. -+ */ -+ if (mode->dn_mode == SCALING || -+ (mode->id == OV5640_MODE_720P_1280_720)) -+ mipi_div = OV5640_MIPI_DIV_SCLK; -+ else -+ mipi_div = OV5640_MIPI_DIV_PCLK; -+ -+ ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv); -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, -+ 0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT); -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, -+ 0xff, sysdiv << 4 | mipi_div); -+ if (ret) - return ret; - -- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, -+ 0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv); -+ if (ret) -+ return ret; -+ -+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, -+ 0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS); -+} -+ -+static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, -+ unsigned long rate, -+ u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, -+ u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) -+{ -+ unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * -+ OV5640_PCLK_ROOT_DIV; -+ -+ _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, -+ sysdiv); -+ *pll_rdiv = OV5640_PLL_ROOT_DIV; -+ *bit_div = OV5640_BIT_DIV; -+ *pclk_div = OV5640_PCLK_ROOT_DIV; -+ -+ return _rate / *pll_rdiv / *bit_div / *pclk_div; -+} -+ -+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) -+{ -+ const struct ov5640_mode_info *mode = sensor->current_mode; -+ u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; -+ struct i2c_client *client = sensor->i2c_client; -+ unsigned int pclk_freq, max_pclk_freq; -+ u8 dvp_pclk_divider; -+ int ret; -+ -+ /* -+ * 1280x720 and 1024x768 are reported to use 'SUBSAMPLING' only, -+ * but they seems to go through the scaler before subsampling. -+ */ -+ if (mode->dn_mode == SCALING || -+ (mode->id == OV5640_MODE_720P_1280_720) || -+ (mode->id == OV5640_MODE_XGA_1024_768)) -+ dvp_pclk_divider = 1; -+ else -+ dvp_pclk_divider = 2; -+ -+ ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER, -+ dvp_pclk_divider); -+ if (ret) -+ return ret; -+ pclk_freq = rate / dvp_pclk_divider; -+ max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency; -+ -+ /* clip rate according to optional maximum pixel clock limit */ -+ if (max_pclk_freq && (pclk_freq > max_pclk_freq)) { -+ rate = max_pclk_freq * dvp_pclk_divider; -+ dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n", -+ pclk_freq, max_pclk_freq); -+ } -+ -+ ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, -+ &bit_div, &pclk_div); -+ -+ if (bit_div == 2) -+ bit_div = 8; -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, -+ 0x0f, bit_div); -+ if (ret) -+ return ret; -+ -+ /* -+ * We need to set sysdiv according to the clock, and to clear -+ * the MIPI divider. -+ */ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, -+ 0xff, sysdiv << 4); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, -+ 0xff, mult); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, -+ 0x1f, prediv | ((pll_rdiv - 1) << 4)); -+ if (ret) -+ return ret; -+ -+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, -+ (ilog2(pclk_div) << 4)); -+} -+ -+#if 0 -+/* set JPEG framing sizes */ -+static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, -+ const struct ov5640_mode_info *mode) -+{ -+ int ret; -+ -+ /* -+ * compression mode 3 timing -+ * -+ * Data is transmitted with programmable width (VFIFO_HSIZE). -+ * No padding done. Last line may have less data. Varying -+ * number of lines per frame, depending on amount of data. -+ */ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); - if (ret < 0) - return ret; - -- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); -+ ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact); - if (ret < 0) - return ret; - -- return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); -+ return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); - } -+#endif - -+/* download ov5640 settings to sensor through i2c */ - static int ov5640_load_regs(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) - { -@@ -957,7 +1123,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, - usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); - } - -- return ov5640_set_timings(sensor, mode); -+ return ret; - } - - static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) -@@ -1062,16 +1228,6 @@ static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) - - if (on) { - /* -- * reset MIPI PCLK/SERCLK divider -- * -- * SC PLL CONTRL1 0 -- * - [3..0]: MIPI PCLK/SERCLK divider -- */ -- ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0x0f, 0); -- if (ret) -- return ret; -- -- /* - * configure parallel port control lines polarity - * - * POLARITY CTRL0 -@@ -1438,14 +1594,44 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) - return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); - } - -+static int ov5640_set_timings(struct ov5640_dev *sensor, -+ const struct ov5640_mode_info *mode) -+{ -+ int ret; -+#if 0 -+ if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { -+ ret = ov5640_set_jpeg_timings(sensor, mode); -+ if (ret < 0) -+ return ret; -+ } -+#endif -+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); -+ if (ret < 0) -+ return ret; -+ -+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); -+ if (ret < 0) -+ return ret; -+ -+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); -+ if (ret < 0) -+ return ret; -+ -+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ - static const struct ov5640_mode_info * - ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, - int width, int height, bool nearest) - { - const struct ov5640_mode_info *mode; - -- mode = v4l2_find_nearest_size(ov5640_mode_data[fr], -- ARRAY_SIZE(ov5640_mode_data[fr]), -+ mode = v4l2_find_nearest_size(ov5640_mode_data, -+ ARRAY_SIZE(ov5640_mode_data), - hact, vact, - width, height); - -@@ -1453,6 +1639,11 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, - (!nearest && (mode->hact != width || mode->vact != height))) - return NULL; - -+ /* Only 640x480 can operate at 60fps (for now) */ -+ if (fr == OV5640_60_FPS && -+ !(mode->hact == 640 && mode->vact == 480)) -+ return NULL; -+ - return mode; - } - -@@ -1637,8 +1828,12 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - enum ov5640_downsize_mode dn_mode, orig_dn_mode; - bool auto_gain = sensor->ctrls.auto_gain->val == 1; - bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; -+ unsigned long rate; - int ret; - -+ if (!orig_mode) -+ orig_mode = mode; -+ - dn_mode = mode->dn_mode; - orig_dn_mode = orig_mode->dn_mode; - -@@ -1655,6 +1850,23 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - goto restore_auto_gain; - } - -+ /* -+ * All the formats we support have 16 bits per pixel, seems to require -+ * the same rate than YUV, so we can just use 16 bpp all the time. -+ */ -+ rate = mode->vtot * mode->htot * 16; -+ rate *= ov5640_framerates[sensor->current_fr]; -+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2) { -+ rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes; -+ ret = ov5640_set_mipi_pclk(sensor, rate); -+ } else { -+ rate = rate / sensor->ep.bus.parallel.bus_width; -+ ret = ov5640_set_dvp_pclk(sensor, rate); -+ } -+ -+ if (ret < 0) -+ return 0; -+ - if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || - (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { - /* -@@ -1678,6 +1890,10 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - if (auto_exp) - ov5640_set_autoexposure(sensor, true); - -+ ret = ov5640_set_timings(sensor, mode); -+ if (ret < 0) -+ return ret; -+ - ret = ov5640_set_binning(sensor, dn_mode != SCALING); - if (ret < 0) - return ret; -@@ -1724,8 +1940,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) - sensor->last_mode = &ov5640_mode_init_data; - - ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, -- (ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) | -- ilog2(OV5640_SCLK_ROOT_DIVIDER_DEFAULT)); -+ (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | -+ ilog2(OV5640_SCLK_ROOT_DIV)); - if (ret) - return ret; - -@@ -1925,34 +2141,39 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, - u32 width, u32 height) - { - const struct ov5640_mode_info *mode; -- u32 minfps, maxfps, fps; -- int ret; -+ enum ov5640_frame_rate rate = OV5640_15_FPS; -+ int minfps, maxfps, best_fps, fps; -+ int i; - - minfps = ov5640_framerates[OV5640_15_FPS]; -- maxfps = ov5640_framerates[OV5640_30_FPS]; -+ maxfps = ov5640_framerates[OV5640_60_FPS]; - - if (fi->numerator == 0) { - fi->denominator = maxfps; - fi->numerator = 1; -- return OV5640_30_FPS; -+ rate = OV5640_60_FPS; -+ goto find_mode; - } - -- fps = DIV_ROUND_CLOSEST(fi->denominator, fi->numerator); -+ fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), -+ minfps, maxfps); - -- fi->numerator = 1; -- if (fps > maxfps) -- fi->denominator = maxfps; -- else if (fps < minfps) -- fi->denominator = minfps; -- else if (2 * fps >= 2 * minfps + (maxfps - minfps)) -- fi->denominator = maxfps; -- else -- fi->denominator = minfps; -+ best_fps = minfps; -+ for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { -+ int curr_fps = ov5640_framerates[i]; -+ -+ if (abs(curr_fps - fps) < abs(best_fps - fps)) { -+ best_fps = curr_fps; -+ rate = i; -+ } -+ } - -- ret = (fi->denominator == minfps) ? OV5640_15_FPS : OV5640_30_FPS; -+ fi->numerator = 1; -+ fi->denominator = best_fps; - -- mode = ov5640_find_mode(sensor, ret, width, height, false); -- return mode ? ret : -EINVAL; -+find_mode: -+ mode = ov5640_find_mode(sensor, rate, width, height, false); -+ return mode ? rate : -EINVAL; - } - - static int ov5640_get_fmt(struct v4l2_subdev *sd, -@@ -2013,6 +2234,10 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, - return 0; - } - -+static const s64 link_freq_menu_items[] = { -+ 384000000, -+}; -+ - static int ov5640_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -@@ -2061,46 +2286,67 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, - struct v4l2_mbus_framefmt *format) - { - int ret = 0; -- bool is_rgb = false; - bool is_jpeg = false; -- u8 val; -+ u8 fmt, mux; - - switch (format->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - /* YUV422, UYVY */ -- val = 0x3f; -+ fmt = 0x3f; -+ mux = OV5640_FMT_MUX_YUV422; - break; - case MEDIA_BUS_FMT_YUYV8_2X8: - /* YUV422, YUYV */ -- val = 0x30; -+ fmt = 0x30; -+ mux = OV5640_FMT_MUX_YUV422; - break; - case MEDIA_BUS_FMT_RGB565_2X8_LE: - /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ -- val = 0x6F; -- is_rgb = true; -+ fmt = 0x6F; -+ mux = OV5640_FMT_MUX_RGB; - break; - case MEDIA_BUS_FMT_RGB565_2X8_BE: - /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ -- val = 0x61; -- is_rgb = true; -+ fmt = 0x61; -+ mux = OV5640_FMT_MUX_RGB; - break; - case MEDIA_BUS_FMT_JPEG_1X8: - /* YUV422, YUYV */ -- val = 0x30; -+ fmt = 0x30; -+ mux = OV5640_FMT_MUX_YUV422; - is_jpeg = true; - break; -+ case MEDIA_BUS_FMT_SBGGR8_1X8: -+ /* Raw, BGBG... / GRGR... */ -+ fmt = 0x00; -+ mux = OV5640_FMT_MUX_RAW_DPC; -+ break; -+ case MEDIA_BUS_FMT_SGBRG8_1X8: -+ /* Raw bayer, GBGB... / RGRG... */ -+ fmt = 0x01; -+ mux = OV5640_FMT_MUX_RAW_DPC; -+ break; -+ case MEDIA_BUS_FMT_SGRBG8_1X8: -+ /* Raw bayer, GRGR... / BGBG... */ -+ fmt = 0x02; -+ mux = OV5640_FMT_MUX_RAW_DPC; -+ break; -+ case MEDIA_BUS_FMT_SRGGB8_1X8: -+ /* Raw bayer, RGRG... / GBGB... */ -+ fmt = 0x03; -+ mux = OV5640_FMT_MUX_RAW_DPC; -+ break; - default: - return -EINVAL; - } - - /* FORMAT CONTROL00: YUV and RGB formatting */ -- ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, val); -+ ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); - if (ret) - return ret; - - /* FORMAT MUX CONTROL: ISP YUV or RGB */ -- ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, -- is_rgb ? 0x01 : 0x00); -+ ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); - if (ret) - return ret; - -@@ -2268,10 +2514,41 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) - return ret; - } - -+static const char * const test_pattern_menu[] = { -+ "Disabled", -+ "Color bars", -+ "Color bars w/ rolling bar", -+ "Color squares", -+ "Color squares w/ rolling bar", -+}; -+ -+#define OV5640_TEST_ENABLE BIT(7) -+#define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ -+#define OV5640_TEST_TRANSPARENT BIT(5) -+#define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ -+#define OV5640_TEST_BAR_STANDARD (0 << 2) -+#define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) -+#define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) -+#define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) -+#define OV5640_TEST_BAR (0 << 0) -+#define OV5640_TEST_RANDOM (1 << 0) -+#define OV5640_TEST_SQUARE (2 << 0) -+#define OV5640_TEST_BLACK (3 << 0) -+ -+static const u8 test_pattern_val[] = { -+ 0, -+ OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | -+ OV5640_TEST_BAR, -+ OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | -+ OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, -+ OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, -+ OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, -+}; -+ - static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) - { -- return ov5640_mod_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, -- 0xa4, value ? 0xa4 : 0); -+ return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, -+ test_pattern_val[value]); - } - - static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) -@@ -2399,6 +2676,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_VFLIP: - ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); - break; -+ case V4L2_CID_LINK_FREQ: -+ return 0; - default: - ret = -EINVAL; - break; -@@ -2412,11 +2691,6 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { - .s_ctrl = ov5640_s_ctrl, - }; - --static const char * const test_pattern_menu[] = { -- "Disabled", -- "Color bars", --}; -- - static int ov5640_init_controls(struct ov5640_dev *sensor) - { - const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; -@@ -2471,6 +2745,9 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) - V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ); - -+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, -+ 0, 0, link_freq_menu_items); -+ - if (hdl->error) { - ret = hdl->error; - goto free_ctrls; -@@ -2501,10 +2778,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, - return -EINVAL; - - fse->min_width = -- ov5640_mode_data[0][fse->index].hact; -+ ov5640_mode_data[fse->index].hact; - fse->max_width = fse->min_width; - fse->min_height = -- ov5640_mode_data[0][fse->index].vact; -+ ov5640_mode_data[fse->index].vact; - fse->max_height = fse->min_height; - - return 0; -@@ -2569,8 +2846,11 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, - - frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, - mode->hact, mode->vact); -- if (frame_rate < 0) -- frame_rate = OV5640_15_FPS; -+ if (frame_rate < 0) { -+ /* Always return a valid frame interval value */ -+ fi->interval = sensor->frame_interval; -+ goto out; -+ } - - mode = ov5640_find_mode(sensor, frame_rate, mode->hact, - mode->vact, true); -@@ -2735,7 +3015,7 @@ static int ov5640_probe(struct i2c_client *client, - sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; - sensor->current_fr = OV5640_30_FPS; - sensor->current_mode = -- &ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480]; -+ &ov5640_mode_data[OV5640_MODE_VGA_640_480]; - sensor->last_mode = sensor->current_mode; - - sensor->ae_target = 52; -diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c -new file mode 100644 -index 0000000..7751960 ---- /dev/null -+++ b/drivers/media/i2c/st-mipid02.c -@@ -0,0 +1,1076 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Driver for ST MIPID02 CSI-2 to PARALLEL bridge -+ * -+ * Copyright (C) STMicroelectronics SA 2019 -+ * Authors: Mickael Guene -+ * for STMicroelectronics. -+ * -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define V4L2_MBUS_CSI2_DPHY V4L2_MBUS_CSI2 -+ -+#define MIPID02_CLK_LANE_WR_REG1 0x01 -+#define MIPID02_CLK_LANE_REG1 0x02 -+#define MIPID02_CLK_LANE_REG3 0x04 -+#define MIPID02_DATA_LANE0_REG1 0x05 -+#define MIPID02_DATA_LANE0_REG2 0x06 -+#define MIPID02_DATA_LANE1_REG1 0x09 -+#define MIPID02_DATA_LANE1_REG2 0x0a -+#define MIPID02_MODE_REG1 0x14 -+#define MIPID02_MODE_REG2 0x15 -+#define MIPID02_DATA_ID_RREG 0x17 -+#define MIPID02_DATA_SELECTION_CTRL 0x19 -+#define MIPID02_PIX_WIDTH_CTRL 0x1e -+#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f -+ -+/* Bits definition for MIPID02_CLK_LANE_REG1 */ -+#define CLK_ENABLE BIT(0) -+/* Bits definition for MIPID02_CLK_LANE_REG3 */ -+#define CLK_MIPI_CSI BIT(1) -+/* Bits definition for MIPID02_DATA_LANE0_REG1 */ -+#define DATA_ENABLE BIT(0) -+/* Bits definition for MIPID02_DATA_LANEx_REG2 */ -+#define DATA_MIPI_CSI BIT(0) -+/* Bits definition for MIPID02_MODE_REG1 */ -+#define MODE_DATA_SWAP BIT(2) -+#define MODE_NO_BYPASS BIT(6) -+/* Bits definition for MIPID02_MODE_REG2 */ -+#define MODE_HSYNC_ACTIVE_HIGH BIT(1) -+#define MODE_VSYNC_ACTIVE_HIGH BIT(2) -+/* Bits definition for MIPID02_DATA_SELECTION_CTRL */ -+#define SELECTION_MANUAL_DATA BIT(2) -+#define SELECTION_MANUAL_WIDTH BIT(3) -+ -+static const u32 mipid02_supported_fmt_codes[] = { -+ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, -+ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, -+ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, -+ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, -+ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, -+ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, -+ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, -+ MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, -+ MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, -+ MEDIA_BUS_FMT_JPEG_1X8 -+}; -+ -+/* regulator supplies */ -+static const char * const mipid02_supply_name[] = { -+ "VDDE", /* 1.8V digital I/O supply */ -+ "VDDIN", /* 1V8 voltage regulator supply */ -+}; -+ -+#define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) -+ -+#define MIPID02_SINK_0 0 -+#define MIPID02_SINK_1 1 -+#define MIPID02_SOURCE 2 -+#define MIPID02_PAD_NB 3 -+ -+struct mipid02_dev { -+ struct i2c_client *i2c_client; -+ struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; -+ struct v4l2_subdev sd; -+ struct media_pad pad[MIPID02_PAD_NB]; -+ struct clk *xclk; -+ struct gpio_desc *reset_gpio; -+ /* endpoints info */ -+ struct v4l2_fwnode_endpoint rx; -+ u64 link_frequency; -+ struct v4l2_fwnode_endpoint tx; -+ /* remote source */ -+ struct v4l2_async_subdev asd; -+ struct v4l2_async_notifier notifier; -+ struct v4l2_subdev *s_subdev; -+ /* registers */ -+ struct { -+ u8 clk_lane_reg1; -+ u8 data_lane0_reg1; -+ u8 data_lane1_reg1; -+ u8 mode_reg1; -+ u8 mode_reg2; -+ u8 data_selection_ctrl; -+ u8 data_id_rreg; -+ u8 pix_width_ctrl; -+ u8 pix_width_ctrl_emb; -+ } r; -+ /* lock to protect all members below */ -+ struct mutex lock; -+ bool streaming; -+ struct v4l2_mbus_framefmt fmt; -+}; -+ -+static int bpp_from_code(__u32 code) -+{ -+ switch (code) { -+ case MEDIA_BUS_FMT_SBGGR8_1X8: -+ case MEDIA_BUS_FMT_SGBRG8_1X8: -+ case MEDIA_BUS_FMT_SGRBG8_1X8: -+ case MEDIA_BUS_FMT_SRGGB8_1X8: -+ return 8; -+ case MEDIA_BUS_FMT_SBGGR10_1X10: -+ case MEDIA_BUS_FMT_SGBRG10_1X10: -+ case MEDIA_BUS_FMT_SGRBG10_1X10: -+ case MEDIA_BUS_FMT_SRGGB10_1X10: -+ return 10; -+ case MEDIA_BUS_FMT_SBGGR12_1X12: -+ case MEDIA_BUS_FMT_SGBRG12_1X12: -+ case MEDIA_BUS_FMT_SGRBG12_1X12: -+ case MEDIA_BUS_FMT_SRGGB12_1X12: -+ return 12; -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_YUYV8_2X8: -+ case MEDIA_BUS_FMT_UYVY8_2X8: -+ case MEDIA_BUS_FMT_RGB565_2X8_LE: -+ case MEDIA_BUS_FMT_RGB565_2X8_BE: -+ return 16; -+ case MEDIA_BUS_FMT_BGR888_1X24: -+ return 24; -+ default: -+ return 0; -+ } -+} -+ -+static u8 data_type_from_code(__u32 code) -+{ -+ switch (code) { -+ case MEDIA_BUS_FMT_SBGGR8_1X8: -+ case MEDIA_BUS_FMT_SGBRG8_1X8: -+ case MEDIA_BUS_FMT_SGRBG8_1X8: -+ case MEDIA_BUS_FMT_SRGGB8_1X8: -+ return 0x2a; -+ case MEDIA_BUS_FMT_SBGGR10_1X10: -+ case MEDIA_BUS_FMT_SGBRG10_1X10: -+ case MEDIA_BUS_FMT_SGRBG10_1X10: -+ case MEDIA_BUS_FMT_SRGGB10_1X10: -+ return 0x2b; -+ case MEDIA_BUS_FMT_SBGGR12_1X12: -+ case MEDIA_BUS_FMT_SGBRG12_1X12: -+ case MEDIA_BUS_FMT_SGRBG12_1X12: -+ case MEDIA_BUS_FMT_SRGGB12_1X12: -+ return 0x2c; -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ case MEDIA_BUS_FMT_YUYV8_2X8: -+ case MEDIA_BUS_FMT_UYVY8_2X8: -+ return 0x1e; -+ case MEDIA_BUS_FMT_BGR888_1X24: -+ return 0x24; -+ case MEDIA_BUS_FMT_RGB565_2X8_LE: -+ case MEDIA_BUS_FMT_RGB565_2X8_BE: -+ return 0x22; -+ default: -+ return 0; -+ } -+} -+ -+static void init_format(struct v4l2_mbus_framefmt *fmt) -+{ -+ fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->colorspace = V4L2_COLORSPACE_SRGB; -+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); -+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; -+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); -+ fmt->width = 640; -+ fmt->height = 480; -+} -+ -+static __u32 get_fmt_code(__u32 code) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { -+ if (code == mipid02_supported_fmt_codes[i]) -+ return code; -+ } -+ -+ return mipid02_supported_fmt_codes[0]; -+} -+ -+static __u32 serial_to_parallel_code(__u32 serial) -+{ -+ if (serial == MEDIA_BUS_FMT_UYVY8_1X16) -+ return MEDIA_BUS_FMT_UYVY8_2X8; -+ if (serial == MEDIA_BUS_FMT_BGR888_1X24) -+ return MEDIA_BUS_FMT_BGR888_3X8; -+ -+ return serial; -+} -+ -+static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct mipid02_dev, sd); -+} -+ -+static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ struct i2c_msg msg[2]; -+ u8 buf[2]; -+ int ret; -+ -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ -+ msg[0].addr = client->addr; -+ msg[0].flags = client->flags; -+ msg[0].buf = buf; -+ msg[0].len = sizeof(buf); -+ -+ msg[1].addr = client->addr; -+ msg[1].flags = client->flags | I2C_M_RD; -+ msg[1].buf = val; -+ msg[1].len = 1; -+ -+ ret = i2c_transfer(client->adapter, msg, 2); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", -+ __func__, client->addr, reg, ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ struct i2c_msg msg; -+ u8 buf[3]; -+ int ret; -+ -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ buf[2] = val; -+ -+ msg.addr = client->addr; -+ msg.flags = client->flags; -+ msg.buf = buf; -+ msg.len = sizeof(buf); -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", -+ __func__, reg, ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int mipid02_get_regulators(struct mipid02_dev *bridge) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) -+ bridge->supplies[i].supply = mipid02_supply_name[i]; -+ -+ return devm_regulator_bulk_get(&bridge->i2c_client->dev, -+ MIPID02_NUM_SUPPLIES, -+ bridge->supplies); -+} -+ -+static void mipid02_apply_reset(struct mipid02_dev *bridge) -+{ -+ gpiod_set_value_cansleep(bridge->reset_gpio, 0); -+ usleep_range(5000, 10000); -+ gpiod_set_value_cansleep(bridge->reset_gpio, 1); -+ usleep_range(5000, 10000); -+ gpiod_set_value_cansleep(bridge->reset_gpio, 0); -+ usleep_range(5000, 10000); -+} -+ -+static int mipid02_set_power_on(struct mipid02_dev *bridge) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ int ret; -+ -+ ret = clk_prepare_enable(bridge->xclk); -+ if (ret) { -+ dev_err(&client->dev, "%s: failed to enable clock\n", __func__); -+ return ret; -+ } -+ -+ ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, -+ bridge->supplies); -+ if (ret) { -+ dev_err(&client->dev, "%s: failed to enable regulators\n", -+ __func__); -+ goto xclk_off; -+ } -+ -+ if (bridge->reset_gpio) { -+ dev_dbg(&client->dev, "apply reset"); -+ mipid02_apply_reset(bridge); -+ } else { -+ dev_dbg(&client->dev, "don't apply reset"); -+ usleep_range(5000, 10000); -+ } -+ -+ return 0; -+ -+xclk_off: -+ clk_disable_unprepare(bridge->xclk); -+ return ret; -+} -+ -+static void mipid02_set_power_off(struct mipid02_dev *bridge) -+{ -+ regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); -+ clk_disable_unprepare(bridge->xclk); -+} -+ -+static int mipid02_detect(struct mipid02_dev *bridge) -+{ -+ u8 reg; -+ -+ /* -+ * There is no version registers. Just try to read register -+ * MIPID02_CLK_LANE_WR_REG1. -+ */ -+ return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); -+} -+ -+static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, -+ struct v4l2_subdev *subdev) -+{ -+ struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; -+ struct v4l2_ctrl *ctrl; -+ int ret; -+ -+ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); -+ if (!ctrl) -+ return 0; -+ qm.index = v4l2_ctrl_g_ctrl(ctrl); -+ -+ ret = v4l2_querymenu(subdev->ctrl_handler, &qm); -+ if (ret) -+ return 0; -+ -+ return qm.value; -+} -+ -+static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, -+ struct v4l2_subdev *subdev) -+{ -+ struct v4l2_fwnode_endpoint *ep = &bridge->rx; -+ struct v4l2_ctrl *ctrl; -+ u32 pixel_clock; -+ u32 bpp = bpp_from_code(bridge->fmt.code); -+ -+ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); -+ if (!ctrl) -+ return 0; -+ pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); -+ -+ return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); -+} -+ -+/* -+ * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency -+ * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel -+ * and number of lanes. -+ */ -+static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ struct v4l2_subdev *subdev = bridge->s_subdev; -+ u32 link_freq; -+ -+ link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); -+ if (!link_freq) { -+ link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, -+ subdev); -+ if (!link_freq) { -+ dev_err(&client->dev, "Failed to get link frequency"); -+ return -EINVAL; -+ } -+ } -+ -+ dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); -+ bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; -+ -+ return 0; -+} -+ -+static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ struct v4l2_fwnode_endpoint *ep = &bridge->rx; -+ bool *polarities = ep->bus.mipi_csi2.lane_polarities; -+ -+ /* midid02 doesn't support clock lane remapping */ -+ if (ep->bus.mipi_csi2.clock_lane != 0) { -+ dev_err(&client->dev, "clk lane must be map to lane 0\n"); -+ return -EINVAL; -+ } -+ bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; -+ -+ return 0; -+} -+ -+static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, -+ bool are_lanes_swap, bool *polarities) -+{ -+ bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; -+ -+ if (nb == 1 && are_lanes_swap) -+ return 0; -+ -+ /* -+ * data lane 0 as pin swap polarity reversed compared to clock and -+ * data lane 1 -+ */ -+ if (!are_pin_swap) -+ bridge->r.data_lane0_reg1 = 1 << 1; -+ bridge->r.data_lane0_reg1 |= DATA_ENABLE; -+ -+ return 0; -+} -+ -+static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, -+ bool are_lanes_swap, bool *polarities) -+{ -+ bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; -+ -+ if (nb == 1 && !are_lanes_swap) -+ return 0; -+ -+ if (are_pin_swap) -+ bridge->r.data_lane1_reg1 = 1 << 1; -+ bridge->r.data_lane1_reg1 |= DATA_ENABLE; -+ -+ return 0; -+} -+ -+static int mipid02_configure_from_rx(struct mipid02_dev *bridge) -+{ -+ struct v4l2_fwnode_endpoint *ep = &bridge->rx; -+ bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; -+ bool *polarities = ep->bus.mipi_csi2.lane_polarities; -+ int nb = ep->bus.mipi_csi2.num_data_lanes; -+ int ret; -+ -+ ret = mipid02_configure_clk_lane(bridge); -+ if (ret) -+ return ret; -+ -+ ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, -+ polarities); -+ if (ret) -+ return ret; -+ -+ ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, -+ polarities); -+ if (ret) -+ return ret; -+ -+ bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; -+ bridge->r.mode_reg1 |= (nb - 1) << 1; -+ -+ return mipid02_configure_from_rx_speed(bridge); -+} -+ -+static int mipid02_configure_from_tx(struct mipid02_dev *bridge) -+{ -+ struct v4l2_fwnode_endpoint *ep = &bridge->tx; -+ -+ bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; -+ bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; -+ bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; -+ if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) -+ bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; -+ if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) -+ bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; -+ -+ return 0; -+} -+ -+static int mipid02_configure_from_code(struct mipid02_dev *bridge) -+{ -+ u8 data_type; -+ -+ bridge->r.data_id_rreg = 0; -+ -+ if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { -+ bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; -+ -+ data_type = data_type_from_code(bridge->fmt.code); -+ if (!data_type) -+ return -EINVAL; -+ bridge->r.data_id_rreg = data_type; -+ } -+ -+ return 0; -+} -+ -+static int mipid02_stream_disable(struct mipid02_dev *bridge) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ int ret; -+ -+ /* Disable all lanes */ -+ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); -+ if (ret) -+ goto error; -+error: -+ if (ret) -+ dev_err(&client->dev, "failed to stream off %d", ret); -+ -+ return ret; -+} -+ -+static int mipid02_stream_enable(struct mipid02_dev *bridge) -+{ -+ struct i2c_client *client = bridge->i2c_client; -+ int ret = -EINVAL; -+ -+ if (!bridge->s_subdev) -+ goto error; -+ -+ memset(&bridge->r, 0, sizeof(bridge->r)); -+ /* build registers content */ -+ ret = mipid02_configure_from_rx(bridge); -+ if (ret) -+ goto error; -+ ret = mipid02_configure_from_tx(bridge); -+ if (ret) -+ goto error; -+ ret = mipid02_configure_from_code(bridge); -+ if (ret) -+ goto error; -+ -+ /* write mipi registers */ -+ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, -+ bridge->r.clk_lane_reg1); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, -+ bridge->r.data_lane0_reg1); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, -+ DATA_MIPI_CSI); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, -+ bridge->r.data_lane1_reg1); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, -+ DATA_MIPI_CSI); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, -+ MODE_NO_BYPASS | bridge->r.mode_reg1); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, -+ bridge->r.mode_reg2); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, -+ bridge->r.data_id_rreg); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, -+ bridge->r.data_selection_ctrl); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, -+ bridge->r.pix_width_ctrl); -+ if (ret) -+ goto error; -+ ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, -+ bridge->r.pix_width_ctrl_emb); -+ if (ret) -+ goto error; -+ -+ return 0; -+ -+error: -+ dev_err(&client->dev, "failed to stream on %d", ret); -+ mipid02_stream_disable(bridge); -+ -+ return ret; -+} -+ -+static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ struct i2c_client *client = bridge->i2c_client; -+ int ret = 0; -+ -+ dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, -+ enable, bridge->streaming); -+ mutex_lock(&bridge->lock); -+ -+ if (bridge->streaming == enable) -+ goto out; -+ -+ ret = enable ? mipid02_stream_enable(bridge) : -+ mipid02_stream_disable(bridge); -+ if (!ret) -+ bridge->streaming = enable; -+ -+out: -+ dev_dbg(&client->dev, "%s current now = %d / %d", __func__, -+ bridge->streaming, ret); -+ mutex_unlock(&bridge->lock); -+ -+ return ret; -+} -+ -+static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ int ret = 0; -+ -+ switch (code->pad) { -+ case MIPID02_SINK_0: -+ if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) -+ ret = -EINVAL; -+ else -+ code->code = mipid02_supported_fmt_codes[code->index]; -+ break; -+ case MIPID02_SOURCE: -+ if (code->index == 0) -+ code->code = serial_to_parallel_code(bridge->fmt.code); -+ else -+ ret = -EINVAL; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int mipid02_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format; -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ struct i2c_client *client = bridge->i2c_client; -+ struct v4l2_mbus_framefmt *fmt; -+ -+ dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); -+ -+ if (format->pad >= MIPID02_PAD_NB) -+ return -EINVAL; -+ /* second CSI-2 pad not yet supported */ -+ if (format->pad == MIPID02_SINK_1) -+ return -EINVAL; -+ -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) -+ fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad); -+ else -+ fmt = &bridge->fmt; -+ -+ mutex_lock(&bridge->lock); -+ -+ *mbus_fmt = *fmt; -+ /* code may need to be converted for source */ -+ if (format->pad == MIPID02_SOURCE) -+ mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); -+ -+ mutex_unlock(&bridge->lock); -+ -+ return 0; -+} -+ -+static void mipid02_set_fmt_source(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ -+ /* source pad mirror active sink pad */ -+ format->format = bridge->fmt; -+ /* but code may need to be converted */ -+ format->format.code = serial_to_parallel_code(format->format.code); -+ -+ /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ -+ if (format->which != V4L2_SUBDEV_FORMAT_TRY) -+ return; -+ -+ *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format; -+} -+ -+static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ struct v4l2_mbus_framefmt *fmt; -+ -+ format->format.code = get_fmt_code(format->format.code); -+ -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) -+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); -+ else -+ fmt = &bridge->fmt; -+ -+ *fmt = format->format; -+} -+ -+static int mipid02_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ struct i2c_client *client = bridge->i2c_client; -+ int ret = 0; -+ -+ dev_dbg(&client->dev, "%s for %d", __func__, format->pad); -+ -+ if (format->pad >= MIPID02_PAD_NB) -+ return -EINVAL; -+ /* second CSI-2 pad not yet supported */ -+ if (format->pad == MIPID02_SINK_1) -+ return -EINVAL; -+ -+ mutex_lock(&bridge->lock); -+ -+ if (bridge->streaming) { -+ ret = -EBUSY; -+ goto error; -+ } -+ -+ if (format->pad == MIPID02_SOURCE) -+ mipid02_set_fmt_source(sd, cfg, format); -+ else -+ mipid02_set_fmt_sink(sd, cfg, format); -+ -+error: -+ mutex_unlock(&bridge->lock); -+ -+ return ret; -+} -+ -+static const struct v4l2_subdev_video_ops mipid02_video_ops = { -+ .s_stream = mipid02_s_stream, -+}; -+ -+static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { -+ .enum_mbus_code = mipid02_enum_mbus_code, -+ .get_fmt = mipid02_get_fmt, -+ .set_fmt = mipid02_set_fmt, -+}; -+ -+static const struct v4l2_subdev_ops mipid02_subdev_ops = { -+ .video = &mipid02_video_ops, -+ .pad = &mipid02_pad_ops, -+}; -+ -+static const struct media_entity_operations mipid02_subdev_entity_ops = { -+ .link_validate = v4l2_subdev_link_validate, -+}; -+ -+static int mipid02_async_bound(struct v4l2_async_notifier *notifier, -+ struct v4l2_subdev *s_subdev, -+ struct v4l2_async_subdev *asd) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); -+ struct i2c_client *client = bridge->i2c_client; -+ int source_pad; -+ int ret; -+ -+ dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev); -+ -+ source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, -+ s_subdev->fwnode, -+ MEDIA_PAD_FL_SOURCE); -+ if (source_pad < 0) { -+ dev_err(&client->dev, "Couldn't find output pad for subdev %s\n", -+ s_subdev->name); -+ return source_pad; -+ } -+ -+ ret = media_create_pad_link(&s_subdev->entity, source_pad, -+ &bridge->sd.entity, 0, -+ MEDIA_LNK_FL_ENABLED | -+ MEDIA_LNK_FL_IMMUTABLE); -+ if (ret) { -+ dev_err(&client->dev, "Couldn't create media link %d", ret); -+ return ret; -+ } -+ -+ bridge->s_subdev = s_subdev; -+ -+ return 0; -+} -+ -+static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, -+ struct v4l2_subdev *s_subdev, -+ struct v4l2_async_subdev *asd) -+{ -+ struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); -+ -+ bridge->s_subdev = NULL; -+} -+ -+static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { -+ .bound = mipid02_async_bound, -+ .unbind = mipid02_async_unbind, -+}; -+ -+static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) -+{ -+ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; -+ struct i2c_client *client = bridge->i2c_client; -+ struct device_node *ep_node; -+ int ret; -+ -+ /* parse rx (endpoint 0) */ -+ ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, -+ 0, 0); -+ if (!ep_node) { -+ dev_err(&client->dev, "unable to find port0 ep"); -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); -+ if (ret) { -+ dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n", -+ ret); -+ goto error_of_node_put; -+ } -+ -+ /* do some sanity checks */ -+ if (ep.bus.mipi_csi2.num_data_lanes > 2) { -+ dev_err(&client->dev, "max supported data lanes is 2 / got %d", -+ ep.bus.mipi_csi2.num_data_lanes); -+ ret = -EINVAL; -+ goto error_of_node_put; -+ } -+ -+ /* register it for later use */ -+ bridge->rx = ep; -+ -+ /* register async notifier so we get noticed when sensor is connected */ -+ bridge->asd.match.fwnode = -+ fwnode_graph_get_remote_port_parent(of_fwnode_handle(ep_node)); -+ bridge->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; -+ of_node_put(ep_node); -+ bridge->notifier.subdevs = -+ devm_kzalloc(&bridge->i2c_client->dev, -+ sizeof(*bridge->notifier.subdevs), -+ GFP_KERNEL); -+ if (!bridge->notifier.subdevs) -+ return -ENOMEM; -+ bridge->notifier.subdevs[0] = &bridge->asd; -+ bridge->notifier.num_subdevs = 1; -+ bridge->notifier.ops = &mipid02_notifier_ops; -+ -+ ret = v4l2_async_subdev_notifier_register(&bridge->sd, -+ &bridge->notifier); -+ if (ret) -+ v4l2_async_notifier_cleanup(&bridge->notifier); -+ -+ return ret; -+ -+error_of_node_put: -+ of_node_put(ep_node); -+error: -+ -+ return ret; -+} -+ -+static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) -+{ -+ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; -+ struct i2c_client *client = bridge->i2c_client; -+ struct device_node *ep_node; -+ int ret; -+ -+ /* parse tx (endpoint 2) */ -+ ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, -+ 2, 0); -+ if (!ep_node) { -+ dev_err(&client->dev, "unable to find port1 ep"); -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); -+ if (ret) { -+ dev_err(&client->dev, "Could not parse v4l2 endpoint\n"); -+ goto error_of_node_put; -+ } -+ -+ of_node_put(ep_node); -+ bridge->tx = ep; -+ -+ return 0; -+ -+error_of_node_put: -+ of_node_put(ep_node); -+error: -+ -+ return -EINVAL; -+} -+ -+static int mipid02_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct mipid02_dev *bridge; -+ u32 clk_freq; -+ int ret; -+ -+ bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); -+ if (!bridge) -+ return -ENOMEM; -+ -+ init_format(&bridge->fmt); -+ -+ bridge->i2c_client = client; -+ v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); -+ -+ /* got and check clock */ -+ bridge->xclk = devm_clk_get(dev, "xclk"); -+ if (IS_ERR(bridge->xclk)) { -+ dev_err(dev, "failed to get xclk\n"); -+ return PTR_ERR(bridge->xclk); -+ } -+ -+ clk_freq = clk_get_rate(bridge->xclk); -+ if (clk_freq < 6000000 || clk_freq > 27000000) { -+ dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n", -+ clk_freq); -+ return -EINVAL; -+ } -+ -+ bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", -+ GPIOD_OUT_HIGH); -+ -+ ret = mipid02_get_regulators(bridge); -+ if (ret) { -+ dev_err(dev, "failed to get regulators %d", ret); -+ return ret; -+ } -+ -+ mutex_init(&bridge->lock); -+ bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; -+ bridge->sd.entity.ops = &mipid02_subdev_entity_ops; -+ bridge->pad[0].flags = MEDIA_PAD_FL_SINK; -+ bridge->pad[1].flags = MEDIA_PAD_FL_SINK; -+ bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; -+ ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB, -+ bridge->pad); -+ if (ret) { -+ dev_err(&client->dev, "pads init failed %d", ret); -+ goto mutex_cleanup; -+ } -+ -+ /* enable clock, power and reset device if available */ -+ ret = mipid02_set_power_on(bridge); -+ if (ret) -+ goto entity_cleanup; -+ -+ ret = mipid02_detect(bridge); -+ if (ret) { -+ dev_err(&client->dev, "failed to detect mipid02 %d", ret); -+ goto power_off; -+ } -+ -+ ret = mipid02_parse_tx_ep(bridge); -+ if (ret) { -+ dev_err(&client->dev, "failed to parse tx %d", ret); -+ goto power_off; -+ } -+ -+ ret = mipid02_parse_rx_ep(bridge); -+ if (ret) { -+ dev_err(&client->dev, "failed to parse rx %d", ret); -+ goto power_off; -+ } -+ -+ ret = v4l2_async_register_subdev(&bridge->sd); -+ if (ret < 0) { -+ dev_err(&client->dev, "v4l2_async_register_subdev failed %d", -+ ret); -+ goto unregister_notifier; -+ } -+ -+ dev_info(&client->dev, "mipid02 device probe successfully"); -+ -+ return 0; -+ -+unregister_notifier: -+ v4l2_async_notifier_unregister(&bridge->notifier); -+ v4l2_async_notifier_cleanup(&bridge->notifier); -+power_off: -+ mipid02_set_power_off(bridge); -+entity_cleanup: -+ media_entity_cleanup(&bridge->sd.entity); -+mutex_cleanup: -+ mutex_destroy(&bridge->lock); -+ -+ return ret; -+} -+ -+static int mipid02_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct mipid02_dev *bridge = to_mipid02_dev(sd); -+ -+ v4l2_async_notifier_unregister(&bridge->notifier); -+ v4l2_async_notifier_cleanup(&bridge->notifier); -+ v4l2_async_unregister_subdev(&bridge->sd); -+ mipid02_set_power_off(bridge); -+ media_entity_cleanup(&bridge->sd.entity); -+ mutex_destroy(&bridge->lock); -+ -+ return 0; -+} -+ -+static const struct of_device_id mipid02_dt_ids[] = { -+ { .compatible = "st,st-mipid02" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, mipid02_dt_ids); -+ -+static struct i2c_driver mipid02_i2c_driver = { -+ .driver = { -+ .name = "st-mipid02", -+ .of_match_table = mipid02_dt_ids, -+ }, -+ .probe_new = mipid02_probe, -+ .remove = mipid02_remove, -+}; -+ -+module_i2c_driver(mipid02_i2c_driver); -+ -+MODULE_AUTHOR("Mickael Guene "); -+MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 54fe90a..6f0721e 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -111,7 +111,7 @@ config VIDEO_S3C_CAMIF - - config VIDEO_STM32_DCMI - tristate "STM32 Digital Camera Memory Interface (DCMI) support" -- depends on VIDEO_V4L2 && OF -+ depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER - depends on ARCH_STM32 || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_FWNODE -diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c -index 7c496bc..1e657fe 100644 ---- a/drivers/media/platform/stm32/stm32-cec.c -+++ b/drivers/media/platform/stm32/stm32-cec.c -@@ -11,7 +11,9 @@ - #include - #include - #include -+#include - #include -+#include - #include - - #include -@@ -56,6 +58,13 @@ - #define ALL_TX_IT (TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST) - #define ALL_RX_IT (RXEND | RXBR | RXACKE | RXOVR) - -+/* -+ * 400 ms is the time it takes for one 16 byte message to be -+ * transferred and 5 is the maximum number of retries. Add -+ * another 100 ms as a margin. -+ */ -+#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) -+ - struct stm32_cec { - struct cec_adapter *adap; - struct device *dev; -@@ -68,6 +77,9 @@ struct stm32_cec { - struct cec_msg rx_msg; - struct cec_msg tx_msg; - int tx_cnt; -+ u32 c_reg; -+ u32 ie_reg; -+ u32 cfg_reg; - }; - - static void cec_hw_init(struct stm32_cec *cec) -@@ -174,6 +186,9 @@ static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable) - dev_err(cec->dev, "fail to enable cec clock\n"); - - clk_enable(cec->clk_hdmi_cec); -+ -+ cec_hw_init(cec); -+ - regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN); - } else { - clk_disable(cec->clk_cec); -@@ -188,7 +203,11 @@ static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) - { - struct stm32_cec *cec = adap->priv; - u32 oar = (1 << logical_addr) << 16; -+ u32 val; - -+ /* Poll every 100µs the register CEC_CR to wait end of transmission */ -+ regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), -+ 100, CEC_XFER_TIMEOUT_MS * 1000); - regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); - - if (logical_addr == CEC_LOG_ADDR_INVALID) -@@ -260,8 +279,8 @@ static int stm32_cec_probe(struct platform_device *pdev) - if (IS_ERR(mmio)) - return PTR_ERR(mmio); - -- cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio, -- &stm32_cec_regmap_cfg); -+ cec->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, -+ &stm32_cec_regmap_cfg); - - if (IS_ERR(cec->regmap)) - return PTR_ERR(cec->regmap); -@@ -315,8 +334,6 @@ static int stm32_cec_probe(struct platform_device *pdev) - return ret; - } - -- cec_hw_init(cec); -- - platform_set_drvdata(pdev, cec); - - return 0; -@@ -334,6 +351,76 @@ static int stm32_cec_remove(struct platform_device *pdev) - return 0; - } - -+static __maybe_unused int cec_runtime_suspend(struct device *dev) -+{ -+ struct stm32_cec *cec = dev_get_drvdata(dev); -+ -+ clk_disable(cec->clk_cec); -+ clk_disable(cec->clk_hdmi_cec); -+ -+ return 0; -+} -+ -+static __maybe_unused int cec_runtime_resume(struct device *dev) -+{ -+ struct stm32_cec *cec = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_enable(cec->clk_cec); -+ if (ret) { -+ dev_err(cec->dev, "fail to enable cec clock\n"); -+ return ret; -+ } -+ -+ ret = clk_enable(cec->clk_hdmi_cec); -+ if (ret) -+ dev_err(cec->dev, "fail to enable hdmi cec clock\n"); -+ -+ return ret; -+} -+ -+static __maybe_unused int cec_suspend(struct device *dev) -+{ -+ struct stm32_cec *cec = dev_get_drvdata(dev); -+ -+ /* change pinctrl state */ -+ pinctrl_pm_select_sleep_state(dev); -+ -+ /* save resgisters settings to cec context */ -+ regmap_read(cec->regmap, CEC_CR, &cec->c_reg); -+ regmap_read(cec->regmap, CEC_IER, &cec->ie_reg); -+ regmap_read(cec->regmap, CEC_CFGR, &cec->cfg_reg); -+ -+ /* disable clock */ -+ pm_runtime_force_suspend(dev); -+ -+ return 0; -+} -+ -+static __maybe_unused int cec_resume(struct device *dev) -+{ -+ struct stm32_cec *cec = dev_get_drvdata(dev); -+ -+ /* clock enable */ -+ pm_runtime_force_resume(dev); -+ -+ /* restore from cec context registers settings */ -+ regmap_write(cec->regmap, CEC_CFGR, cec->cfg_reg); -+ regmap_write(cec->regmap, CEC_IER, cec->ie_reg); -+ regmap_write(cec->regmap, CEC_CR, cec->c_reg); -+ -+ /* restore pinctl default state */ -+ pinctrl_pm_select_default_state(dev); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops cec_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(cec_suspend, cec_resume) -+ SET_RUNTIME_PM_OPS(cec_runtime_suspend, -+ cec_runtime_resume, NULL) -+}; -+ - static const struct of_device_id stm32_cec_of_match[] = { - { .compatible = "st,stm32-cec" }, - { /* end node */ } -@@ -346,6 +433,7 @@ static struct platform_driver stm32_cec_driver = { - .driver = { - .name = CEC_NAME, - .of_match_table = stm32_cec_of_match, -+ .pm = &cec_pm_ops, - }, - }; - -diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index 18d0b56..0a59f44 100644 ---- a/drivers/media/platform/stm32/stm32-dcmi.c -+++ b/drivers/media/platform/stm32/stm32-dcmi.c -@@ -95,13 +95,18 @@ enum state { - #define MIN_HEIGHT 16U - #define MAX_HEIGHT 2592U - -+/* DMA can sustain YUV 720p@15fps max */ -+#define MAX_DMA_BANDWIDTH (1280 * 720 * 2 * 15) -+ - #define TIMEOUT_MS 1000 - --struct dcmi_graph_entity { -- struct device_node *node; -+#define OVERRUN_ERROR_THRESHOLD 3 - -+struct dcmi_graph_entity { - struct v4l2_async_subdev asd; -- struct v4l2_subdev *subdev; -+ -+ struct device_node *remote_node; -+ struct v4l2_subdev *source; - }; - - struct dcmi_format { -@@ -167,6 +172,10 @@ struct stm32_dcmi { - - /* Ensure DMA operations atomicity */ - struct mutex dma_lock; -+ -+ struct media_device mdev; -+ struct media_pad vid_cap_pad; -+ struct media_pipeline pipeline; - }; - - static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) -@@ -446,11 +455,13 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) - - spin_lock_irq(&dcmi->irqlock); - -- if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { -- dcmi->errors_count++; -- if (dcmi->misr & IT_OVR) -- dcmi->overrun_count++; -+ if (dcmi->misr & IT_OVR) { -+ dcmi->overrun_count++; -+ if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) -+ dcmi->errors_count++; - } -+ if (dcmi->misr & IT_ERR) -+ dcmi->errors_count++; - - if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && - dcmi->misr & IT_FRAME) { -@@ -576,6 +587,144 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) - spin_unlock_irq(&dcmi->irqlock); - } - -+static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) -+{ -+ struct media_entity *entity = &dcmi->vdev->entity; -+ struct media_pad *pad; -+ -+ /* Walk searching for entity having no sink */ -+ while (1) { -+ pad = &entity->pads[0]; -+ if (!(pad->flags & MEDIA_PAD_FL_SINK)) -+ break; -+ -+ pad = media_entity_remote_pad(pad); -+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) -+ break; -+ -+ entity = pad->entity; -+ } -+ -+ return entity; -+} -+ -+static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, -+ struct v4l2_subdev_pad_config *pad_cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct media_entity *entity = &dcmi->entity.source->entity; -+ struct v4l2_subdev *subdev; -+ struct media_pad *sink_pad = NULL; -+ struct media_pad *src_pad = NULL; -+ struct media_pad *pad = NULL; -+ struct v4l2_subdev_format fmt = *format; -+ bool found = false; -+ int ret; -+ -+ /* -+ * Starting from sensor subdevice, walk within -+ * pipeline and set format on each subdevice -+ */ -+ while (1) { -+ unsigned int i; -+ -+ /* Search if current entity has a source pad */ -+ for (i = 0; i < entity->num_pads; i++) { -+ pad = &entity->pads[i]; -+ if (pad->flags & MEDIA_PAD_FL_SOURCE) { -+ src_pad = pad; -+ found = true; -+ break; -+ } -+ } -+ if (!found) -+ break; -+ -+ subdev = media_entity_to_v4l2_subdev(entity); -+ -+ /* Propagate format on sink pad if any, otherwise source pad */ -+ if (sink_pad) -+ pad = sink_pad; -+ -+ dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n", -+ subdev->name, pad->index, format->format.code, -+ format->format.width, format->format.height); -+ -+ fmt.pad = pad->index; -+ ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt); -+ if (ret < 0) { -+ dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", -+ __func__, format->format.code, -+ format->format.width, format->format.height, -+ subdev->name, pad->index, ret); -+ return ret; -+ } -+ -+ if (fmt.format.code != format->format.code || -+ fmt.format.width != format->format.width || -+ fmt.format.height != format->format.height) { -+ dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n", -+ subdev->name, pad->index, fmt.format.code, -+ fmt.format.width, fmt.format.height); -+ } -+ -+ /* Walk to next entity */ -+ sink_pad = media_entity_remote_pad(src_pad); -+ if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) -+ break; -+ -+ entity = sink_pad->entity; -+ } -+ *format = fmt; -+ -+ return 0; -+} -+ -+static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) -+{ -+ struct media_entity *entity = &dcmi->vdev->entity; -+ struct v4l2_subdev *subdev; -+ struct media_pad *pad; -+ int ret; -+ -+ /* Start/stop all entities within pipeline */ -+ while (1) { -+ pad = &entity->pads[0]; -+ if (!(pad->flags & MEDIA_PAD_FL_SINK)) -+ break; -+ -+ pad = media_entity_remote_pad(pad); -+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) -+ break; -+ -+ entity = pad->entity; -+ subdev = media_entity_to_v4l2_subdev(entity); -+ -+ ret = v4l2_subdev_call(subdev, video, s_stream, state); -+ if (ret < 0 && ret != -ENOIOCTLCMD) { -+ dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n", -+ __func__, subdev->name, -+ state ? "start" : "stop", ret); -+ return ret; -+ } -+ -+ dev_dbg(dcmi->dev, "\"%s\" is %s\n", -+ subdev->name, state ? "started" : "stopped"); -+ } -+ -+ return 0; -+} -+ -+static int dcmi_pipeline_start(struct stm32_dcmi *dcmi) -+{ -+ return dcmi_pipeline_s_stream(dcmi, 1); -+} -+ -+static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) -+{ -+ dcmi_pipeline_s_stream(dcmi, 0); -+} -+ - static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - { - struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); -@@ -590,14 +739,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - goto err_release_buffers; - } - -- /* Enable stream on the sub device */ -- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1); -- if (ret && ret != -ENOIOCTLCMD) { -- dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error", -- __func__); -+ ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); -+ if (ret < 0) { -+ dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", -+ __func__, ret); - goto err_pm_put; - } - -+ ret = dcmi_pipeline_start(dcmi); -+ if (ret) -+ goto err_media_pipeline_stop; -+ - spin_lock_irq(&dcmi->irqlock); - - /* Set bus width */ -@@ -635,8 +787,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - dcmi_set_crop(dcmi); - - /* Enable jpeg capture */ -- if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) -- reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ -+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) { -+ unsigned int rate; -+ struct v4l2_streamparm p = { -+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE -+ }; -+ struct v4l2_fract frame_interval = {1, 30}; -+ -+ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.source, &p); -+ if (!ret) -+ frame_interval = p.parm.capture.timeperframe; -+ -+ rate = dcmi->fmt.fmt.pix.sizeimage * -+ frame_interval.denominator / frame_interval.numerator; -+ -+ /* -+ * If rate exceed DMA capabilities, switch to snapshot mode -+ * to ensure that current DMA transfer is elapsed before -+ * capturing a new JPEG. -+ */ -+ if (rate > MAX_DMA_BANDWIDTH) { -+ reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ -+ dev_dbg(dcmi->dev, "Capture rate is too high for continuous mode (%d > %d bytes/s), switch to snapshot mode\n", -+ rate, MAX_DMA_BANDWIDTH); -+ } -+ } - - /* Enable dcmi */ - reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); -@@ -669,16 +844,22 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - if (ret) { - dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", - __func__); -- goto err_subdev_streamoff; -+ goto err_pipeline_stop; - } - - /* Enable interruptions */ -- reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); -+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) -+ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); -+ else -+ reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR); - - return 0; - --err_subdev_streamoff: -- v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); -+err_pipeline_stop: -+ dcmi_pipeline_stop(dcmi); -+ -+err_media_pipeline_stop: -+ media_pipeline_stop(&dcmi->vdev->entity); - - err_pm_put: - pm_runtime_put(dcmi->dev); -@@ -703,13 +884,10 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) - { - struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); - struct dcmi_buf *buf, *node; -- int ret; - -- /* Disable stream on the sub device */ -- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); -- if (ret && ret != -ENOIOCTLCMD) -- dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", -- __func__, ret); -+ dcmi_pipeline_stop(dcmi); -+ -+ media_pipeline_stop(&dcmi->vdev->entity); - - spin_lock_irq(&dcmi->irqlock); - -@@ -850,7 +1028,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, - } - - v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, - &pad_cfg, &format); - if (ret < 0) - return ret; -@@ -927,8 +1105,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) - mf->width = sd_framesize.width; - mf->height = sd_framesize.height; - -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, -- set_fmt, NULL, &format); -+ ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); - if (ret < 0) - return ret; - -@@ -984,7 +1161,7 @@ static int dcmi_get_sensor_format(struct stm32_dcmi *dcmi, - }; - int ret; - -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt); -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_fmt, NULL, &fmt); - if (ret) - return ret; - -@@ -1013,7 +1190,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, - } - - v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, - &pad_cfg, &format); - if (ret < 0) - return ret; -@@ -1036,7 +1213,7 @@ static int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi, - /* - * Get sensor bounds first - */ -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection, -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_selection, - NULL, &bounds); - if (!ret) - *r = bounds.r; -@@ -1217,7 +1394,7 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, - - fse.code = sd_fmt->mbus_code; - -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size, -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_size, - NULL, &fse); - if (ret) - return ret; -@@ -1234,7 +1411,7 @@ static int dcmi_g_parm(struct file *file, void *priv, - { - struct stm32_dcmi *dcmi = video_drvdata(file); - -- return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); -+ return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.source, p); - } - - static int dcmi_s_parm(struct file *file, void *priv, -@@ -1242,7 +1419,7 @@ static int dcmi_s_parm(struct file *file, void *priv, - { - struct stm32_dcmi *dcmi = video_drvdata(file); - -- return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); -+ return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.source, p); - } - - static int dcmi_enum_frameintervals(struct file *file, void *fh, -@@ -1264,7 +1441,7 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh, - - fie.code = sd_fmt->mbus_code; - -- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, -+ ret = v4l2_subdev_call(dcmi->entity.source, pad, - enum_frame_interval, NULL, &fie); - if (ret) - return ret; -@@ -1284,7 +1461,7 @@ MODULE_DEVICE_TABLE(of, stm32_dcmi_of_match); - static int dcmi_open(struct file *file) - { - struct stm32_dcmi *dcmi = video_drvdata(file); -- struct v4l2_subdev *sd = dcmi->entity.subdev; -+ struct v4l2_subdev *sd = dcmi->entity.source; - int ret; - - if (mutex_lock_interruptible(&dcmi->lock)) -@@ -1315,7 +1492,7 @@ static int dcmi_open(struct file *file) - static int dcmi_release(struct file *file) - { - struct stm32_dcmi *dcmi = video_drvdata(file); -- struct v4l2_subdev *sd = dcmi->entity.subdev; -+ struct v4l2_subdev *sd = dcmi->entity.source; - bool fh_singular; - int ret; - -@@ -1402,6 +1579,12 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) - return 0; - } - -+/* -+ * FIXME: For the time being we only support subdevices -+ * which expose RGB & YUV "parallel form" mbus code (_2X8). -+ * Nevertheless, this allows to support serial source subdevices -+ * and serial to parallel bridges which conform to this. -+ */ - static const struct dcmi_format dcmi_formats[] = { - { - .fourcc = V4L2_PIX_FMT_RGB565, -@@ -1426,7 +1609,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) - { - const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)]; - unsigned int num_fmts = 0, i, j; -- struct v4l2_subdev *subdev = dcmi->entity.subdev; -+ struct v4l2_subdev *subdev = dcmi->entity.source; - struct v4l2_subdev_mbus_code_enum mbus_code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; -@@ -1440,12 +1623,20 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) - /* Code supported, have we got this fourcc yet? */ - for (j = 0; j < num_fmts; j++) - if (sd_fmts[j]->fourcc == -- dcmi_formats[i].fourcc) -+ dcmi_formats[i].fourcc) { - /* Already available */ -+ dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n", -+ (char *)&sd_fmts[j]->fourcc, -+ mbus_code.code); - break; -- if (j == num_fmts) -+ } -+ if (j == num_fmts) { - /* New */ - sd_fmts[num_fmts++] = dcmi_formats + i; -+ dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n", -+ (char *)&sd_fmts[num_fmts - 1]->fourcc, -+ sd_fmts[num_fmts - 1]->mbus_code); -+ } - } - mbus_code.index++; - } -@@ -1472,7 +1663,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) - static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) - { - unsigned int num_fsize = 0; -- struct v4l2_subdev *subdev = dcmi->entity.subdev; -+ struct v4l2_subdev *subdev = dcmi->entity.source; - struct v4l2_subdev_frame_size_enum fse = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .code = dcmi->sd_format->mbus_code, -@@ -1519,7 +1710,20 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) - struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); - int ret; - -- dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler; -+ /* -+ * Now that the graph is complete, -+ * we search for the source subdevice -+ * in order to expose it through V4L2 interface -+ */ -+ dcmi->entity.source = -+ media_entity_to_v4l2_subdev(dcmi_find_source(dcmi)); -+ if (!dcmi->entity.source) { -+ dev_err(dcmi->dev, "Source subdevice not found\n"); -+ return -ENODEV; -+ } -+ -+ dcmi->vdev->ctrl_handler = dcmi->entity.source->ctrl_handler; -+ - ret = dcmi_formats_init(dcmi); - if (ret) { - dev_err(dcmi->dev, "No supported mediabus format found\n"); -@@ -1544,14 +1748,6 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) - return ret; - } - -- ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); -- if (ret) { -- dev_err(dcmi->dev, "Failed to register video device\n"); -- return ret; -- } -- -- dev_dbg(dcmi->dev, "Device registered as %s\n", -- video_device_node_name(dcmi->vdev)); - return 0; - } - -@@ -1572,12 +1768,31 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, - struct v4l2_async_subdev *asd) - { - struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); -+ unsigned int ret; -+ int src_pad; - -- dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name); -+ dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); - -- dcmi->entity.subdev = subdev; -+ /* -+ * Link this sub-device to DCMI, it could be -+ * a parallel camera sensor or a bridge -+ */ -+ src_pad = media_entity_get_fwnode_pad(&subdev->entity, -+ subdev->fwnode, -+ MEDIA_PAD_FL_SOURCE); -+ -+ ret = media_create_pad_link(&subdev->entity, src_pad, -+ &dcmi->vdev->entity, 0, -+ MEDIA_LNK_FL_IMMUTABLE | -+ MEDIA_LNK_FL_ENABLED); -+ if (ret) -+ dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", -+ subdev->name); -+ else -+ dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", -+ subdev->name); - -- return 0; -+ return ret; - } - - static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { -@@ -1601,7 +1816,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node) - return -EINVAL; - - /* Remote node to connect */ -- dcmi->entity.node = remote; -+ dcmi->entity.remote_node = remote; - dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - dcmi->entity.asd.match.fwnode = of_fwnode_handle(remote); - return 0; -@@ -1622,7 +1837,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) - /* Register the subdevices notifier. */ - subdevs = devm_kzalloc(dcmi->dev, sizeof(*subdevs), GFP_KERNEL); - if (!subdevs) { -- of_node_put(dcmi->entity.node); -+ of_node_put(dcmi->entity.remote_node); - return -ENOMEM; - } - -@@ -1635,7 +1850,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) - ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); - if (ret < 0) { - dev_err(dcmi->dev, "Notifier registration failed\n"); -- of_node_put(dcmi->entity.node); -+ of_node_put(dcmi->entity.remote_node); - return ret; - } - -@@ -1746,10 +1961,19 @@ static int dcmi_probe(struct platform_device *pdev) - - q = &dcmi->queue; - -+ dcmi->v4l2_dev.mdev = &dcmi->mdev; -+ -+ /* Initialize media device */ -+ strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); -+ snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), -+ "platform:%s", DRV_NAME); -+ dcmi->mdev.dev = &pdev->dev; -+ media_device_init(&dcmi->mdev); -+ - /* Initialize the top-level structure */ - ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev); - if (ret) -- goto err_dma_release; -+ goto err_media_device_cleanup; - - dcmi->vdev = video_device_alloc(); - if (!dcmi->vdev) { -@@ -1769,6 +1993,25 @@ static int dcmi_probe(struct platform_device *pdev) - V4L2_CAP_READWRITE; - video_set_drvdata(dcmi->vdev, dcmi); - -+ /* Media entity pads */ -+ dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; -+ ret = media_entity_pads_init(&dcmi->vdev->entity, -+ 1, &dcmi->vid_cap_pad); -+ if (ret) { -+ dev_err(dcmi->dev, "Failed to init media entity pad\n"); -+ goto err_device_release; -+ } -+ dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; -+ -+ ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); -+ if (ret) { -+ dev_err(dcmi->dev, "Failed to register video device\n"); -+ goto err_media_entity_cleanup; -+ } -+ -+ dev_dbg(dcmi->dev, "Device registered as %s\n", -+ video_device_node_name(dcmi->vdev)); -+ - /* Buffer queue */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; -@@ -1784,12 +2027,12 @@ static int dcmi_probe(struct platform_device *pdev) - ret = vb2_queue_init(q); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to initialize vb2 queue\n"); -- goto err_device_release; -+ goto err_media_entity_cleanup; - } - - ret = dcmi_graph_init(dcmi); - if (ret < 0) -- goto err_device_release; -+ goto err_media_entity_cleanup; - - /* Reset device */ - ret = reset_control_assert(dcmi->rstc); -@@ -1814,11 +2057,14 @@ static int dcmi_probe(struct platform_device *pdev) - - return 0; - -+err_media_entity_cleanup: -+ media_entity_cleanup(&dcmi->vdev->entity); - err_device_release: - video_device_release(dcmi->vdev); - err_device_unregister: - v4l2_device_unregister(&dcmi->v4l2_dev); --err_dma_release: -+err_media_device_cleanup: -+ media_device_cleanup(&dcmi->mdev); - dma_release_channel(dcmi->dma_chan); - - return ret; -@@ -1831,7 +2077,9 @@ static int dcmi_remove(struct platform_device *pdev) - pm_runtime_disable(&pdev->dev); - - v4l2_async_notifier_unregister(&dcmi->notifier); -+ media_entity_cleanup(&dcmi->vdev->entity); - v4l2_device_unregister(&dcmi->v4l2_dev); -+ media_device_cleanup(&dcmi->mdev); - - dma_release_channel(dcmi->dma_chan); - -diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c -index fecccb5..89a7839 100644 ---- a/drivers/media/usb/uvc/uvc_queue.c -+++ b/drivers/media/usb/uvc/uvc_queue.c -@@ -224,7 +224,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int ret; - - queue->queue.type = type; -- queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; -+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - queue->queue.drv_priv = queue; - queue->queue.buf_struct_size = sizeof(struct uvc_buffer); - queue->queue.mem_ops = &vb2_vmalloc_memops; -@@ -357,6 +357,19 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type) - return ret; - } - -+ssize_t uvc_queue_read(struct uvc_video_queue *queue, struct file *file, -+ char __user *buf, size_t count, loff_t *ppos) -+{ -+ ssize_t ret; -+ -+ mutex_lock(&queue->mutex); -+ ret = vb2_read(&queue->queue, buf, count, ppos, -+ file->f_flags & O_NONBLOCK); -+ mutex_unlock(&queue->mutex); -+ -+ return ret; -+} -+ - int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) - { - return vb2_mmap(&queue->queue, vma); -diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c -index 18a7384..242d886 100644 ---- a/drivers/media/usb/uvc/uvc_v4l2.c -+++ b/drivers/media/usb/uvc/uvc_v4l2.c -@@ -594,7 +594,8 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, - strlcpy(cap->driver, "uvcvideo", sizeof(cap->driver)); - strlcpy(cap->card, vdev->name, sizeof(cap->card)); - usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); -- cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING -+ cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | -+ V4L2_CAP_READWRITE - | chain->caps; - - return 0; -@@ -1433,8 +1434,12 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, - static ssize_t uvc_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) - { -- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n"); -- return -EINVAL; -+ struct uvc_fh *handle = file->private_data; -+ struct uvc_streaming *stream = handle->stream; -+ -+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read\n"); -+ -+ return uvc_queue_read(&stream->queue, file, data, count, ppos); - } - - static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h -index a738486..a7e843a 100644 ---- a/drivers/media/usb/uvc/uvcvideo.h -+++ b/drivers/media/usb/uvc/uvcvideo.h -@@ -704,6 +704,8 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); - void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); - struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf); -+ssize_t uvc_queue_read(struct uvc_video_queue *queue, struct file *file, -+ char __user *buf, size_t count, loff_t *ppos); - int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); - __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 169bdbb..505338e 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -158,6 +158,9 @@ static void v4l2_fwnode_endpoint_parse_parallel_bus( - flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH : - V4L2_MBUS_DATA_ENABLE_LOW; - -+ if (!fwnode_property_read_u32(fwnode, "pclk-max-frequency", &v)) -+ bus->pclk_max_frequency = v; -+ - bus->flags = flags; - - } -diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h -index d6a5a3b..2a6b253 100644 ---- a/include/uapi/linux/media-bus-format.h -+++ b/include/uapi/linux/media-bus-format.h -@@ -34,7 +34,7 @@ - - #define MEDIA_BUS_FMT_FIXED 0x0001 - --/* RGB - next is 0x101b */ -+/* RGB - next is 0x101c */ - #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 - #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 - #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 -@@ -50,6 +50,7 @@ - #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 - #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 - #define MEDIA_BUS_FMT_BGR888_1X24 0x1013 -+#define MEDIA_BUS_FMT_BGR888_3X8 0x101b - #define MEDIA_BUS_FMT_GBR888_1X24 0x1014 - #define MEDIA_BUS_FMT_RGB888_1X24 0x100a - #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch deleted file mode 100644 index 84e0ea9..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch +++ /dev/null @@ -1,1792 +0,0 @@ -From f37dea894c9913b5d35a7dc0258fddb735d1b007 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:42 +0100 -Subject: [PATCH 14/31] ARM stm32mp1 r3 MFD - ---- - drivers/mfd/Kconfig | 34 +++ - drivers/mfd/Makefile | 4 +- - drivers/mfd/stm32-pwr.c | 400 +++++++++++++++++++++++++ - drivers/mfd/stmfx.c | 545 +++++++++++++++++++++++++++++++++++ - drivers/mfd/stpmic1.c | 219 ++++++++++++++ - drivers/mfd/syscon.c | 19 ++ - drivers/mfd/wm8994-core.c | 21 ++ - include/dt-bindings/mfd/st,stpmic1.h | 50 ++++ - include/linux/mfd/stmfx.h | 123 ++++++++ - include/linux/mfd/stpmic1.h | 212 ++++++++++++++ - include/linux/mfd/wm8994/pdata.h | 6 + - 11 files changed, 1632 insertions(+), 1 deletion(-) - create mode 100644 drivers/mfd/stm32-pwr.c - create mode 100644 drivers/mfd/stmfx.c - create mode 100644 drivers/mfd/stpmic1.c - create mode 100644 include/dt-bindings/mfd/st,stpmic1.h - create mode 100644 include/linux/mfd/stmfx.h - create mode 100644 include/linux/mfd/stpmic1.h - -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index dd938a5..2930188 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -1855,6 +1855,40 @@ config MFD_STM32_TIMERS - for PWM and IIO Timer. This driver allow to share the - registers between the others drivers. - -+config MFD_STM32MP1_PWR -+ bool "STM32MP1 wake-up pins" -+ depends on MACH_STM32MP157 -+ default y -+ -+config MFD_STMFX -+ tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)" -+ depends on I2C -+ depends on OF || COMPILE_TEST -+ select MFD_CORE -+ select REGMAP_I2C -+ help -+ Support for the STMicroelectronics Multi-Function eXpander. -+ -+ This driver provides common support for accessing the device, -+ additional drivers must be enabled in order to use the functionality -+ of the device. -+ -+config MFD_STPMIC1 -+ tristate "Support for STPMIC1 PMIC" -+ depends on (I2C=y && OF) -+ select REGMAP_I2C -+ select REGMAP_IRQ -+ select MFD_CORE -+ help -+ Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on -+ key, watchdog and regulator functionalities which are supported via -+ the relevant subsystems. This driver provides core support for the -+ STPMIC1. In order to use the actual functionaltiy of the device other -+ drivers must be enabled. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called stpmic1. -+ - menu "Multimedia Capabilities Port drivers" - depends on ARCH_SA1100 - -diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 5856a94..d794a2d 100644 ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -232,12 +232,14 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o - obj-$(CONFIG_MFD_MT6397) += mt6397-core.o - - obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o -+obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o - obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o - - obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o - obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o -+obj-$(CONFIG_MFD_STM32MP1_PWR) += stm32-pwr.o - obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o - obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o - obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o - obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o -- -+obj-$(CONFIG_MFD_STMFX) += stmfx.o -diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c -new file mode 100644 -index 0000000..92744bf ---- /dev/null -+++ b/drivers/mfd/stm32-pwr.c -@@ -0,0 +1,400 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved -+ * Author: Pascal Paillet for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define NB_WAKEUPPINS 6 -+ -+#define STM32_SVC_PWR 0x82001001 -+#define STM32_WRITE 0x1 -+#define STM32_SET_BITS 0x2 -+#define STM32_CLEAR_BITS 0x3 -+ -+#define SMC_PWR_BASE 0x50001000 -+// PWR Registers -+#define WKUPCR 0x20 -+#define WKUPFR 0x24 -+#define MPUWKUPENR 0x28 -+ -+#define WKUP_FLAGS_MASK GENMASK(5, 0) -+ -+// WKUPCR bits definition -+#define WKUP_EDGE_SHIFT 8 -+#define WKUP_PULL_SHIFT 16 -+#define WKUP_PULL_MASK GENMASK(1, 0) -+ -+enum wkup_pull_setting { -+ WKUP_NO_PULL = 0, -+ WKUP_PULL_UP, -+ WKUP_PULL_DOWN, -+ WKUP_PULL_RESERVED -+}; -+ -+#define SMC(class, op, offset, val) do { \ -+ struct arm_smccc_res res; \ -+ arm_smccc_smc(class, op, SMC_PWR_BASE + (offset), val, \ -+ 0, 0, 0, 0, &res); \ -+} while (0) \ -+ -+struct stm32_pwr_data { -+ struct device *dev; -+ void __iomem *base; /* IO Memory base address */ -+ struct irq_domain *domain; /* Domain for this controller */ -+ int irq; /* Parent interrupt */ -+ u32 masked; /* IRQ is masked */ -+ u32 wake; /* IRQ is wake on */ -+ u32 pending; /* IRQ has been received while wake on*/ -+ struct gpio_desc *gpio[NB_WAKEUPPINS]; -+}; -+ -+static void stm32_pwr_irq_ack(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq)); -+} -+ -+static void stm32_pwr_irq_set_enable(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ if (!(priv->masked & BIT(d->hwirq)) || (priv->wake & BIT(d->hwirq))) -+ SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq)); -+ else -+ SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq)); -+} -+ -+static void stm32_pwr_irq_mask(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ priv->masked |= BIT(d->hwirq); -+ stm32_pwr_irq_set_enable(d); -+} -+ -+static void stm32_pwr_irq_unmask(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ priv->masked &= ~BIT(d->hwirq); -+ stm32_pwr_irq_set_enable(d); -+} -+ -+static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ struct irq_data *parent = irq_get_irq_data(priv->irq); -+ -+ dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on); -+ if (on) { -+ priv->wake |= BIT(d->hwirq); -+ } else { -+ priv->wake &= ~BIT(d->hwirq); -+ priv->pending &= ~BIT(d->hwirq); -+ } -+ stm32_pwr_irq_set_enable(d); -+ -+ if (parent->chip && parent->chip->irq_set_wake) -+ return parent->chip->irq_set_wake(parent, on); -+ -+ return 0; -+} -+ -+static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ int pin_id = d->hwirq; -+ u32 wkupcr; -+ int en; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ -+ en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id); -+ /* reference manual request to disable the wakeup pin while -+ * changing the edge detection setting -+ */ -+ if (en) -+ stm32_pwr_irq_mask(d); -+ -+ wkupcr = readl_relaxed(priv->base + WKUPCR); -+ switch (flow_type & IRQ_TYPE_SENSE_MASK) { -+ case IRQF_TRIGGER_FALLING: -+ wkupcr |= (1 << (WKUP_EDGE_SHIFT + pin_id)); -+ break; -+ case IRQF_TRIGGER_RISING: -+ wkupcr &= ~(1 << (WKUP_EDGE_SHIFT + pin_id)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); -+ -+ if (en) -+ stm32_pwr_irq_unmask(d); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_SMP -+static int stm32_pwr_set_affinity_parent(struct irq_data *data, -+ const struct cpumask *dest, bool force) -+{ -+ struct stm32_pwr_data *priv = data->domain->host_data; -+ struct irq_data *parent = irq_get_irq_data(priv->irq); -+ -+ if (parent->chip && parent->chip->irq_set_affinity) -+ return parent->chip->irq_set_affinity(parent, dest, force); -+ -+ return IRQ_SET_MASK_OK_DONE; -+} -+#endif -+ -+static int stm32_pwr_irq_request_resources(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ struct gpio_desc *gpio; -+ int ret; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ gpio = gpiod_get_index(priv->dev, "wakeup", d->hwirq, GPIOD_IN); -+ if (IS_ERR(gpio)) { -+ ret = PTR_ERR(gpio); -+ dev_err(priv->dev, "Failed to get wakeup gpio: %d", ret); -+ return ret; -+ } -+ priv->gpio[d->hwirq] = gpio; -+ return 0; -+} -+ -+static void stm32_pwr_irq_release_resources(struct irq_data *d) -+{ -+ struct stm32_pwr_data *priv = d->domain->host_data; -+ -+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ gpiod_put(priv->gpio[d->hwirq]); -+} -+ -+static struct irq_chip stm32_pwr_irq_chip = { -+ .name = "stm32-pwr-irq", -+ .irq_ack = stm32_pwr_irq_ack, -+ .irq_mask = stm32_pwr_irq_mask, -+ .irq_unmask = stm32_pwr_irq_unmask, -+ .irq_set_type = stm32_pwr_irq_set_type, -+ .irq_set_wake = stm32_pwr_irq_set_wake, -+ .irq_request_resources = stm32_pwr_irq_request_resources, -+ .irq_release_resources = stm32_pwr_irq_release_resources, -+#ifdef CONFIG_SMP -+ .irq_set_affinity = stm32_pwr_set_affinity_parent, -+#endif -+}; -+ -+static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id, -+ enum wkup_pull_setting config) -+{ -+ struct stm32_pwr_data *priv = d->host_data; -+ u32 wkupcr; -+ -+ dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config); -+ -+ if (config >= WKUP_PULL_RESERVED) { -+ pr_err("%s: bad irq pull config\n", __func__); -+ return -EINVAL; -+ } -+ -+ wkupcr = readl_relaxed(priv->base + WKUPCR); -+ wkupcr &= ~((WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2)); -+ wkupcr |= (config & WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2); -+ -+ SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); -+ -+ return 0; -+} -+ -+static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr, -+ const u32 *intspec, unsigned int intsize, -+ irq_hw_number_t *out_hwirq, unsigned int *out_type) -+{ -+ if (WARN_ON(intsize < 3)) { -+ pr_err("%s: bad irq config parameters\n", __func__); -+ return -EINVAL; -+ } -+ -+ *out_hwirq = intspec[0]; -+ *out_type = intspec[1] & (IRQ_TYPE_SENSE_MASK); -+ -+ return stm32_pwr_irq_set_pull_config(d, intspec[0], intspec[2]); -+} -+ -+static int stm32_pwr_alloc(struct irq_domain *d, unsigned int virq, -+ unsigned int nr_irqs, void *data) -+{ -+ struct irq_fwspec *fwspec = data; -+ irq_hw_number_t hwirq; -+ -+ hwirq = fwspec->param[0]; -+ irq_domain_set_info(d, virq, hwirq, &stm32_pwr_irq_chip, d->host_data, -+ handle_edge_irq, NULL, NULL); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops stm32_pwr_irq_domain_ops = { -+ .alloc = stm32_pwr_alloc, -+ .xlate = stm32_pwr_xlate, -+ .free = irq_domain_free_irqs_common, -+}; -+ -+/* -+ * Handler for the cascaded IRQ. -+ */ -+static void stm32_pwr_handle_irq(struct irq_desc *desc) -+{ -+ struct stm32_pwr_data *priv = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ u32 wkupfr, wkupenr, i; -+ -+ chained_irq_enter(chip, desc); -+ -+ wkupfr = readl_relaxed(priv->base + WKUPFR); -+ wkupenr = readl_relaxed(priv->base + MPUWKUPENR); -+ -+ for (i = 0; i < NB_WAKEUPPINS; i++) { -+ if ((wkupfr & BIT(i)) && (wkupenr & BIT(i))) { -+ struct irq_desc *d; -+ -+ d = irq_to_desc(irq_find_mapping(priv->domain, i)); -+ -+ if (priv->wake & BIT(i)) { -+ dev_dbg(priv->dev, -+ "irq %d while wake enabled\n", i); -+ priv->pending |= BIT(i); -+ } -+ -+ dev_dbg(priv->dev, "handle wkup irq:%d\n", i); -+ handle_edge_irq(d); -+ } -+ } -+ chained_irq_exit(chip, desc); -+} -+ -+static int __maybe_unused stm32_pwr_suspend(struct device *dev) -+{ -+ struct stm32_pwr_data *priv = dev_get_drvdata(dev); -+ -+ dev_dbg(priv->dev, "suspend"); -+ if (priv->pending != 0) -+ return -EBUSY; -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops stm32_pwr_pm = { -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pwr_suspend, NULL) -+}; -+ -+static int stm32_pwr_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct stm32_pwr_data *priv; -+ struct device_node *np = dev->of_node; -+ struct resource *res; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ priv->dev = dev; -+ dev_set_drvdata(dev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->base)) { -+ dev_err(dev, "Unable to map registers\n"); -+ return PTR_ERR(priv->base); -+ } -+ -+ /* Disable all wake-up pins */ -+ SMC(STM32_SVC_PWR, STM32_WRITE, MPUWKUPENR, 0); -+ /* Clear all interrupts flags */ -+ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, WKUP_FLAGS_MASK); -+ -+ priv->domain = irq_domain_add_linear(np, NB_WAKEUPPINS, -+ &stm32_pwr_irq_domain_ops, priv); -+ if (!priv->domain) { -+ dev_err(dev, "%s: Unable to add irq domain!\n", __func__); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = irq_of_parse_and_map(np, 0); -+ if (ret < 0) { -+ dev_err(dev, "failed to get PWR IRQ\n"); -+ ret = priv->irq; -+ goto out_domain; -+ } -+ -+ priv->irq = ret; -+ irq_set_chained_handler_and_data(priv->irq, stm32_pwr_handle_irq, priv); -+ -+ of_node_clear_flag(np, OF_POPULATED); -+ -+ return 0; -+ -+out_domain: -+ irq_domain_remove(priv->domain); -+out: -+ return ret; -+} -+ -+static int stm32_pwr_remove(struct platform_device *pdev) -+{ -+ struct stm32_pwr_data *priv = dev_get_drvdata(&pdev->dev); -+ -+ irq_domain_remove(priv->domain); -+ return 0; -+} -+ -+static const struct of_device_id stm32_pwr_ids[] = { -+ { .compatible = "st,stm32mp1-pwr", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_pwr_ids); -+ -+static struct platform_driver stm32_pwr_driver = { -+ .probe = stm32_pwr_probe, -+ .remove = stm32_pwr_remove, -+ .driver = { -+ .name = "stm32_pwr", -+ .of_match_table = stm32_pwr_ids, -+ .pm = &stm32_pwr_pm, -+ }, -+}; -+ -+static int __init stm32_pwr_init(void) -+{ -+ return platform_driver_register(&stm32_pwr_driver); -+} -+ -+static void __exit stm32_pwr_exit(void) -+{ -+ return platform_driver_unregister(&stm32_pwr_driver); -+} -+ -+arch_initcall(stm32_pwr_init); -+module_exit(stm32_pwr_exit); -diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c -new file mode 100644 -index 0000000..857991c ---- /dev/null -+++ b/drivers/mfd/stmfx.c -@@ -0,0 +1,545 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Driver for STMicroelectronics Multi-Function eXpander (STMFX) core -+ * -+ * Copyright (C) 2019 STMicroelectronics -+ * Author(s): Amelie Delaunay . -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static bool stmfx_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case STMFX_REG_SYS_CTRL: -+ case STMFX_REG_IRQ_SRC_EN: -+ case STMFX_REG_IRQ_PENDING: -+ case STMFX_REG_IRQ_GPI_PENDING1: -+ case STMFX_REG_IRQ_GPI_PENDING2: -+ case STMFX_REG_IRQ_GPI_PENDING3: -+ case STMFX_REG_GPIO_STATE1: -+ case STMFX_REG_GPIO_STATE2: -+ case STMFX_REG_GPIO_STATE3: -+ case STMFX_REG_IRQ_GPI_SRC1: -+ case STMFX_REG_IRQ_GPI_SRC2: -+ case STMFX_REG_IRQ_GPI_SRC3: -+ case STMFX_REG_GPO_SET1: -+ case STMFX_REG_GPO_SET2: -+ case STMFX_REG_GPO_SET3: -+ case STMFX_REG_GPO_CLR1: -+ case STMFX_REG_GPO_CLR2: -+ case STMFX_REG_GPO_CLR3: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool stmfx_reg_writeable(struct device *dev, unsigned int reg) -+{ -+ return (reg >= STMFX_REG_SYS_CTRL); -+} -+ -+static const struct regmap_config stmfx_regmap_config = { -+ .reg_bits = 8, -+ .reg_stride = 1, -+ .val_bits = 8, -+ .max_register = STMFX_REG_MAX, -+ .volatile_reg = stmfx_reg_volatile, -+ .writeable_reg = stmfx_reg_writeable, -+ .cache_type = REGCACHE_RBTREE, -+}; -+ -+static const struct resource stmfx_pinctrl_resources[] = { -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO), -+}; -+ -+static const struct resource stmfx_idd_resources[] = { -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_IDD), -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_ERROR), -+}; -+ -+static const struct resource stmfx_ts_resources[] = { -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_DET), -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_NE), -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_TH), -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_FULL), -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_OVF), -+}; -+ -+static struct mfd_cell stmfx_cells[] = { -+ { -+ .of_compatible = "st,stmfx-0300-pinctrl", -+ .name = "stmfx-pinctrl", -+ .resources = stmfx_pinctrl_resources, -+ .num_resources = ARRAY_SIZE(stmfx_pinctrl_resources), -+ }, -+ { -+ .of_compatible = "st,stmfx-0300-idd", -+ .name = "stmfx-idd", -+ .resources = stmfx_idd_resources, -+ .num_resources = ARRAY_SIZE(stmfx_idd_resources), -+ }, -+ { -+ .of_compatible = "st,stmfx-0300-ts", -+ .name = "stmfx-ts", -+ .resources = stmfx_ts_resources, -+ .num_resources = ARRAY_SIZE(stmfx_ts_resources), -+ }, -+}; -+ -+static u8 stmfx_func_to_mask(u32 func) -+{ -+ u8 mask = 0; -+ -+ if (func & STMFX_FUNC_GPIO) -+ mask |= STMFX_REG_SYS_CTRL_GPIO_EN; -+ -+ if ((func & STMFX_FUNC_ALTGPIO_LOW) || (func & STMFX_FUNC_ALTGPIO_HIGH)) -+ mask |= STMFX_REG_SYS_CTRL_ALTGPIO_EN; -+ -+ if (func & STMFX_FUNC_TS) -+ mask |= STMFX_REG_SYS_CTRL_TS_EN; -+ -+ if (func & STMFX_FUNC_IDD) -+ mask |= STMFX_REG_SYS_CTRL_IDD_EN; -+ -+ return mask; -+} -+ -+int stmfx_function_enable(struct stmfx *stmfx, u32 func) -+{ -+ u32 sys_ctrl; -+ u8 mask; -+ int ret; -+ -+ ret = regmap_read(stmfx->map, STMFX_REG_SYS_CTRL, &sys_ctrl); -+ if (ret) -+ return ret; -+ -+ /* -+ * IDD and TS have priority in STMFX FW, so if IDD and TS are enabled, -+ * ALTGPIO function is disabled by STMFX FW. If IDD or TS is enabled, -+ * the number of aGPIO available decreases. To avoid GPIO management -+ * disturbance, abort IDD or TS function enable in this case. -+ */ -+ if (((func & STMFX_FUNC_IDD) || (func & STMFX_FUNC_TS)) && -+ (sys_ctrl & STMFX_REG_SYS_CTRL_ALTGPIO_EN)) { -+ dev_err(stmfx->dev, "ALTGPIO function already enabled\n"); -+ return -EBUSY; -+ } -+ -+ /* If TS is enabled, aGPIO[3:0] cannot be used */ -+ if ((func & STMFX_FUNC_ALTGPIO_LOW) && -+ (sys_ctrl & STMFX_REG_SYS_CTRL_TS_EN)) { -+ dev_err(stmfx->dev, "TS in use, aGPIO[3:0] unavailable\n"); -+ return -EBUSY; -+ } -+ -+ /* If IDD is enabled, aGPIO[7:4] cannot be used */ -+ if ((func & STMFX_FUNC_ALTGPIO_HIGH) && -+ (sys_ctrl & STMFX_REG_SYS_CTRL_IDD_EN)) { -+ dev_err(stmfx->dev, "IDD in use, aGPIO[7:4] unavailable\n"); -+ return -EBUSY; -+ } -+ -+ mask = stmfx_func_to_mask(func); -+ -+ return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, mask); -+} -+EXPORT_SYMBOL_GPL(stmfx_function_enable); -+ -+int stmfx_function_disable(struct stmfx *stmfx, u32 func) -+{ -+ u8 mask = stmfx_func_to_mask(func); -+ -+ return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, 0); -+} -+EXPORT_SYMBOL_GPL(stmfx_function_disable); -+ -+static void stmfx_irq_bus_lock(struct irq_data *data) -+{ -+ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); -+ -+ mutex_lock(&stmfx->lock); -+} -+ -+static void stmfx_irq_bus_sync_unlock(struct irq_data *data) -+{ -+ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); -+ -+ regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, stmfx->irq_src); -+ -+ mutex_unlock(&stmfx->lock); -+} -+ -+static void stmfx_irq_mask(struct irq_data *data) -+{ -+ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); -+ -+ stmfx->irq_src &= ~BIT(data->hwirq % 8); -+} -+ -+static void stmfx_irq_unmask(struct irq_data *data) -+{ -+ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); -+ -+ stmfx->irq_src |= BIT(data->hwirq % 8); -+} -+ -+static struct irq_chip stmfx_irq_chip = { -+ .name = "stmfx-core", -+ .irq_bus_lock = stmfx_irq_bus_lock, -+ .irq_bus_sync_unlock = stmfx_irq_bus_sync_unlock, -+ .irq_mask = stmfx_irq_mask, -+ .irq_unmask = stmfx_irq_unmask, -+}; -+ -+static irqreturn_t stmfx_irq_handler(int irq, void *data) -+{ -+ struct stmfx *stmfx = data; -+ unsigned long bits; -+ u32 pending, ack; -+ int n, ret; -+ -+ ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending); -+ if (ret) -+ return IRQ_NONE; -+ -+ /* -+ * There is no ACK for GPIO, MFX_REG_IRQ_PENDING_GPIO is a logical OR -+ * of MFX_REG_IRQ_GPI _PENDING1/_PENDING2/_PENDING3 -+ */ -+ ack = pending & ~BIT(STMFX_REG_IRQ_SRC_EN_GPIO); -+ if (ack) { -+ ret = regmap_write(stmfx->map, STMFX_REG_IRQ_ACK, ack); -+ if (ret) -+ return IRQ_NONE; -+ } -+ -+ bits = pending; -+ for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX) -+ handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n)); -+ -+ return IRQ_HANDLED; -+} -+ -+static int stmfx_irq_map(struct irq_domain *d, unsigned int virq, -+ irq_hw_number_t hwirq) -+{ -+ irq_set_chip_data(virq, d->host_data); -+ irq_set_chip_and_handler(virq, &stmfx_irq_chip, handle_simple_irq); -+ irq_set_nested_thread(virq, 1); -+ irq_set_noprobe(virq); -+ -+ return 0; -+} -+ -+static void stmfx_irq_unmap(struct irq_domain *d, unsigned int virq) -+{ -+ irq_set_chip_and_handler(virq, NULL, NULL); -+ irq_set_chip_data(virq, NULL); -+} -+ -+static const struct irq_domain_ops stmfx_irq_ops = { -+ .map = stmfx_irq_map, -+ .unmap = stmfx_irq_unmap, -+}; -+ -+static void stmfx_irq_exit(struct i2c_client *client) -+{ -+ struct stmfx *stmfx = i2c_get_clientdata(client); -+ int hwirq; -+ -+ for (hwirq = 0; hwirq < STMFX_REG_IRQ_SRC_MAX; hwirq++) -+ irq_dispose_mapping(irq_find_mapping(stmfx->irq_domain, hwirq)); -+ -+ irq_domain_remove(stmfx->irq_domain); -+} -+ -+static int stmfx_irq_init(struct i2c_client *client) -+{ -+ struct stmfx *stmfx = i2c_get_clientdata(client); -+ u32 irqoutpin = 0, irqtrigger; -+ int ret; -+ -+ stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node, -+ STMFX_REG_IRQ_SRC_MAX, 0, -+ &stmfx_irq_ops, stmfx); -+ if (!stmfx->irq_domain) { -+ dev_err(stmfx->dev, "Failed to create IRQ domain\n"); -+ return -EINVAL; -+ } -+ -+ if (!of_property_read_bool(stmfx->dev->of_node, "drive-open-drain")) -+ irqoutpin |= STMFX_REG_IRQ_OUT_PIN_TYPE; -+ -+ irqtrigger = irq_get_trigger_type(client->irq); -+ if ((irqtrigger & IRQ_TYPE_EDGE_RISING) || -+ (irqtrigger & IRQ_TYPE_LEVEL_HIGH)) -+ irqoutpin |= STMFX_REG_IRQ_OUT_PIN_POL; -+ -+ ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); -+ if (ret) -+ return ret; -+ -+ ret = devm_request_threaded_irq(stmfx->dev, client->irq, -+ NULL, stmfx_irq_handler, -+ irqtrigger | IRQF_ONESHOT, -+ "stmfx", stmfx); -+ if (ret) -+ stmfx_irq_exit(client); -+ -+ return ret; -+} -+ -+static int stmfx_chip_reset(struct stmfx *stmfx) -+{ -+ int ret; -+ -+ ret = regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, -+ STMFX_REG_SYS_CTRL_SWRST); -+ if (ret) -+ return ret; -+ -+ msleep(STMFX_BOOT_TIME_MS); -+ -+ return ret; -+} -+ -+static int stmfx_chip_init(struct i2c_client *client) -+{ -+ struct stmfx *stmfx = i2c_get_clientdata(client); -+ u32 id; -+ u8 version[2]; -+ int ret; -+ -+ stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd"); -+ ret = PTR_ERR_OR_ZERO(stmfx->vdd); -+ if (ret == -ENODEV) { -+ stmfx->vdd = NULL; -+ } else if (ret == -EPROBE_DEFER) { -+ return ret; -+ } else if (ret) { -+ dev_err(&client->dev, "Failed to get VDD regulator: %d\n", ret); -+ return ret; -+ } -+ -+ if (stmfx->vdd) { -+ ret = regulator_enable(stmfx->vdd); -+ if (ret) { -+ dev_err(&client->dev, "VDD enable failed: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = regmap_read(stmfx->map, STMFX_REG_CHIP_ID, &id); -+ if (ret) { -+ dev_err(&client->dev, "Error reading chip ID: %d\n", ret); -+ goto err; -+ } -+ -+ /* -+ * 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) != (client->addr << 1)) { -+ dev_err(&client->dev, "Unknown chip ID: %#x\n", id); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ ret = regmap_bulk_read(stmfx->map, STMFX_REG_FW_VERSION_MSB, -+ version, ARRAY_SIZE(version)); -+ if (ret) { -+ dev_err(&client->dev, "Error reading FW version: %d\n", ret); -+ goto err; -+ } -+ -+ dev_info(&client->dev, "STMFX id: %#x, fw version: %x.%02x\n", -+ id, version[0], version[1]); -+ -+ ret = stmfx_chip_reset(stmfx); -+ if (ret) { -+ dev_err(&client->dev, "Failed to reset chip: %d\n", ret); -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ if (stmfx->vdd) -+ return regulator_disable(stmfx->vdd); -+ -+ return ret; -+} -+ -+static int stmfx_chip_exit(struct i2c_client *client) -+{ -+ struct stmfx *stmfx = i2c_get_clientdata(client); -+ -+ regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0); -+ regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0); -+ -+ if (stmfx->vdd) -+ return regulator_disable(stmfx->vdd); -+ -+ return 0; -+} -+ -+static int stmfx_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct device *dev = &client->dev; -+ struct stmfx *stmfx; -+ int ret; -+ -+ stmfx = devm_kzalloc(dev, sizeof(*stmfx), GFP_KERNEL); -+ if (!stmfx) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, stmfx); -+ -+ stmfx->dev = dev; -+ -+ stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config); -+ if (IS_ERR(stmfx->map)) { -+ ret = PTR_ERR(stmfx->map); -+ dev_err(dev, "Failed to allocate register map: %d\n", ret); -+ return ret; -+ } -+ -+ mutex_init(&stmfx->lock); -+ -+ ret = stmfx_chip_init(client); -+ if (ret) { -+ if (ret == -ETIMEDOUT) -+ return -EPROBE_DEFER; -+ return ret; -+ } -+ -+ if (client->irq < 0) { -+ dev_err(dev, "Failed to get IRQ: %d\n", client->irq); -+ ret = client->irq; -+ goto err_chip_exit; -+ } -+ -+ ret = stmfx_irq_init(client); -+ if (ret) -+ goto err_chip_exit; -+ -+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, -+ stmfx_cells, ARRAY_SIZE(stmfx_cells), NULL, -+ 0, stmfx->irq_domain); -+ if (ret) -+ goto err_irq_exit; -+ -+ return 0; -+ -+err_irq_exit: -+ stmfx_irq_exit(client); -+err_chip_exit: -+ stmfx_chip_exit(client); -+ -+ return ret; -+} -+ -+static int stmfx_remove(struct i2c_client *client) -+{ -+ stmfx_irq_exit(client); -+ -+ return stmfx_chip_exit(client); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stmfx_suspend(struct device *dev) -+{ -+ struct stmfx *stmfx = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = regmap_raw_read(stmfx->map, STMFX_REG_SYS_CTRL, -+ &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_raw_read(stmfx->map, STMFX_REG_IRQ_OUT_PIN, -+ &stmfx->bkp_irqoutpin, -+ sizeof(stmfx->bkp_irqoutpin)); -+ if (ret) -+ return ret; -+ -+ if (stmfx->vdd) -+ return regulator_disable(stmfx->vdd); -+ -+ return 0; -+} -+ -+static int stmfx_resume(struct device *dev) -+{ -+ struct stmfx *stmfx = dev_get_drvdata(dev); -+ int ret; -+ -+ if (stmfx->vdd) { -+ ret = regulator_enable(stmfx->vdd); -+ if (ret) { -+ dev_err(stmfx->dev, -+ "VDD enable failed: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL, -+ &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, -+ &stmfx->bkp_irqoutpin, -+ sizeof(stmfx->bkp_irqoutpin)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, -+ &stmfx->irq_src, sizeof(stmfx->irq_src)); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stmfx_dev_pm_ops, stmfx_suspend, stmfx_resume); -+ -+static const struct of_device_id stmfx_of_match[] = { -+ { .compatible = "st,stmfx-0300", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stmfx_of_match); -+ -+static struct i2c_driver stmfx_driver = { -+ .driver = { -+ .name = "stmfx-core", -+ .of_match_table = of_match_ptr(stmfx_of_match), -+ .pm = &stmfx_dev_pm_ops, -+ }, -+ .probe = stmfx_probe, -+ .remove = stmfx_remove, -+}; -+module_i2c_driver(stmfx_driver); -+ -+MODULE_DESCRIPTION("STMFX core driver"); -+MODULE_AUTHOR("Amelie Delaunay "); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c -new file mode 100644 -index 0000000..766c321 ---- /dev/null -+++ b/drivers/mfd/stpmic1.c -@@ -0,0 +1,219 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2018 -+// Author: Pascal Paillet -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define STPMIC1_MAIN_IRQ 0 -+ -+static const struct regmap_range stpmic1_readable_ranges[] = { -+ regmap_reg_range(TURN_ON_SR, VERSION_SR), -+ regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), -+ regmap_reg_range(BST_SW_CR, BST_SW_CR), -+ regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), -+ regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), -+ regmap_reg_range(INT_MASK_R1, INT_MASK_R4), -+ regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), -+ regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), -+ regmap_reg_range(INT_SRC_R1, INT_SRC_R1), -+}; -+ -+static const struct regmap_range stpmic1_writeable_ranges[] = { -+ regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), -+ regmap_reg_range(BST_SW_CR, BST_SW_CR), -+ regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), -+ regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), -+ regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), -+}; -+ -+static const struct regmap_range stpmic1_volatile_ranges[] = { -+ regmap_reg_range(TURN_ON_SR, VERSION_SR), -+ regmap_reg_range(WCHDG_CR, WCHDG_CR), -+ regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), -+ regmap_reg_range(INT_SRC_R1, INT_SRC_R4), -+}; -+ -+static const struct regmap_access_table stpmic1_readable_table = { -+ .yes_ranges = stpmic1_readable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(stpmic1_readable_ranges), -+}; -+ -+static const struct regmap_access_table stpmic1_writeable_table = { -+ .yes_ranges = stpmic1_writeable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(stpmic1_writeable_ranges), -+}; -+ -+static const struct regmap_access_table stpmic1_volatile_table = { -+ .yes_ranges = stpmic1_volatile_ranges, -+ .n_yes_ranges = ARRAY_SIZE(stpmic1_volatile_ranges), -+}; -+ -+const struct regmap_config stpmic1_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .cache_type = REGCACHE_RBTREE, -+ .max_register = PMIC_MAX_REGISTER_ADDRESS, -+ .rd_table = &stpmic1_readable_table, -+ .wr_table = &stpmic1_writeable_table, -+ .volatile_table = &stpmic1_volatile_table, -+}; -+ -+static const struct regmap_irq stpmic1_irqs[] = { -+ REGMAP_IRQ_REG(IT_PONKEY_F, 0, 0x01), -+ REGMAP_IRQ_REG(IT_PONKEY_R, 0, 0x02), -+ REGMAP_IRQ_REG(IT_WAKEUP_F, 0, 0x04), -+ REGMAP_IRQ_REG(IT_WAKEUP_R, 0, 0x08), -+ REGMAP_IRQ_REG(IT_VBUS_OTG_F, 0, 0x10), -+ REGMAP_IRQ_REG(IT_VBUS_OTG_R, 0, 0x20), -+ REGMAP_IRQ_REG(IT_SWOUT_F, 0, 0x40), -+ REGMAP_IRQ_REG(IT_SWOUT_R, 0, 0x80), -+ -+ REGMAP_IRQ_REG(IT_CURLIM_BUCK1, 1, 0x01), -+ REGMAP_IRQ_REG(IT_CURLIM_BUCK2, 1, 0x02), -+ REGMAP_IRQ_REG(IT_CURLIM_BUCK3, 1, 0x04), -+ REGMAP_IRQ_REG(IT_CURLIM_BUCK4, 1, 0x08), -+ REGMAP_IRQ_REG(IT_OCP_OTG, 1, 0x10), -+ REGMAP_IRQ_REG(IT_OCP_SWOUT, 1, 0x20), -+ REGMAP_IRQ_REG(IT_OCP_BOOST, 1, 0x40), -+ REGMAP_IRQ_REG(IT_OVP_BOOST, 1, 0x80), -+ -+ REGMAP_IRQ_REG(IT_CURLIM_LDO1, 2, 0x01), -+ REGMAP_IRQ_REG(IT_CURLIM_LDO2, 2, 0x02), -+ REGMAP_IRQ_REG(IT_CURLIM_LDO3, 2, 0x04), -+ REGMAP_IRQ_REG(IT_CURLIM_LDO4, 2, 0x08), -+ REGMAP_IRQ_REG(IT_CURLIM_LDO5, 2, 0x10), -+ REGMAP_IRQ_REG(IT_CURLIM_LDO6, 2, 0x20), -+ REGMAP_IRQ_REG(IT_SHORT_SWOTG, 2, 0x40), -+ REGMAP_IRQ_REG(IT_SHORT_SWOUT, 2, 0x80), -+ -+ REGMAP_IRQ_REG(IT_TWARN_F, 3, 0x01), -+ REGMAP_IRQ_REG(IT_TWARN_R, 3, 0x02), -+ REGMAP_IRQ_REG(IT_VINLOW_F, 3, 0x04), -+ REGMAP_IRQ_REG(IT_VINLOW_R, 3, 0x08), -+ REGMAP_IRQ_REG(IT_SWIN_F, 3, 0x40), -+ REGMAP_IRQ_REG(IT_SWIN_R, 3, 0x80), -+}; -+ -+static const struct regmap_irq_chip stpmic1_regmap_irq_chip = { -+ .name = "pmic_irq", -+ .status_base = INT_PENDING_R1, -+ .mask_base = INT_CLEAR_MASK_R1, -+ .unmask_base = INT_SET_MASK_R1, -+ .ack_base = INT_CLEAR_R1, -+ .num_regs = STPMIC1_PMIC_NUM_IRQ_REGS, -+ .irqs = stpmic1_irqs, -+ .num_irqs = ARRAY_SIZE(stpmic1_irqs), -+}; -+ -+static int stpmic1_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ struct stpmic1 *ddata; -+ struct device *dev = &i2c->dev; -+ int ret; -+ struct device_node *np = dev->of_node; -+ u32 reg; -+ -+ ddata = devm_kzalloc(dev, sizeof(struct stpmic1), GFP_KERNEL); -+ if (!ddata) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(i2c, ddata); -+ ddata->dev = dev; -+ -+ ddata->regmap = devm_regmap_init_i2c(i2c, &stpmic1_regmap_config); -+ if (IS_ERR(ddata->regmap)) -+ return PTR_ERR(ddata->regmap); -+ -+ ddata->irq = of_irq_get(np, STPMIC1_MAIN_IRQ); -+ if (ddata->irq < 0) { -+ dev_err(dev, "Failed to get main IRQ: %d\n", ddata->irq); -+ return ddata->irq; -+ } -+ -+ ret = regmap_read(ddata->regmap, VERSION_SR, ®); -+ if (ret) { -+ dev_err(dev, "Unable to read PMIC version\n"); -+ return ret; -+ } -+ dev_info(dev, "PMIC Chip Version: 0x%x\n", reg); -+ -+ /* Initialize PMIC IRQ Chip & associated IRQ domains */ -+ ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq, -+ IRQF_ONESHOT | IRQF_SHARED, -+ 0, &stpmic1_regmap_irq_chip, -+ &ddata->irq_data); -+ if (ret) { -+ dev_err(dev, "IRQ Chip registration failed: %d\n", ret); -+ return ret; -+ } -+ -+ return devm_of_platform_populate(dev); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stpmic1_suspend(struct device *dev) -+{ -+ struct i2c_client *i2c = to_i2c_client(dev); -+ struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); -+ -+ disable_irq(pmic_dev->irq); -+ -+ if (device_may_wakeup(dev)) -+ enable_irq_wake(pmic_dev->irq); -+ -+ return 0; -+} -+ -+static int stpmic1_resume(struct device *dev) -+{ -+ struct i2c_client *i2c = to_i2c_client(dev); -+ struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); -+ int ret; -+ -+ ret = regcache_sync(pmic_dev->regmap); -+ if (ret) -+ return ret; -+ -+ if (device_may_wakeup(dev)) -+ disable_irq_wake(pmic_dev->irq); -+ -+ enable_irq(pmic_dev->irq); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stpmic1_pm, stpmic1_suspend, stpmic1_resume); -+ -+static const struct of_device_id stpmic1_of_match[] = { -+ { .compatible = "st,stpmic1", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stpmic1_of_match); -+ -+static struct i2c_driver stpmic1_driver = { -+ .driver = { -+ .name = "stpmic1", -+ .of_match_table = of_match_ptr(stpmic1_of_match), -+ .pm = &stpmic1_pm, -+ }, -+ .probe = stpmic1_probe, -+}; -+ -+module_i2c_driver(stpmic1_driver); -+ -+MODULE_DESCRIPTION("STPMIC1 PMIC Driver"); -+MODULE_AUTHOR("Pascal Paillet "); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c -index b6d05cd..a0ba4ff 100644 ---- a/drivers/mfd/syscon.c -+++ b/drivers/mfd/syscon.c -@@ -12,6 +12,7 @@ - * (at your option) any later version. - */ - -+#include - #include - #include - #include -@@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = { - - static struct syscon *of_syscon_register(struct device_node *np) - { -+ struct clk *clk; - struct syscon *syscon; - struct regmap *regmap; - void __iomem *base; -@@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np) - goto err_regmap; - } - -+ clk = of_clk_get(np, 0); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); -+ /* clock is optional */ -+ if (ret != -ENOENT) -+ goto err_clk; -+ } else { -+ ret = regmap_mmio_attach_clk(regmap, clk); -+ if (ret) -+ goto err_attach; -+ } -+ - syscon->regmap = regmap; - syscon->np = np; - -@@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np) - - return syscon; - -+err_attach: -+ if (!IS_ERR(clk)) -+ clk_put(clk); -+err_clk: -+ regmap_exit(regmap); - err_regmap: - iounmap(base); - err_map: -diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c -index 22bd652..ab8f1d4 100644 ---- a/drivers/mfd/wm8994-core.c -+++ b/drivers/mfd/wm8994-core.c -@@ -12,6 +12,7 @@ - * - */ - -+#include - #include - #include - #include -@@ -191,6 +192,12 @@ static int wm8994_resume(struct device *dev) - if (!wm8994->suspended) - return 0; - -+ /* -+ * LDO1/2 minimum cycle time is 36ms according to codec specification -+ * Wait before enabling regulator to make sure we fit this requirement -+ */ -+ msleep(40); -+ - ret = regulator_bulk_enable(wm8994->num_supplies, - wm8994->supplies); - if (ret != 0) { -@@ -314,6 +321,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) - if (pdata->ldo[1].enable < 0) - pdata->ldo[1].enable = 0; - -+ pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1"); -+ if (IS_ERR(pdata->mclk1)) { -+ if (PTR_ERR(pdata->mclk1) != -ENOENT) -+ return PTR_ERR(pdata->mclk1); -+ pdata->mclk1 = NULL; -+ } -+ -+ pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2"); -+ if (IS_ERR(pdata->mclk2)) { -+ if (PTR_ERR(pdata->mclk2) != -ENOENT) -+ return PTR_ERR(pdata->mclk2); -+ pdata->mclk2 = NULL; -+ } -+ - return 0; - } - #else -diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h -new file mode 100644 -index 0000000..321cd087 ---- /dev/null -+++ b/include/dt-bindings/mfd/st,stpmic1.h -@@ -0,0 +1,50 @@ -+/* 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 -+ -+/* BUCK MODES definitions */ -+#define STPMIC1_BUCK_MODE_NORMAL 0 -+#define STPMIC1_BUCK_MODE_LP 2 -+ -+#endif /* __DT_BINDINGS_STPMIC1_H__ */ -diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h -new file mode 100644 -index 0000000..3c67983 ---- /dev/null -+++ b/include/linux/mfd/stmfx.h -@@ -0,0 +1,123 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2019 STMicroelectronics -+ * Author(s): Amelie Delaunay . -+ */ -+ -+#ifndef MFD_STMFX_H -+#define MFD_STMFX_H -+ -+#include -+ -+/* 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 */ -+/* IRQ output management */ -+#define STMFX_REG_IRQ_OUT_PIN 0x41 /* RW */ -+#define STMFX_REG_IRQ_SRC_EN 0x42 /* RW */ -+#define STMFX_REG_IRQ_PENDING 0x08 /* R */ -+#define STMFX_REG_IRQ_ACK 0x44 /* RW */ -+/* GPIO management */ -+#define STMFX_REG_IRQ_GPI_PENDING1 0x0C /* R */ -+#define STMFX_REG_IRQ_GPI_PENDING2 0x0D /* R */ -+#define STMFX_REG_IRQ_GPI_PENDING3 0x0E /* R */ -+#define STMFX_REG_GPIO_STATE1 0x10 /* R */ -+#define STMFX_REG_GPIO_STATE2 0x11 /* R */ -+#define STMFX_REG_GPIO_STATE3 0x12 /* R */ -+#define STMFX_REG_IRQ_GPI_SRC1 0x48 /* RW */ -+#define STMFX_REG_IRQ_GPI_SRC2 0x49 /* RW */ -+#define STMFX_REG_IRQ_GPI_SRC3 0x4A /* RW */ -+#define STMFX_REG_IRQ_GPI_EVT1 0x4C /* RW */ -+#define STMFX_REG_IRQ_GPI_EVT2 0x4D /* RW */ -+#define STMFX_REG_IRQ_GPI_EVT3 0x4E /* RW */ -+#define STMFX_REG_IRQ_GPI_TYPE1 0x50 /* RW */ -+#define STMFX_REG_IRQ_GPI_TYPE2 0x51 /* RW */ -+#define STMFX_REG_IRQ_GPI_TYPE3 0x52 /* RW */ -+#define STMFX_REG_IRQ_GPI_ACK1 0x54 /* RW */ -+#define STMFX_REG_IRQ_GPI_ACK2 0x55 /* RW */ -+#define STMFX_REG_IRQ_GPI_ACK3 0x56 /* RW */ -+#define STMFX_REG_GPIO_DIR1 0x60 /* RW */ -+#define STMFX_REG_GPIO_DIR2 0x61 /* RW */ -+#define STMFX_REG_GPIO_DIR3 0x62 /* RW */ -+#define STMFX_REG_GPIO_TYPE1 0x64 /* RW */ -+#define STMFX_REG_GPIO_TYPE2 0x65 /* RW */ -+#define STMFX_REG_GPIO_TYPE3 0x66 /* RW */ -+#define STMFX_REG_GPIO_PUPD1 0x68 /* RW */ -+#define STMFX_REG_GPIO_PUPD2 0x69 /* RW */ -+#define STMFX_REG_GPIO_PUPD3 0x6A /* RW */ -+#define STMFX_REG_GPO_SET1 0x6C /* RW */ -+#define STMFX_REG_GPO_SET2 0x6D /* RW */ -+#define STMFX_REG_GPO_SET3 0x6E /* RW */ -+#define STMFX_REG_GPO_CLR1 0x70 /* RW */ -+#define STMFX_REG_GPO_CLR2 0x71 /* RW */ -+#define STMFX_REG_GPO_CLR3 0x72 /* RW */ -+ -+#define STMFX_REG_MAX 0xB0 -+ -+/* MFX boot time is around 10ms, so after reset, we have to wait this delay */ -+#define STMFX_BOOT_TIME_MS 10 -+ -+/* 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_TS_EN BIT(1) -+#define STMFX_REG_SYS_CTRL_IDD_EN BIT(2) -+#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3) -+#define STMFX_REG_SYS_CTRL_SWRST BIT(7) -+ -+/* STMFX_REG_IRQ_OUT_PIN bitfields */ -+#define STMFX_REG_IRQ_OUT_PIN_TYPE BIT(0) /* 0-OD 1-PP */ -+#define STMFX_REG_IRQ_OUT_PIN_POL BIT(1) /* 0-active LOW 1-active HIGH */ -+ -+/* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */ -+enum stmfx_irqs { -+ STMFX_REG_IRQ_SRC_EN_GPIO = 0, -+ STMFX_REG_IRQ_SRC_EN_IDD, -+ STMFX_REG_IRQ_SRC_EN_ERROR, -+ STMFX_REG_IRQ_SRC_EN_TS_DET, -+ STMFX_REG_IRQ_SRC_EN_TS_NE, -+ STMFX_REG_IRQ_SRC_EN_TS_TH, -+ STMFX_REG_IRQ_SRC_EN_TS_FULL, -+ STMFX_REG_IRQ_SRC_EN_TS_OVF, -+ STMFX_REG_IRQ_SRC_MAX, -+}; -+ -+enum stmfx_functions { -+ STMFX_FUNC_GPIO = BIT(0), /* GPIO[15:0] */ -+ STMFX_FUNC_ALTGPIO_LOW = BIT(1), /* aGPIO[3:0] */ -+ STMFX_FUNC_ALTGPIO_HIGH = BIT(2), /* aGPIO[7:4] */ -+ STMFX_FUNC_TS = BIT(3), -+ STMFX_FUNC_IDD = BIT(4), -+}; -+ -+/** -+ * struct stmfx_ddata - STMFX MFD structure -+ * @device: device reference used for logs -+ * @map: register map -+ * @vdd: STMFX power supply -+ * @irq_domain: IRQ domain -+ * @lock: IRQ bus lock -+ * @irq_src: cache of IRQ_SRC_EN register for bus_lock -+ * @bkp_sysctrl: backup of SYS_CTRL register for suspend/resume -+ * @bkp_irqoutpin: backup of IRQ_OUT_PIN register for suspend/resume -+ */ -+struct stmfx { -+ struct device *dev; -+ struct regmap *map; -+ struct regulator *vdd; -+ struct irq_domain *irq_domain; -+ struct mutex lock; /* IRQ bus lock */ -+ u8 irq_src; -+#ifdef CONFIG_PM -+ u8 bkp_sysctrl; -+ u8 bkp_irqoutpin; -+#endif -+}; -+ -+int stmfx_function_enable(struct stmfx *stmfx, u32 func); -+int stmfx_function_disable(struct stmfx *stmfx, u32 func); -+#endif -diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h -new file mode 100644 -index 0000000..fa3f99f ---- /dev/null -+++ b/include/linux/mfd/stpmic1.h -@@ -0,0 +1,212 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Philippe Peurichard , -+ * Pascal Paillet for STMicroelectronics. -+ */ -+ -+#ifndef __LINUX_MFD_STPMIC1_H -+#define __LINUX_MFD_STPMIC1_H -+ -+#define TURN_ON_SR 0x1 -+#define TURN_OFF_SR 0x2 -+#define ICC_LDO_TURN_OFF_SR 0x3 -+#define ICC_BUCK_TURN_OFF_SR 0x4 -+#define RREQ_STATE_SR 0x5 -+#define VERSION_SR 0x6 -+ -+#define SWOFF_PWRCTRL_CR 0x10 -+#define PADS_PULL_CR 0x11 -+#define BUCKS_PD_CR 0x12 -+#define LDO14_PD_CR 0x13 -+#define LDO56_VREF_PD_CR 0x14 -+#define VBUS_DET_VIN_CR 0x15 -+#define PKEY_TURNOFF_CR 0x16 -+#define BUCKS_MASK_RANK_CR 0x17 -+#define BUCKS_MASK_RESET_CR 0x18 -+#define LDOS_MASK_RANK_CR 0x19 -+#define LDOS_MASK_RESET_CR 0x1A -+#define WCHDG_CR 0x1B -+#define WCHDG_TIMER_CR 0x1C -+#define BUCKS_ICCTO_CR 0x1D -+#define LDOS_ICCTO_CR 0x1E -+ -+#define BUCK1_ACTIVE_CR 0x20 -+#define BUCK2_ACTIVE_CR 0x21 -+#define BUCK3_ACTIVE_CR 0x22 -+#define BUCK4_ACTIVE_CR 0x23 -+#define VREF_DDR_ACTIVE_CR 0x24 -+#define LDO1_ACTIVE_CR 0x25 -+#define LDO2_ACTIVE_CR 0x26 -+#define LDO3_ACTIVE_CR 0x27 -+#define LDO4_ACTIVE_CR 0x28 -+#define LDO5_ACTIVE_CR 0x29 -+#define LDO6_ACTIVE_CR 0x2A -+ -+#define BUCK1_STDBY_CR 0x30 -+#define BUCK2_STDBY_CR 0x31 -+#define BUCK3_STDBY_CR 0x32 -+#define BUCK4_STDBY_CR 0x33 -+#define VREF_DDR_STDBY_CR 0x34 -+#define LDO1_STDBY_CR 0x35 -+#define LDO2_STDBY_CR 0x36 -+#define LDO3_STDBY_CR 0x37 -+#define LDO4_STDBY_CR 0x38 -+#define LDO5_STDBY_CR 0x39 -+#define LDO6_STDBY_CR 0x3A -+ -+#define BST_SW_CR 0x40 -+ -+#define INT_PENDING_R1 0x50 -+#define INT_PENDING_R2 0x51 -+#define INT_PENDING_R3 0x52 -+#define INT_PENDING_R4 0x53 -+ -+#define INT_DBG_LATCH_R1 0x60 -+#define INT_DBG_LATCH_R2 0x61 -+#define INT_DBG_LATCH_R3 0x62 -+#define INT_DBG_LATCH_R4 0x63 -+ -+#define INT_CLEAR_R1 0x70 -+#define INT_CLEAR_R2 0x71 -+#define INT_CLEAR_R3 0x72 -+#define INT_CLEAR_R4 0x73 -+ -+#define INT_MASK_R1 0x80 -+#define INT_MASK_R2 0x81 -+#define INT_MASK_R3 0x82 -+#define INT_MASK_R4 0x83 -+ -+#define INT_SET_MASK_R1 0x90 -+#define INT_SET_MASK_R2 0x91 -+#define INT_SET_MASK_R3 0x92 -+#define INT_SET_MASK_R4 0x93 -+ -+#define INT_CLEAR_MASK_R1 0xA0 -+#define INT_CLEAR_MASK_R2 0xA1 -+#define INT_CLEAR_MASK_R3 0xA2 -+#define INT_CLEAR_MASK_R4 0xA3 -+ -+#define INT_SRC_R1 0xB0 -+#define INT_SRC_R2 0xB1 -+#define INT_SRC_R3 0xB2 -+#define INT_SRC_R4 0xB3 -+ -+#define PMIC_MAX_REGISTER_ADDRESS INT_SRC_R4 -+ -+#define STPMIC1_PMIC_NUM_IRQ_REGS 4 -+ -+#define TURN_OFF_SR_ICC_EVENT 0x08 -+ -+#define LDO_VOLTAGE_MASK GENMASK(6, 2) -+#define BUCK_VOLTAGE_MASK GENMASK(7, 2) -+#define LDO_BUCK_VOLTAGE_SHIFT 2 -+ -+#define LDO_ENABLE_MASK BIT(0) -+#define BUCK_ENABLE_MASK BIT(0) -+ -+#define BUCK_HPLP_ENABLE_MASK BIT(1) -+#define BUCK_HPLP_SHIFT 1 -+ -+#define STDBY_ENABLE_MASK BIT(0) -+ -+#define BUCKS_PD_CR_REG_MASK GENMASK(7, 0) -+#define BUCK_MASK_RANK_REGISTER_MASK GENMASK(3, 0) -+#define BUCK_MASK_RESET_REGISTER_MASK GENMASK(3, 0) -+#define LDO1234_PULL_DOWN_REGISTER_MASK GENMASK(7, 0) -+#define LDO56_VREF_PD_CR_REG_MASK GENMASK(5, 0) -+#define LDO_MASK_RANK_REGISTER_MASK GENMASK(5, 0) -+#define LDO_MASK_RESET_REGISTER_MASK GENMASK(5, 0) -+ -+#define BUCK1_PULL_DOWN_REG BUCKS_PD_CR -+#define BUCK1_PULL_DOWN_MASK BIT(0) -+#define BUCK2_PULL_DOWN_REG BUCKS_PD_CR -+#define BUCK2_PULL_DOWN_MASK BIT(2) -+#define BUCK3_PULL_DOWN_REG BUCKS_PD_CR -+#define BUCK3_PULL_DOWN_MASK BIT(4) -+#define BUCK4_PULL_DOWN_REG BUCKS_PD_CR -+#define BUCK4_PULL_DOWN_MASK BIT(6) -+ -+#define LDO1_PULL_DOWN_REG LDO14_PD_CR -+#define LDO1_PULL_DOWN_MASK BIT(0) -+#define LDO2_PULL_DOWN_REG LDO14_PD_CR -+#define LDO2_PULL_DOWN_MASK BIT(2) -+#define LDO3_PULL_DOWN_REG LDO14_PD_CR -+#define LDO3_PULL_DOWN_MASK BIT(4) -+#define LDO4_PULL_DOWN_REG LDO14_PD_CR -+#define LDO4_PULL_DOWN_MASK BIT(6) -+#define LDO5_PULL_DOWN_REG LDO56_VREF_PD_CR -+#define LDO5_PULL_DOWN_MASK BIT(0) -+#define LDO6_PULL_DOWN_REG LDO56_VREF_PD_CR -+#define LDO6_PULL_DOWN_MASK BIT(2) -+#define VREF_DDR_PULL_DOWN_REG LDO56_VREF_PD_CR -+#define VREF_DDR_PULL_DOWN_MASK BIT(4) -+ -+#define BUCKS_ICCTO_CR_REG_MASK GENMASK(6, 0) -+#define LDOS_ICCTO_CR_REG_MASK GENMASK(5, 0) -+ -+#define LDO_BYPASS_MASK BIT(7) -+ -+/* Main PMIC Control Register -+ * SWOFF_PWRCTRL_CR -+ * Address : 0x10 -+ */ -+#define ICC_EVENT_ENABLED BIT(4) -+#define PWRCTRL_POLARITY_HIGH BIT(3) -+#define PWRCTRL_PIN_VALID BIT(2) -+#define RESTART_REQUEST_ENABLED BIT(1) -+#define SOFTWARE_SWITCH_OFF_ENABLED BIT(0) -+ -+/* Main PMIC PADS Control Register -+ * PADS_PULL_CR -+ * Address : 0x11 -+ */ -+#define WAKEUP_DETECTOR_DISABLED BIT(4) -+#define PWRCTRL_PD_ACTIVE BIT(3) -+#define PWRCTRL_PU_ACTIVE BIT(2) -+#define WAKEUP_PD_ACTIVE BIT(1) -+#define PONKEY_PU_INACTIVE BIT(0) -+ -+/* Main PMIC VINLOW Control Register -+ * VBUS_DET_VIN_CRC DMSC -+ * Address : 0x15 -+ */ -+#define SWIN_DETECTOR_ENABLED BIT(7) -+#define SWOUT_DETECTOR_ENABLED BIT(6) -+#define VINLOW_ENABLED BIT(0) -+#define VINLOW_CTRL_REG_MASK GENMASK(7, 0) -+ -+/* USB Control Register -+ * Address : 0x40 -+ */ -+#define BOOST_OVP_DISABLED BIT(7) -+#define VBUS_OTG_DETECTION_DISABLED BIT(6) -+#define SW_OUT_DISCHARGE BIT(5) -+#define VBUS_OTG_DISCHARGE BIT(4) -+#define OCP_LIMIT_HIGH BIT(3) -+#define SWIN_SWOUT_ENABLED BIT(2) -+#define USBSW_OTG_SWITCH_ENABLED BIT(1) -+#define BOOST_ENABLED BIT(0) -+ -+/* PKEY_TURNOFF_CR -+ * Address : 0x16 -+ */ -+#define PONKEY_PWR_OFF BIT(7) -+#define PONKEY_CC_FLAG_CLEAR BIT(6) -+#define PONKEY_TURNOFF_TIMER_MASK GENMASK(3, 0) -+#define PONKEY_TURNOFF_MASK GENMASK(7, 0) -+ -+/* -+ * struct stpmic1 - stpmic1 master device for sub-drivers -+ * @dev: master device of the chip (can be used to access platform data) -+ * @irq: main IRQ number -+ * @regmap_irq_chip_data: irq chip data -+ */ -+struct stpmic1 { -+ struct device *dev; -+ struct regmap *regmap; -+ int irq; -+ struct regmap_irq_chip_data *irq_data; -+}; -+ -+#endif /* __LINUX_MFD_STPMIC1_H */ -diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h -index b19c370..cdaf3f6 100644 ---- a/include/linux/mfd/wm8994/pdata.h -+++ b/include/linux/mfd/wm8994/pdata.h -@@ -239,6 +239,12 @@ struct wm8994_pdata { - * GPIO for the IRQ pin if host only supports edge triggering - */ - int irq_gpio; -+ -+ /* MCLK1 clock provider */ -+ struct clk *mclk1; -+ -+ /* MCLK2 clock provider */ -+ struct clk *mclk2; - }; - - #endif --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch deleted file mode 100644 index 22202c4..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch +++ /dev/null @@ -1,5193 +0,0 @@ -From 1549511bd55cdcfccdaded1d1e1b0e7e68adc8bb Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:42 +0100 -Subject: [PATCH 15/31] ARM stm32mp1 r3 MMC MTD - ---- - drivers/mmc/host/Kconfig | 10 + - drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/mmci.c | 862 ++++++++++---- - drivers/mmc/host/mmci.h | 189 ++- - drivers/mmc/host/mmci_qcom_dml.c | 17 +- - drivers/mmc/host/mmci_stm32_sdmmc.c | 429 +++++++ - drivers/mtd/nand/raw/Kconfig | 9 + - drivers/mtd/nand/raw/Makefile | 1 + - drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2041 ++++++++++++++++++++++++++++++++ - drivers/mtd/spi-nor/Kconfig | 7 - - drivers/mtd/spi-nor/Makefile | 1 - - drivers/mtd/spi-nor/stm32-quadspi.c | 720 ----------- - 12 files changed, 3285 insertions(+), 1002 deletions(-) - create mode 100644 drivers/mmc/host/mmci_stm32_sdmmc.c - create mode 100644 drivers/mtd/nand/raw/stm32_fmc2_nand.c - delete mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c - -diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 694d082..9742519 100644 ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -34,6 +34,16 @@ config MMC_QCOM_DML - - if unsure, say N. - -+config MMC_STM32_SDMMC -+ bool "STMicroelectronics STM32 SDMMC Controller" -+ depends on MMC_ARMMMCI -+ default y -+ help -+ This selects the STMicroelectronics STM32 SDMMC host controller. -+ If you have a STM32 sdmmc host with internal DMA say Y here. -+ -+ If unsure, say N. -+ - config MMC_PXA - tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" - depends on ARCH_PXA -diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index ce8398e..f14410f 100644 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -6,6 +6,7 @@ - obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o - armmmci-y := mmci.o - armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o -+armmmci-$(CONFIG_MMC_STM32_SDMMC) += mmci_stm32_sdmmc.o - obj-$(CONFIG_MMC_PXA) += pxamci.o - obj-$(CONFIG_MMC_MXC) += mxcmmc.o - obj-$(CONFIG_MMC_MXS) += mxs-mmc.o -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index fa6268c..1c6b5d0 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -21,15 +22,16 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include - #include - #include - #include --#include --#include -+#include - #include - #include - #include -@@ -37,6 +39,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -46,41 +49,79 @@ - - #define DRIVER_NAME "mmci-pl18x" - -+#ifdef CONFIG_DMA_ENGINE -+void mmci_variant_init(struct mmci_host *host); -+#else -+static inline void mmci_variant_init(struct mmci_host *host) {} -+#endif -+ -+#ifdef CONFIG_MMC_STM32_SDMMC -+void sdmmc_variant_init(struct mmci_host *host); -+#else -+static inline void sdmmc_variant_init(struct mmci_host *host) {} -+#endif -+static void -+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c); -+ - static unsigned int fmax = 515633; - - static struct variant_data variant_arm = { - .fifosize = 16 * 4, - .fifohalfsize = 8 * 4, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 16, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .pwrreg_powerup = MCI_PWR_UP, - .f_max = 100000000, - .reversed_irq_handling = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_ROD, -+ .init = mmci_variant_init, - }; - - static struct variant_data variant_arm_extended_fifo = { - .fifosize = 128 * 4, - .fifohalfsize = 64 * 4, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 16, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .pwrreg_powerup = MCI_PWR_UP, - .f_max = 100000000, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_ROD, -+ .init = mmci_variant_init, - }; - - static struct variant_data variant_arm_extended_fifo_hwfc = { - .fifosize = 128 * 4, - .fifohalfsize = 64 * 4, - .clkreg_enable = MCI_ARM_HWFCEN, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 16, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .pwrreg_powerup = MCI_PWR_UP, - .f_max = 100000000, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_ROD, -+ .init = mmci_variant_init, - }; - - static struct variant_data variant_u300 = { -@@ -88,17 +129,25 @@ static struct variant_data variant_u300 = { - .fifohalfsize = 8 * 4, - .clkreg_enable = MCI_ST_U300_HWFCEN, - .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 16, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, -- .st_sdio = true, - .pwrreg_powerup = MCI_PWR_ON, - .f_max = 100000000, - .signal_direction = true, - .pwrreg_clkgate = true, - .pwrreg_nopower = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, -+ .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_nomadik = { -@@ -106,9 +155,14 @@ static struct variant_data variant_nomadik = { - .fifohalfsize = 8 * 4, - .clkreg = MCI_CLK_ENABLE, - .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 24, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, -- .st_sdio = true, - .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .f_max = 100000000, -@@ -116,8 +170,11 @@ static struct variant_data variant_nomadik = { - .pwrreg_clkgate = true, - .pwrreg_nopower = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, -+ .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_ux500 = { -@@ -127,9 +184,14 @@ static struct variant_data variant_ux500 = { - .clkreg_enable = MCI_ST_UX500_HWFCEN, - .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, - .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datalength_bits = 24, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, -- .st_sdio = true, - .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .f_max = 100000000, -@@ -141,8 +203,11 @@ static struct variant_data variant_ux500 = { - .busy_detect_mask = MCI_ST_BUSYENDMASK, - .pwrreg_nopower = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, -+ .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_ux500v2 = { -@@ -152,10 +217,15 @@ static struct variant_data variant_ux500v2 = { - .clkreg_enable = MCI_ST_UX500_HWFCEN, - .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, - .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, - .datalength_bits = 24, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, -- .st_sdio = true, - .st_clkdiv = true, - .blksz_datactrl16 = true, - .pwrreg_powerup = MCI_PWR_ON, -@@ -168,8 +238,11 @@ static struct variant_data variant_ux500v2 = { - .busy_detect_mask = MCI_ST_BUSYENDMASK, - .pwrreg_nopower = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, -+ .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_stm32 = { -@@ -179,14 +252,77 @@ static struct variant_data variant_stm32 = { - .clkreg_enable = MCI_ST_UX500_HWFCEN, - .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, - .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .datalength_bits = 24, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, -- .st_sdio = true, - .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .f_max = 48000000, - .pwrreg_clkgate = true, - .pwrreg_nopower = true, -+ .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, -+}; -+ -+static struct variant_data variant_stm32_sdmmc = { -+ .fifosize = 16 * 4, -+ .fifohalfsize = 8 * 4, -+ .f_max = 208000000, -+ .stm32_clkdiv = true, -+ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, -+ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, -+ .cmdreg_srsp = MCI_CPSM_STM32_SRSP, -+ .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, -+ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, -+ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, -+ .datactrl_first = true, -+ .datacnt_useless = true, -+ .datalength_bits = 25, -+ .datactrl_blocksz = 14, -+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, -+ .stm32_idmabsize_mask = GENMASK(12, 5), -+ .busy_detect = true, -+ .busy_timeout = true, -+ .busy_detect_flag = MCI_STM32_BUSYD0, -+ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, -+ .init = sdmmc_variant_init, -+ .quirks = MMCI_QUIRK_STM32_DTMODE | -+ MMCI_QUIRK_STM32_VSWITCH, -+}; -+ -+static struct variant_data variant_stm32_sdmmcv2 = { -+ .fifosize = 16 * 4, -+ .fifohalfsize = 8 * 4, -+ .f_max = 208000000, -+ .stm32_clkdiv = true, -+ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, -+ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, -+ .cmdreg_srsp = MCI_CPSM_STM32_SRSP, -+ .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, -+ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, -+ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, -+ .datactrl_first = true, -+ .datacnt_useless = true, -+ .datalength_bits = 25, -+ .datactrl_blocksz = 14, -+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, -+ .stm32_idmabsize_mask = GENMASK(16, 5), -+ .dma_lli = true, -+ .busy_detect = true, -+ .busy_timeout = true, -+ .busy_detect_flag = MCI_STM32_BUSYD0, -+ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, -+ .init = sdmmc_variant_init, -+ .quirks = MMCI_QUIRK_STM32_DTMODE | -+ MMCI_QUIRK_STM32_VSWITCH, - }; - - static struct variant_data variant_qcom = { -@@ -197,15 +333,22 @@ static struct variant_data variant_qcom = { - MCI_QCOM_CLK_SELECT_IN_FBCLK, - .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8, - .datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE, -+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, -+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, -+ .cmdreg_srsp = MCI_CPSM_RESPONSE, - .data_cmd_enable = MCI_CPSM_QCOM_DATCMD, - .blksz_datactrl4 = true, - .datalength_bits = 24, -+ .datactrl_blocksz = 11, -+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE, - .pwrreg_powerup = MCI_PWR_UP, - .f_max = 208000000, - .explicit_mclk_control = true, - .qcom_fifo = true, - .qcom_dml = true, - .mmcimask1 = true, -+ .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_ROD, - .init = qcom_variant_init, -@@ -226,24 +369,6 @@ static int mmci_card_busy(struct mmc_host *mmc) - return busy; - } - --/* -- * Validate mmc prerequisites -- */ --static int mmci_validate_data(struct mmci_host *host, -- struct mmc_data *data) --{ -- if (!data) -- return 0; -- -- if (!is_power_of_2(data->blksz)) { -- dev_err(mmc_dev(host->mmc), -- "unsupported block size (%d bytes)\n", data->blksz); -- return -EINVAL; -- } -- -- return 0; --} -- - static void mmci_reg_delay(struct mmci_host *host) - { - /* -@@ -262,7 +387,7 @@ static void mmci_reg_delay(struct mmci_host *host) - /* - * This must be called with host->lock held - */ --static void mmci_write_clkreg(struct mmci_host *host, u32 clk) -+void mmci_write_clkreg(struct mmci_host *host, u32 clk) - { - if (host->clk_reg != clk) { - host->clk_reg = clk; -@@ -273,7 +398,7 @@ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) - /* - * This must be called with host->lock held - */ --static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) -+void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) - { - if (host->pwr_reg != pwr) { - host->pwr_reg = pwr; -@@ -357,9 +482,157 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) - mmci_write_clkreg(host, clk); - } - -+void mmci_dma_release(struct mmci_host *host) -+{ -+ if (host->ops && host->ops->dma_release) -+ host->ops->dma_release(host); -+ -+ host->use_dma = false; -+} -+ -+void mmci_dma_setup(struct mmci_host *host) -+{ -+ if (!host->ops || !host->ops->dma_setup) -+ return; -+ -+ if (host->ops->dma_setup(host)) -+ return; -+ -+ /* initialize pre request cookie */ -+ host->next_cookie = 1; -+ -+ host->use_dma = true; -+} -+ -+/* -+ * Validate mmc prerequisites -+ */ -+static int mmci_validate_data(struct mmci_host *host, -+ struct mmc_data *data) -+{ -+ if (!data) -+ return 0; -+ -+ if ((host->mmc->card && !mmc_card_sdio(host->mmc->card)) && -+ !is_power_of_2(data->blksz)) { -+ dev_err(mmc_dev(host->mmc), -+ "unsupported block size (%d bytes)\n", data->blksz); -+ return -EINVAL; -+ } -+ -+ if (host->ops && host->ops->validate_data) -+ return host->ops->validate_data(host, data); -+ -+ return 0; -+} -+ -+int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next) -+{ -+ int err; -+ -+ if (!host->ops || !host->ops->prep_data) -+ return 0; -+ -+ err = host->ops->prep_data(host, data, next); -+ -+ if (next && !err) -+ data->host_cookie = ++host->next_cookie < 0 ? -+ 1 : host->next_cookie; -+ -+ return err; -+} -+ -+void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data, -+ int err) -+{ -+ if (host->ops && host->ops->unprep_data) -+ host->ops->unprep_data(host, data, err); -+ -+ data->host_cookie = 0; -+} -+ -+void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -+{ -+ WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); -+ -+ if (host->ops && host->ops->get_next_data) -+ host->ops->get_next_data(host, data); -+} -+ -+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) -+{ -+ struct mmc_data *data = host->data; -+ int ret; -+ -+ if (!host->use_dma) -+ return -EINVAL; -+ -+ ret = mmci_prep_data(host, data, false); -+ if (ret) -+ return ret; -+ -+ if (!host->ops || !host->ops->dma_start) -+ return -EINVAL; -+ -+ /* Okay, go for it. */ -+ dev_vdbg(mmc_dev(host->mmc), -+ "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", -+ data->sg_len, data->blksz, data->blocks, data->flags); -+ -+ host->ops->dma_start(host, &datactrl); -+ -+ /* Trigger the DMA transfer */ -+ mmci_write_datactrlreg(host, datactrl); -+ -+ /* -+ * Let the MMCI say when the data is ended and it's time -+ * to fire next DMA request. When that happens, MMCI will -+ * call mmci_data_end() -+ */ -+ writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, -+ host->base + MMCIMASK0); -+ return 0; -+} -+ -+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) -+{ -+ if (!host->use_dma) -+ return; -+ -+ if (host->ops && host->ops->dma_finalize) -+ host->ops->dma_finalize(host, data); -+} -+ -+void mmci_dma_error(struct mmci_host *host) -+{ -+ if (!host->use_dma) -+ return; -+ -+ if (host->ops && host->ops->dma_error) -+ host->ops->dma_error(host); -+} -+ - static void - mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) - { -+ /* -+ * If an error happens on command or data step, some variants -+ * require a stop command to reinit the DPSM. -+ * If it's not done the next data command freeze hardware block. -+ */ -+ if (host->variant->cmdreg_stop) { -+ u32 dpsm; -+ -+ dpsm = readl_relaxed(host->base + MMCISTATUS); -+ dpsm &= MCI_STM32_DPSMACTIVE; -+ -+ if (dpsm && ((mrq->cmd && mrq->cmd->error) || -+ (mrq->data && mrq->data->error))) { -+ mmci_start_command(host, &host->stop_abort, 0); -+ return; -+ } -+ } -+ - writel(0, host->base + MMCICOMMAND); - - BUG_ON(host->data); -@@ -378,7 +651,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) - if (host->singleirq) { - unsigned int mask0 = readl(base + MMCIMASK0); - -- mask0 &= ~MCI_IRQ1MASK; -+ mask0 &= ~variant->irq_pio_mask; - mask0 |= mask; - - writel(mask0, base + MMCIMASK0); -@@ -415,31 +688,50 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) - * no custom DMA interfaces are supported. - */ - #ifdef CONFIG_DMA_ENGINE --static void mmci_dma_setup(struct mmci_host *host) -+struct mmci_dmae_next { -+ struct dma_async_tx_descriptor *desc; -+ struct dma_chan *chan; -+}; -+ -+struct mmci_dmae_priv { -+ struct dma_chan *cur; -+ struct dma_chan *rx_channel; -+ struct dma_chan *tx_channel; -+ struct dma_async_tx_descriptor *desc_current; -+ struct mmci_dmae_next next_data; -+}; -+ -+int mmci_dmae_setup(struct mmci_host *host) - { - const char *rxname, *txname; -+ struct mmci_dmae_priv *dmae; -+ -+ dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); -+ if (!dmae) -+ return -ENOMEM; - -- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); -- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); -+ host->dma_priv = dmae; - -- /* initialize pre request cookie */ -- host->next_data.cookie = 1; -+ dmae->rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), -+ "rx"); -+ dmae->tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), -+ "tx"); - - /* - * If only an RX channel is specified, the driver will - * attempt to use it bidirectionally, however if it is - * is specified but cannot be located, DMA will be disabled. - */ -- if (host->dma_rx_channel && !host->dma_tx_channel) -- host->dma_tx_channel = host->dma_rx_channel; -+ if (dmae->rx_channel && !dmae->tx_channel) -+ dmae->tx_channel = dmae->rx_channel; - -- if (host->dma_rx_channel) -- rxname = dma_chan_name(host->dma_rx_channel); -+ if (dmae->rx_channel) -+ rxname = dma_chan_name(dmae->rx_channel); - else - rxname = "none"; - -- if (host->dma_tx_channel) -- txname = dma_chan_name(host->dma_tx_channel); -+ if (dmae->tx_channel) -+ txname = dma_chan_name(dmae->tx_channel); - else - txname = "none"; - -@@ -450,66 +742,84 @@ static void mmci_dma_setup(struct mmci_host *host) - * Limit the maximum segment size in any SG entry according to - * the parameters of the DMA engine device. - */ -- if (host->dma_tx_channel) { -- struct device *dev = host->dma_tx_channel->device->dev; -+ if (dmae->tx_channel) { -+ struct device *dev = dmae->tx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } -- if (host->dma_rx_channel) { -- struct device *dev = host->dma_rx_channel->device->dev; -+ if (dmae->rx_channel) { -+ struct device *dev = dmae->rx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } - -- if (host->ops && host->ops->dma_setup) -- host->ops->dma_setup(host); -+ if (!dmae->tx_channel || !dmae->rx_channel) { -+ mmci_dmae_release(host); -+ return -EINVAL; -+ } -+ -+ return 0; - } - - /* - * This is used in or so inline it - * so it can be discarded. - */ --static inline void mmci_dma_release(struct mmci_host *host) -+void mmci_dmae_release(struct mmci_host *host) - { -- if (host->dma_rx_channel) -- dma_release_channel(host->dma_rx_channel); -- if (host->dma_tx_channel) -- dma_release_channel(host->dma_tx_channel); -- host->dma_rx_channel = host->dma_tx_channel = NULL; --} -+ struct mmci_dmae_priv *dmae = host->dma_priv; - --static void mmci_dma_data_error(struct mmci_host *host) --{ -- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); -- dmaengine_terminate_all(host->dma_current); -- host->dma_in_progress = false; -- host->dma_current = NULL; -- host->dma_desc_current = NULL; -- host->data->host_cookie = 0; -+ if (dmae->rx_channel) -+ dma_release_channel(dmae->rx_channel); -+ if (dmae->tx_channel) -+ dma_release_channel(dmae->tx_channel); -+ dmae->rx_channel = dmae->tx_channel = NULL; - } - - static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) - { -+ struct mmci_dmae_priv *dmae = host->dma_priv; - struct dma_chan *chan; - - if (data->flags & MMC_DATA_READ) -- chan = host->dma_rx_channel; -+ chan = dmae->rx_channel; - else -- chan = host->dma_tx_channel; -+ chan = dmae->tx_channel; - - dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, - mmc_get_dma_dir(data)); - } - --static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) -+void mmci_dmae_error(struct mmci_host *host) - { -+ struct mmci_dmae_priv *dmae = host->dma_priv; -+ -+ if (!dma_inprogress(host)) -+ return; -+ -+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); -+ dmaengine_terminate_all(dmae->cur); -+ host->dma_in_progress = false; -+ dmae->cur = NULL; -+ dmae->desc_current = NULL; -+ host->data->host_cookie = 0; -+ -+ mmci_dma_unmap(host, host->data); -+} -+ -+void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) -+{ -+ struct mmci_dmae_priv *dmae = host->dma_priv; - u32 status; - int i; - -+ if (!dma_inprogress(host)) -+ return; -+ - /* Wait up to 1ms for the DMA to complete */ - for (i = 0; ; i++) { - status = readl(host->base + MMCISTATUS); -@@ -525,13 +835,12 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) - * contiguous buffers. On TX, we'll get a FIFO underrun error. - */ - if (status & MCI_RXDATAAVLBLMASK) { -- mmci_dma_data_error(host); -+ mmci_dma_error(host); - if (!data->error) - data->error = -EIO; -- } -- -- if (!data->host_cookie) -+ } else if (!data->host_cookie) { - mmci_dma_unmap(host, data); -+ } - - /* - * Use of DMA with scatter-gather is impossible. -@@ -543,15 +852,16 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) - } - - host->dma_in_progress = false; -- host->dma_current = NULL; -- host->dma_desc_current = NULL; -+ dmae->cur = NULL; -+ dmae->desc_current = NULL; - } - - /* prepares DMA channel and DMA descriptor, returns non-zero on failure */ --static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, -+static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, - struct dma_chan **dma_chan, - struct dma_async_tx_descriptor **dma_desc) - { -+ struct mmci_dmae_priv *dmae = host->dma_priv; - struct variant_data *variant = host->variant; - struct dma_slave_config conf = { - .src_addr = host->phybase + MMCIFIFO, -@@ -570,10 +880,10 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, - - if (data->flags & MMC_DATA_READ) { - conf.direction = DMA_DEV_TO_MEM; -- chan = host->dma_rx_channel; -+ chan = dmae->rx_channel; - } else { - conf.direction = DMA_MEM_TO_DEV; -- chan = host->dma_tx_channel; -+ chan = dmae->tx_channel; - } - - /* If there's no DMA channel, fall back to PIO */ -@@ -610,160 +920,137 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, - return -ENOMEM; - } - --static inline int mmci_dma_prep_data(struct mmci_host *host, -- struct mmc_data *data) -+int mmci_dmae_prep_data(struct mmci_host *host, -+ struct mmc_data *data, -+ bool next) - { -+ struct mmci_dmae_priv *dmae = host->dma_priv; -+ struct mmci_dmae_next *nd = &dmae->next_data; -+ -+ if (!host->use_dma) -+ return -EINVAL; -+ -+ if (next) -+ return _mmci_dmae_prep_data(host, data, &nd->chan, &nd->desc); - /* Check if next job is already prepared. */ -- if (host->dma_current && host->dma_desc_current) -+ if (dmae->cur && dmae->desc_current) - return 0; - - /* No job were prepared thus do it now. */ -- return __mmci_dma_prep_data(host, data, &host->dma_current, -- &host->dma_desc_current); -+ return _mmci_dmae_prep_data(host, data, &dmae->cur, -+ &dmae->desc_current); - } - --static inline int mmci_dma_prep_next(struct mmci_host *host, -- struct mmc_data *data) -+int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) - { -- struct mmci_host_next *nd = &host->next_data; -- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); --} -- --static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) --{ -- int ret; -+ struct mmci_dmae_priv *dmae = host->dma_priv; - struct mmc_data *data = host->data; - -- ret = mmci_dma_prep_data(host, host->data); -- if (ret) -- return ret; -- -- /* Okay, go for it. */ -- dev_vdbg(mmc_dev(host->mmc), -- "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", -- data->sg_len, data->blksz, data->blocks, data->flags); - host->dma_in_progress = true; -- dmaengine_submit(host->dma_desc_current); -- dma_async_issue_pending(host->dma_current); -+ dmaengine_submit(dmae->desc_current); -+ dma_async_issue_pending(dmae->cur); - - if (host->variant->qcom_dml) - dml_start_xfer(host, data); - -- datactrl |= MCI_DPSM_DMAENABLE; -+ *datactrl |= MCI_DPSM_DMAENABLE; - -- /* Trigger the DMA transfer */ -- mmci_write_datactrlreg(host, datactrl); -- -- /* -- * Let the MMCI say when the data is ended and it's time -- * to fire next DMA request. When that happens, MMCI will -- * call mmci_data_end() -- */ -- writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, -- host->base + MMCIMASK0); - return 0; - } - --static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) --{ -- struct mmci_host_next *next = &host->next_data; -- -- WARN_ON(data->host_cookie && data->host_cookie != next->cookie); -- WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan)); -- -- host->dma_desc_current = next->dma_desc; -- host->dma_current = next->dma_chan; -- next->dma_desc = NULL; -- next->dma_chan = NULL; --} -- --static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) -+void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data) - { -- struct mmci_host *host = mmc_priv(mmc); -- struct mmc_data *data = mrq->data; -- struct mmci_host_next *nd = &host->next_data; -+ struct mmci_dmae_priv *dmae = host->dma_priv; -+ struct mmci_dmae_next *next = &dmae->next_data; - -- if (!data) -+ if (!host->use_dma) - return; - -- BUG_ON(data->host_cookie); -+ WARN_ON(!data->host_cookie && (next->desc || next->chan)); - -- if (mmci_validate_data(host, data)) -- return; -- -- if (!mmci_dma_prep_next(host, data)) -- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; -+ dmae->desc_current = next->desc; -+ dmae->cur = next->chan; -+ next->desc = NULL; -+ next->chan = NULL; - } - --static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, -- int err) -+void mmci_dmae_unprep_data(struct mmci_host *host, -+ struct mmc_data *data, int err) -+ - { -- struct mmci_host *host = mmc_priv(mmc); -- struct mmc_data *data = mrq->data; -+ struct mmci_dmae_priv *dmae = host->dma_priv; - -- if (!data || !data->host_cookie) -+ if (!host->use_dma) - return; - - mmci_dma_unmap(host, data); - - if (err) { -- struct mmci_host_next *next = &host->next_data; -+ struct mmci_dmae_next *next = &dmae->next_data; - struct dma_chan *chan; - if (data->flags & MMC_DATA_READ) -- chan = host->dma_rx_channel; -+ chan = dmae->rx_channel; - else -- chan = host->dma_tx_channel; -+ chan = dmae->tx_channel; - dmaengine_terminate_all(chan); - -- if (host->dma_desc_current == next->dma_desc) -- host->dma_desc_current = NULL; -+ if (dmae->desc_current == next->desc) -+ dmae->desc_current = NULL; - -- if (host->dma_current == next->dma_chan) { -+ if (dmae->cur == next->chan) { - host->dma_in_progress = false; -- host->dma_current = NULL; -+ dmae->cur = NULL; - } - -- next->dma_desc = NULL; -- next->dma_chan = NULL; -- data->host_cookie = 0; -+ next->desc = NULL; -+ next->chan = NULL; - } - } - --#else --/* Blank functions if the DMA engine is not available */ --static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) --{ --} --static inline void mmci_dma_setup(struct mmci_host *host) --{ --} -+static struct mmci_host_ops mmci_variant_ops = { -+ .prep_data = mmci_dmae_prep_data, -+ .unprep_data = mmci_dmae_unprep_data, -+ .get_next_data = mmci_dmae_get_next_data, -+ .dma_setup = mmci_dmae_setup, -+ .dma_release = mmci_dmae_release, -+ .dma_start = mmci_dmae_start, -+ .dma_finalize = mmci_dmae_finalize, -+ .dma_error = mmci_dmae_error, -+}; - --static inline void mmci_dma_release(struct mmci_host *host) -+void mmci_variant_init(struct mmci_host *host) - { -+ host->ops = &mmci_variant_ops; - } -+#endif - --static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) -+static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) - { --} -+ struct mmci_host *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; - --static inline void mmci_dma_finalize(struct mmci_host *host, -- struct mmc_data *data) --{ --} -+ if (!data) -+ return; - --static inline void mmci_dma_data_error(struct mmci_host *host) --{ -+ WARN_ON(data->host_cookie); -+ -+ if (mmci_validate_data(host, data)) -+ return; -+ -+ mmci_prep_data(host, data, true); - } - --static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) -+static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, -+ int err) - { -- return -ENOSYS; --} -+ struct mmci_host *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; - --#define mmci_pre_request NULL --#define mmci_post_request NULL -+ if (!data || !data->host_cookie) -+ return; - --#endif -+ mmci_unprep_data(host, data, err); -+} - - static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - { -@@ -790,14 +1077,23 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - writel(host->size, base + MMCIDATALENGTH); - - blksz_bits = ffs(data->blksz) - 1; -- BUG_ON(1 << blksz_bits != data->blksz); - - if (variant->blksz_datactrl16) -- datactrl = MCI_DPSM_ENABLE | (data->blksz << 16); -+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16); - else if (variant->blksz_datactrl4) -- datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); -+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4); - else -- datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; -+ datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4; -+ -+ if (variant->quirks & MMCI_QUIRK_STM32_DTMODE) { -+ if (host->mmc->card && mmc_card_sdio(host->mmc->card) && -+ data->blocks == 1) -+ datactrl |= MCI_DPSM_STM32_MODE_SDIO; -+ else if (data->stop && !host->mrq->sbc) -+ datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP; -+ else -+ datactrl |= MCI_DPSM_STM32_MODE_BLOCK; -+ } - - if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; -@@ -813,7 +1109,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - * otherwise the transfer will not start. The threshold - * depends on the rate of MCLK. - */ -- if (variant->st_sdio && data->flags & MMC_DATA_WRITE && -+ if (variant->quirks & MMCI_QUIRK_ST_SDIO && -+ data->flags & MMC_DATA_WRITE && - (host->size < 8 || - (host->size <= 8 && host->mclk > 50000000))) - clk = host->clk_reg & ~variant->clkreg_enable; -@@ -831,7 +1128,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - * Attempt to use DMA operation mode, if this - * should fail, fall back to PIO mode - */ -- if (!mmci_dma_start_data(host, datactrl)) -+ if (!mmci_dma_start(host, datactrl)) - return; - - /* IRQ mode, map the SG list for CPU reading/writing */ -@@ -864,21 +1161,44 @@ static void - mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) - { - void __iomem *base = host->base; -+ unsigned long long clks; - - dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", - cmd->opcode, cmd->arg, cmd->flags); - -- if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { -+ if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) { - writel(0, base + MMCICOMMAND); - mmci_reg_delay(host); - } - -- c |= cmd->opcode | MCI_CPSM_ENABLE; -+ if (host->variant->cmdreg_stop && -+ cmd->opcode == MMC_STOP_TRANSMISSION) -+ c |= host->variant->cmdreg_stop; -+ -+ c |= cmd->opcode | host->variant->cmdreg_cpsm_enable; - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) -- c |= MCI_CPSM_LONGRSP; -- c |= MCI_CPSM_RESPONSE; -+ c |= host->variant->cmdreg_lrsp_crc; -+ else if (cmd->flags & MMC_RSP_CRC) -+ c |= host->variant->cmdreg_srsp_crc; -+ else -+ c |= host->variant->cmdreg_srsp; - } -+ -+ if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { -+ if (!cmd->busy_timeout) -+ cmd->busy_timeout = 1000; -+ -+ clks = (unsigned long long)cmd->busy_timeout * host->cclk; -+ do_div(clks, MSEC_PER_SEC); -+ -+ writel_relaxed(clks, host->base + MMCIDATATIMER); -+ } -+ -+ if (host->variant->quirks & MMCI_QUIRK_STM32_VSWITCH && -+ cmd->opcode == SD_SWITCH_VOLTAGE) -+ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); -+ - if (/*interrupt*/0) - c |= MCI_CPSM_INTERRUPT; - -@@ -910,10 +1230,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - u32 remain, success; - - /* Terminate the DMA transfer */ -- if (dma_inprogress(host)) { -- mmci_dma_data_error(host); -- mmci_dma_unmap(host, data); -- } -+ mmci_dma_error(host); - - /* - * Calculate how far we are into the transfer. Note that -@@ -922,8 +1239,12 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - * can be as much as a FIFO-worth of data ahead. This - * matters for FIFO overruns only. - */ -- remain = readl(host->base + MMCIDATACNT); -- success = data->blksz * data->blocks - remain; -+ if (!host->variant->datacnt_useless) { -+ remain = readl(host->base + MMCIDATACNT); -+ success = data->blksz * data->blocks - remain; -+ } else { -+ success = 0; -+ } - - dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", - status_err, success); -@@ -951,19 +1272,18 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); - - if (status & MCI_DATAEND || data->error) { -- if (dma_inprogress(host)) -- mmci_dma_finalize(host, data); -+ mmci_dma_finalize(host, data); -+ - mmci_stop_data(host); - - if (!data->error) - /* The error clause is handled above, success! */ - data->bytes_xfered = data->blksz * data->blocks; - -- if (!data->stop || host->mrq->sbc) { -+ if (!data->stop || (host->mrq->sbc && !data->error)) - mmci_request_end(host, data->mrq); -- } else { -+ else - mmci_start_command(host, data->stop, 0); -- } - } - } - -@@ -972,11 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - unsigned int status) - { - void __iomem *base = host->base; -- bool sbc; -+ bool busy_resp, sbc; -+ u32 err_msk; - - if (!cmd) - return; - -+ busy_resp = !!(cmd->flags & MMC_RSP_BUSY); - sbc = (cmd == host->mrq->sbc); - - /* -@@ -984,18 +1306,21 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - * handling. Note that we tag on any latent IRQs postponed - * due to waiting for busy status. - */ -+ err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; -+ if (host->variant->busy_timeout && busy_resp) -+ err_msk |= MCI_DATATIMEOUT; -+ - if (!((status|host->busy_status) & -- (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) -+ (err_msk|MCI_CMDSENT|MCI_CMDRESPEND))) - return; - - /* - * ST Micro variant: handle busy detection. - */ -- if (host->variant->busy_detect) { -- bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); -+ if (busy_resp && host->variant->busy_detect) { - - /* We are busy with a command, return */ -- if (host->busy_status && -+ if (host->busy_status && !(status & (err_msk)) && - (status & host->variant->busy_detect_flag)) - return; - -@@ -1005,9 +1330,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - * that the special busy status bit is still set before - * proceeding. - */ -- if (!host->busy_status && busy_resp && -- !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && -- (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { -+ if (!host->busy_status && !(status & (err_msk)) && -+ (readl(base + MMCISTATUS) & -+ host->variant->busy_detect_flag)) { - - /* Clear the busy start IRQ */ - writel(host->variant->busy_detect_mask, -@@ -1049,6 +1374,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - cmd->error = -ETIMEDOUT; - } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { - cmd->error = -EILSEQ; -+ } else if (busy_resp && host->variant->busy_timeout && -+ status & MCI_DATATIMEOUT) { -+ cmd->error = -ETIMEDOUT; - } else { - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); -@@ -1059,16 +1387,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - if ((!sbc && !cmd->data) || cmd->error) { - if (host->data) { - /* Terminate the DMA transfer */ -- if (dma_inprogress(host)) { -- mmci_dma_data_error(host); -- mmci_dma_unmap(host, host->data); -- } -+ mmci_dma_error(host); -+ - mmci_stop_data(host); - } - mmci_request_end(host, host->mrq); - } else if (sbc) { - mmci_start_command(host, host->mrq->cmd, 0); -- } else if (!(cmd->data->flags & MMC_DATA_READ)) { -+ } else if (!host->variant->datactrl_first && -+ !(cmd->data->flags & MMC_DATA_READ)) { - mmci_start_data(host, cmd->data); - } - } -@@ -1268,7 +1595,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) - if (status & host->mask1_reg) - mmci_pio_irq(irq, dev_id); - -- status &= ~MCI_IRQ1MASK; -+ status &= ~host->variant->irq_pio_mask; - } - - /* -@@ -1281,7 +1608,8 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) - * to make sure that both start and end interrupts are always - * cleared one after the other. - */ -- status &= readl(host->base + MMCIMASK0); -+ status &= readl(host->base + MMCIMASK0) | -+ host->variant->busy_detect_flag; - if (host->variant->busy_detect) - writel(status & ~host->variant->busy_detect_mask, - host->base + MMCICLEAR); -@@ -1333,7 +1661,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) - if (mrq->data) - mmci_get_next_data(host, mrq->data); - -- if (mrq->data && mrq->data->flags & MMC_DATA_READ) -+ if (mrq->data && -+ (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ)) - mmci_start_data(host, mrq->data); - - if (mrq->sbc) -@@ -1443,8 +1772,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - - spin_lock_irqsave(&host->lock, flags); - -- mmci_set_clkreg(host, ios->clock); -- mmci_write_pwrreg(host, pwr); -+ if (host->ops && host->ops->set_clkreg) -+ host->ops->set_clkreg(host, ios->clock); -+ else -+ mmci_set_clkreg(host, ios->clock); -+ -+ if (host->ops && host->ops->set_pwrreg) -+ host->ops->set_pwrreg(host, pwr); -+ else -+ mmci_write_pwrreg(host, pwr); -+ - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); -@@ -1467,6 +1804,8 @@ static int mmci_get_cd(struct mmc_host *mmc) - - static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - { -+ struct mmci_host *host = mmc_priv(mmc); -+ unsigned long flags; - int ret = 0; - - if (!IS_ERR(mmc->supply.vqmmc)) { -@@ -1479,6 +1818,28 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - case MMC_SIGNAL_VOLTAGE_180: - ret = regulator_set_voltage(mmc->supply.vqmmc, - 1700000, 1950000); -+ -+ if (ret) -+ break; -+ -+ if (host->variant->quirks & MMCI_QUIRK_STM32_VSWITCH) { -+ u32 status; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ mmci_write_pwrreg(host, host->pwr_reg | -+ MCI_STM32_VSWITCH); -+ -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ /* wait voltage switch completion while 10ms */ -+ ret = readl_relaxed_poll_timeout( -+ host->base + MMCISTATUS, -+ status, -+ (status & MCI_STM32_VSWEND), -+ 10, 10000); -+ } -+ - break; - case MMC_SIGNAL_VOLTAGE_120: - ret = regulator_set_voltage(mmc->supply.vqmmc, -@@ -1493,6 +1854,16 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - return ret; - } - -+static int mmci_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct mmci_host *host = mmc_priv(mmc); -+ -+ if (host->ops && host->ops->execute_tuning) -+ return host->ops->execute_tuning(mmc, opcode); -+ -+ return -EINVAL; -+} -+ - static struct mmc_host_ops mmci_ops = { - .request = mmci_request, - .pre_req = mmci_pre_request, -@@ -1501,6 +1872,7 @@ static struct mmc_host_ops mmci_ops = { - .get_ro = mmc_gpio_get_ro, - .get_cd = mmci_get_cd, - .start_signal_voltage_switch = mmci_sig_volt_switch, -+ .execute_tuning = mmci_execute_tuning, - }; - - static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) -@@ -1523,6 +1895,12 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) - host->pwr_reg_add |= MCI_ST_CMDDIREN; - if (of_get_property(np, "st,sig-pin-fbclk", NULL)) - host->pwr_reg_add |= MCI_ST_FBCLKEN; -+ if (of_get_property(np, "st,sig-dir", NULL)) -+ host->pwr_reg_add |= MCI_STM32_DIRPOL; -+ if (of_get_property(np, "st,neg-edge", NULL)) -+ host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE; -+ if (of_get_property(np, "st,use-ckin", NULL)) -+ host->clk_reg_add |= MCI_STM32_CLK_SELCKIN; - - if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) - mmc->caps |= MMC_CAP_MMC_HIGHSPEED; -@@ -1649,6 +2027,8 @@ static int mmci_probe(struct amba_device *dev, - */ - if (variant->st_clkdiv) - mmc->f_min = DIV_ROUND_UP(host->mclk, 257); -+ else if (variant->stm32_clkdiv) -+ mmc->f_min = DIV_ROUND_UP(host->mclk, 2046); - else if (variant->explicit_mclk_control) - mmc->f_min = clk_round_rate(host->clk, 100000); - else -@@ -1670,6 +2050,12 @@ static int mmci_probe(struct amba_device *dev, - - dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); - -+ host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); -+ if (IS_ERR(host->rst)) { -+ ret = PTR_ERR(host->rst); -+ goto clk_disable; -+ } -+ - /* Get regulators and the supported OCR mask */ - ret = mmc_regulator_get_supply(mmc); - if (ret) -@@ -1680,12 +2066,7 @@ static int mmci_probe(struct amba_device *dev, - else if (plat->ocr_mask) - dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); - -- /* DT takes precedence over platform data. */ -- if (!np) { -- if (!plat->cd_invert) -- mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; -- mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; -- } -+ host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); - - /* We support these capabilities. */ - mmc->caps |= MMC_CAP_CMD23; -@@ -1694,6 +2075,8 @@ static int mmci_probe(struct amba_device *dev, - * Enable busy detection. - */ - if (variant->busy_detect) { -+ u32 max_busy_timeout = 0; -+ - mmci_ops.card_busy = mmci_card_busy; - /* - * Not all variants have a flag to enable busy detection -@@ -1703,7 +2086,18 @@ static int mmci_probe(struct amba_device *dev, - mmci_write_datactrlreg(host, - host->variant->busy_dpsm_flag); - mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; -- mmc->max_busy_timeout = 0; -+ -+ if (variant->busy_timeout) -+ max_busy_timeout = ~0UL / (mmc->f_max / MSEC_PER_SEC); -+ -+ mmc->max_busy_timeout = max_busy_timeout; -+ } -+ -+ /* prepare the stop command, used to abort and reinitialized the DPSM */ -+ if (variant->cmdreg_stop) { -+ host->stop_abort.opcode = MMC_STOP_TRANSMISSION; -+ host->stop_abort.arg = 0; -+ host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; - } - - mmc->ops = &mmci_ops; -@@ -1732,13 +2126,13 @@ static int mmci_probe(struct amba_device *dev, - /* - * Block size can be up to 2048 bytes, but must be a power of two. - */ -- mmc->max_blk_size = 1 << 11; -+ mmc->max_blk_size = 1 << variant->datactrl_blocksz; - - /* - * Limit the number of blocks transferred so that we don't overflow - * the maximum request size. - */ -- mmc->max_blk_count = mmc->max_req_size >> 11; -+ mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz; - - spin_lock_init(&host->lock); - -@@ -1754,30 +2148,16 @@ static int mmci_probe(struct amba_device *dev, - * - not using DT but using a descriptor table, or - * - using a table of descriptors ALONGSIDE DT, or - * look up these descriptors named "cd" and "wp" right here, fail -- * silently of these do not exist and proceed to try platform data -+ * silently of these do not exist - */ - if (!np) { - ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL); -- if (ret < 0) { -- if (ret == -EPROBE_DEFER) -- goto clk_disable; -- else if (gpio_is_valid(plat->gpio_cd)) { -- ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); -- if (ret) -- goto clk_disable; -- } -- } -+ if (ret == -EPROBE_DEFER) -+ goto clk_disable; - - ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); -- if (ret < 0) { -- if (ret == -EPROBE_DEFER) -- goto clk_disable; -- else if (gpio_is_valid(plat->gpio_wp)) { -- ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); -- if (ret) -- goto clk_disable; -- } -- } -+ if (ret == -EPROBE_DEFER) -+ goto clk_disable; - } - - ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, -@@ -1977,6 +2357,16 @@ static const struct amba_id mmci_ids[] = { - .mask = 0x00ffffff, - .data = &variant_stm32, - }, -+ { -+ .id = 0x10153180, -+ .mask = 0xf0ffffff, -+ .data = &variant_stm32_sdmmc, -+ }, -+ { -+ .id = 0x00253180, -+ .mask = 0xf0ffffff, -+ .data = &variant_stm32_sdmmcv2, -+ }, - /* Qualcomm variants */ - { - .id = 0x00051180, -diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 613d37a..e10093e 100644 ---- a/drivers/mmc/host/mmci.h -+++ b/drivers/mmc/host/mmci.h -@@ -23,6 +23,14 @@ - #define MCI_ST_DATA31DIREN (1 << 5) - #define MCI_ST_FBCLKEN (1 << 7) - #define MCI_ST_DATA74DIREN (1 << 8) -+/* -+ * The STM32 sdmmc does not have PWR_UP/OD/ROD -+ * and uses the power register for -+ */ -+#define MCI_STM32_PWR_CYC 0x02 -+#define MCI_STM32_VSWITCH BIT(2) -+#define MCI_STM32_VSWITCHEN BIT(3) -+#define MCI_STM32_DIRPOL BIT(4) - - #define MMCICLOCK 0x004 - #define MCI_CLK_ENABLE (1 << 8) -@@ -50,6 +58,19 @@ - #define MCI_QCOM_CLK_SELECT_IN_FBCLK BIT(15) - #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15)) - -+/* Modified on STM32 sdmmc */ -+#define MCI_STM32_CLK_CLKDIV_MSK GENMASK(9, 0) -+#define MCI_STM32_CLK_WIDEBUS_4 BIT(14) -+#define MCI_STM32_CLK_WIDEBUS_8 BIT(15) -+#define MCI_STM32_CLK_NEGEDGE BIT(16) -+#define MCI_STM32_CLK_HWFCEN BIT(17) -+#define MCI_STM32_CLK_DDR BIT(18) -+#define MCI_STM32_CLK_BUSSPEED BIT(19) -+#define MCI_STM32_CLK_SEL_MSK GENMASK(21, 20) -+#define MCI_STM32_CLK_SELCK (0 << 20) -+#define MCI_STM32_CLK_SELCKIN (1 << 20) -+#define MCI_STM32_CLK_SELFBCK (2 << 20) -+ - #define MMCIARGUMENT 0x008 - - /* The command register controls the Command Path State Machine (CPSM) */ -@@ -72,6 +93,15 @@ - #define MCI_CPSM_QCOM_CCSDISABLE BIT(15) - #define MCI_CPSM_QCOM_AUTO_CMD19 BIT(16) - #define MCI_CPSM_QCOM_AUTO_CMD21 BIT(21) -+/* Command register in STM32 sdmmc versions */ -+#define MCI_CPSM_STM32_CMDTRANS BIT(6) -+#define MCI_CPSM_STM32_CMDSTOP BIT(7) -+#define MCI_CPSM_STM32_WAITRESP_MASK GENMASK(9, 8) -+#define MCI_CPSM_STM32_NORSP (0 << 8) -+#define MCI_CPSM_STM32_SRSP_CRC (1 << 8) -+#define MCI_CPSM_STM32_SRSP (2 << 8) -+#define MCI_CPSM_STM32_LRSP_CRC (3 << 8) -+#define MCI_CPSM_STM32_ENABLE BIT(12) - - #define MMCIRESPCMD 0x010 - #define MMCIRESPONSE0 0x014 -@@ -101,6 +131,12 @@ - /* Control register extensions in the Qualcomm versions */ - #define MCI_DPSM_QCOM_DATA_PEND BIT(17) - #define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20) -+/* Control register extensions in STM32 versions */ -+#define MCI_DPSM_STM32_MODE_BLOCK (0 << 2) -+#define MCI_DPSM_STM32_MODE_SDIO (1 << 2) -+#define MCI_DPSM_STM32_MODE_STREAM (2 << 2) -+#define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2) -+#define MCI_DPSM_STM32_SDIOEN BIT(11) - - #define MMCIDATACNT 0x030 - #define MMCISTATUS 0x034 -@@ -130,6 +166,11 @@ - #define MCI_ST_SDIOIT (1 << 22) - #define MCI_ST_CEATAEND (1 << 23) - #define MCI_ST_CARDBUSY (1 << 24) -+/* Extended status bits for the STM32 variants */ -+#define MCI_STM32_DPSMACTIVE BIT(12) -+#define MCI_STM32_BUSYD0 BIT(20) -+#define MCI_STM32_BUSYD0END BIT(21) -+#define MCI_STM32_VSWEND BIT(25) - - #define MMCICLEAR 0x038 - #define MCI_CMDCRCFAILCLR (1 << 0) -@@ -175,21 +216,45 @@ - #define MCI_ST_SDIOITMASK (1 << 22) - #define MCI_ST_CEATAENDMASK (1 << 23) - #define MCI_ST_BUSYENDMASK (1 << 24) -+/* Extended status bits for the STM32 variants */ -+#define MCI_STM32_BUSYD0ENDMASK BIT(21) - - #define MMCIMASK1 0x040 - #define MMCIFIFOCNT 0x048 - #define MMCIFIFO 0x080 /* to 0x0bc */ - -+/* STM32 sdmmc registers for IDMA (Internal DMA) */ -+#define MMCI_STM32_IDMACTRLR 0x050 -+#define MMCI_STM32_IDMAEN BIT(0) -+#define MMCI_STM32_IDMALLIEN BIT(1) -+ -+#define MMCI_STM32_IDMABSIZER 0x054 -+#define MMCI_STM32_IDMABNDT_SHIFT 5 -+#define MMCI_STM32_IDMABNDT_MASK GENMASK(12, 5) -+ -+#define MMCI_STM32_IDMABASE0R 0x058 -+ -+#define MMCI_STM32_IDMALAR 0x64 -+#define MMCI_STM32_IDMALA_MASK GENMASK(13, 0) -+#define MMCI_STM32_ABR BIT(29) -+#define MMCI_STM32_ULS BIT(30) -+#define MMCI_STM32_ULA BIT(31) -+ -+#define MMCI_STM32_IDMABAR 0x68 -+ - #define MCI_IRQENABLE \ - (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \ - MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \ - MCI_CMDRESPENDMASK | MCI_CMDSENTMASK) - - /* These interrupts are directed to IRQ1 when two IRQ lines are available */ --#define MCI_IRQ1MASK \ -+#define MCI_IRQ_PIO_MASK \ - (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ - MCI_TXFIFOHALFEMPTYMASK) - -+#define MCI_IRQ_PIO_STM32_MASK \ -+ (MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK) -+ - #define NR_SG 128 - - #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" -@@ -204,19 +269,29 @@ struct mmci_host; - * @clkreg_enable: enable value for MMCICLOCK register - * @clkreg_8bit_bus_enable: enable value for 8 bit bus - * @clkreg_neg_edge_enable: enable value for inverted data/cmd output -+ * @cmdreg_cpsm_enable: enable value for CPSM -+ * @cmdreg_lrsp_crc: enable value for long response with crc -+ * @cmdreg_srsp_crc: enable value for short response with crc -+ * @cmdreg_srsp: enable value for short response without crc -+ * @cmdreg_stop: enable value for stop and abort transmission - * @datalength_bits: number of bits in the MMCIDATALENGTH register - * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY - * is asserted (likewise for RX) - * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY - * is asserted (likewise for RX) - * @data_cmd_enable: enable value for data commands. -- * @st_sdio: enable ST specific SDIO logic - * @st_clkdiv: true if using a ST-specific clock divider algorithm -+ * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm - * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl - * register - * @datactrl_mask_sdio: SDIO enable mask in datactrl register -+ * @datactrl_blksz: block size in power of two -+ * @datactrl_dpsm_enable: enable value for DPSM -+ * @datactrl_first: true if data must be setup before send command -+ * @datacnt_useless: true if you could not use datacnt register to read -+ * remaining data - * @pwrreg_powerup: power up value for MMCIPOWER register - * @f_max: maximum clk frequency supported by the controller. - * @signal_direction: input/out direction of bus signals can be indicated -@@ -233,53 +308,83 @@ struct mmci_host; - * @qcom_dml: enables qcom specific dma glue for dma transfers. - * @reversed_irq_handling: handle data irq before cmd irq. - * @mmcimask1: true if variant have a MMCIMASK1 register. -+ * @irq_pio_mask: bitmask used to manage interrupt pio transfert in mmcimask -+ * register - * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS - * register. - * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register -+ * @dma_lli: true if variant has dma link list feature. -+ * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size. -+ * @quirks: A bitmap of hardware quirks that require some special action. - */ - struct variant_data { - unsigned int clkreg; - unsigned int clkreg_enable; - unsigned int clkreg_8bit_bus_enable; - unsigned int clkreg_neg_edge_enable; -+ unsigned int cmdreg_cpsm_enable; -+ unsigned int cmdreg_lrsp_crc; -+ unsigned int cmdreg_srsp_crc; -+ unsigned int cmdreg_srsp; -+ unsigned int cmdreg_stop; - unsigned int datalength_bits; - unsigned int fifosize; - unsigned int fifohalfsize; - unsigned int data_cmd_enable; - unsigned int datactrl_mask_ddrmode; - unsigned int datactrl_mask_sdio; -- bool st_sdio; -- bool st_clkdiv; -- bool blksz_datactrl16; -- bool blksz_datactrl4; -+ unsigned int datactrl_blocksz; -+ unsigned int datactrl_dpsm_enable; -+ u8 datactrl_first:1; -+ u8 datacnt_useless:1; -+ u8 st_clkdiv:1; -+ u8 stm32_clkdiv:1; -+ u8 blksz_datactrl16:1; -+ u8 blksz_datactrl4:1; - u32 pwrreg_powerup; - u32 f_max; -- bool signal_direction; -- bool pwrreg_clkgate; -- bool busy_detect; -+ u8 signal_direction:1; -+ u8 pwrreg_clkgate:1; -+ u8 busy_detect:1; -+ u8 busy_timeout:1; - u32 busy_dpsm_flag; - u32 busy_detect_flag; - u32 busy_detect_mask; -- bool pwrreg_nopower; -- bool explicit_mclk_control; -- bool qcom_fifo; -- bool qcom_dml; -- bool reversed_irq_handling; -- bool mmcimask1; -+ u8 pwrreg_nopower:1; -+ u8 explicit_mclk_control:1; -+ u8 qcom_fifo:1; -+ u8 qcom_dml:1; -+ u8 reversed_irq_handling:1; -+ u8 mmcimask1:1; -+ unsigned int irq_pio_mask; - u32 start_err; - u32 opendrain; -+ u8 dma_lli:1; -+ u32 stm32_idmabsize_mask; -+ u32 quirks; - void (*init)(struct mmci_host *host); - }; - -+#define MMCI_QUIRK_STM32_DTMODE BIT(0) -+#define MMCI_QUIRK_ST_SDIO BIT(2) /* enable ST specific SDIO logic */ -+#define MMCI_QUIRK_STM32_VSWITCH BIT(3) -+ - /* mmci variant callbacks */ - struct mmci_host_ops { -- void (*dma_setup)(struct mmci_host *host); --}; -- --struct mmci_host_next { -- struct dma_async_tx_descriptor *dma_desc; -- struct dma_chan *dma_chan; -- s32 cookie; -+ int (*validate_data)(struct mmci_host *host, struct mmc_data *data); -+ int (*prep_data)(struct mmci_host *host, struct mmc_data *data, -+ bool next); -+ void (*unprep_data)(struct mmci_host *host, struct mmc_data *data, -+ int err); -+ void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); -+ int (*dma_setup)(struct mmci_host *host); -+ void (*dma_release)(struct mmci_host *host); -+ int (*dma_start)(struct mmci_host *host, unsigned int *datactrl); -+ void (*dma_finalize)(struct mmci_host *host, struct mmc_data *data); -+ void (*dma_error)(struct mmci_host *host); -+ void (*set_clkreg)(struct mmci_host *host, unsigned int desired); -+ void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); -+ int (*execute_tuning)(struct mmc_host *mmc, u32 opcode); - }; - - struct mmci_host { -@@ -287,10 +392,13 @@ struct mmci_host { - void __iomem *base; - struct mmc_request *mrq; - struct mmc_command *cmd; -+ struct mmc_command stop_abort; - struct mmc_data *data; - struct mmc_host *mmc; - struct clk *clk; -- bool singleirq; -+ u8 singleirq:1; -+ -+ struct reset_control *rst; - - spinlock_t lock; - -@@ -301,13 +409,15 @@ struct mmci_host { - u32 pwr_reg; - u32 pwr_reg_add; - u32 clk_reg; -+ u32 clk_reg_add; - u32 datactrl_reg; - u32 busy_status; - u32 mask1_reg; -- bool vqmmc_enabled; -+ u8 vqmmc_enabled:1; - struct mmci_platform_data *plat; - struct mmci_host_ops *ops; - struct variant_data *variant; -+ void *variant_priv; - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - struct pinctrl_state *pins_opendrain; -@@ -323,18 +433,25 @@ struct mmci_host { - unsigned int size; - int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain); - --#ifdef CONFIG_DMA_ENGINE -- /* DMA stuff */ -- struct dma_chan *dma_current; -- struct dma_chan *dma_rx_channel; -- struct dma_chan *dma_tx_channel; -- struct dma_async_tx_descriptor *dma_desc_current; -- struct mmci_host_next next_data; -- bool dma_in_progress; -+ u8 use_dma:1; -+ u8 dma_in_progress:1; -+ void *dma_priv; - --#define dma_inprogress(host) ((host)->dma_in_progress) --#else --#define dma_inprogress(host) (0) --#endif -+ s32 next_cookie; - }; - -+#define dma_inprogress(host) ((host)->dma_in_progress) -+ -+void mmci_write_clkreg(struct mmci_host *host, u32 clk); -+void mmci_write_pwrreg(struct mmci_host *host, u32 pwr); -+ -+int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, -+ bool next); -+void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data, -+ int err); -+void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); -+int mmci_dmae_setup(struct mmci_host *host); -+void mmci_dmae_release(struct mmci_host *host); -+int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); -+void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); -+void mmci_dmae_error(struct mmci_host *host); -diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c -index be3fab5..25d0a75 100644 ---- a/drivers/mmc/host/mmci_qcom_dml.c -+++ b/drivers/mmc/host/mmci_qcom_dml.c -@@ -119,19 +119,23 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name) - } - - /* Initialize the dml hardware connected to SD Card controller */ --static void qcom_dma_setup(struct mmci_host *host) -+static int qcom_dma_setup(struct mmci_host *host) - { - u32 config; - void __iomem *base; - int consumer_id, producer_id; - struct device_node *np = host->mmc->parent->of_node; - -+ if (mmci_dmae_setup(host)) -+ return -EINVAL; -+ - consumer_id = of_get_dml_pipe_index(np, "tx"); - producer_id = of_get_dml_pipe_index(np, "rx"); - - if (producer_id < 0 || consumer_id < 0) { - host->variant->qcom_dml = false; -- return; -+ mmci_dmae_release(host); -+ return -EINVAL; - } - - base = host->base + DML_OFFSET; -@@ -175,10 +179,19 @@ static void qcom_dma_setup(struct mmci_host *host) - - /* Make sure dml initialization is finished */ - mb(); -+ -+ return 0; - } - - static struct mmci_host_ops qcom_variant_ops = { -+ .prep_data = mmci_dmae_prep_data, -+ .unprep_data = mmci_dmae_unprep_data, -+ .get_next_data = mmci_dmae_get_next_data, - .dma_setup = qcom_dma_setup, -+ .dma_release = mmci_dmae_release, -+ .dma_start = mmci_dmae_start, -+ .dma_finalize = mmci_dmae_finalize, -+ .dma_error = mmci_dmae_error, - }; - - void qcom_variant_init(struct mmci_host *host) -diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c -new file mode 100644 -index 0000000..675d6f60 ---- /dev/null -+++ b/drivers/mmc/host/mmci_stm32_sdmmc.c -@@ -0,0 +1,429 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Ludovic.barre@st.com for STMicroelectronics. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mmci.h" -+ -+#define DLYB_CR 0x0 -+#define DLYB_CR_DEN BIT(0) -+#define DLYB_CR_SEN BIT(1) -+ -+#define DLYB_CFGR 0x4 -+#define DLYB_CFGR_SEL_MASK GENMASK(3, 0) -+#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8) -+#define DLYB_CFGR_LNG_MASK GENMASK(27, 16) -+#define DLYB_CFGR_LNGF BIT(31) -+ -+#define DLYB_NB_DELAY 11 -+#define DLYB_CFGR_SEL_MAX (DLYB_NB_DELAY + 1) -+#define DLYB_CFGR_UNIT_MAX 127 -+ -+#define SDMMC_LLI_BUF_LEN PAGE_SIZE -+#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) -+ -+struct sdmmc_lli_desc { -+ u32 idmalar; -+ u32 idmabase; -+ u32 idmasize; -+}; -+ -+struct sdmmc_idma { -+ dma_addr_t sg_dma; -+ void *sg_cpu; -+}; -+ -+struct sdmmc_dlyb { -+ void __iomem *base; -+ u32 unit; -+ u32 max; -+}; -+ -+static int sdmmc_idma_validate_data(struct mmci_host *host, -+ struct mmc_data *data) -+{ -+ struct scatterlist *sg; -+ int i; -+ -+ /* -+ * idma has constraints on idmabase & idmasize for each element -+ * excepted the last element which has no constraint on idmasize -+ */ -+ for_each_sg(data->sg, sg, data->sg_len - 1, i) { -+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) || -+ !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) { -+ dev_err(mmc_dev(host->mmc), -+ "unaligned scatterlist: ofst:%x length:%d\n", -+ data->sg->offset, data->sg->length); -+ return -EINVAL; -+ } -+ } -+ -+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) { -+ dev_err(mmc_dev(host->mmc), -+ "unaligned last scatterlist: ofst:%x length:%d\n", -+ data->sg->offset, data->sg->length); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int _sdmmc_idma_prep_data(struct mmci_host *host, -+ struct mmc_data *data) -+{ -+ int n_elem; -+ -+ n_elem = dma_map_sg(mmc_dev(host->mmc), -+ data->sg, -+ data->sg_len, -+ mmc_get_dma_dir(data)); -+ -+ if (!n_elem) { -+ dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int sdmmc_idma_prep_data(struct mmci_host *host, -+ struct mmc_data *data, bool next) -+{ -+ /* Check if job is already prepared. */ -+ if (!next && data->host_cookie == host->next_cookie) -+ return 0; -+ -+ return _sdmmc_idma_prep_data(host, data); -+} -+ -+static void sdmmc_idma_unprep_data(struct mmci_host *host, -+ struct mmc_data *data, int err) -+{ -+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ mmc_get_dma_dir(data)); -+} -+ -+static int sdmmc_idma_setup(struct mmci_host *host) -+{ -+ struct sdmmc_idma *idma; -+ -+ idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); -+ if (!idma) -+ return -ENOMEM; -+ -+ host->dma_priv = idma; -+ -+ if (host->variant->dma_lli) { -+ idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), -+ SDMMC_LLI_BUF_LEN, -+ &idma->sg_dma, GFP_KERNEL); -+ if (!idma->sg_cpu) { -+ dev_err(mmc_dev(host->mmc), -+ "Failed to alloc IDMA descriptor\n"); -+ return -ENOMEM; -+ } -+ host->mmc->max_segs = SDMMC_LLI_BUF_LEN / -+ sizeof(struct sdmmc_lli_desc); -+ host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask; -+ } else { -+ host->mmc->max_segs = 1; -+ host->mmc->max_seg_size = host->mmc->max_req_size; -+ } -+ -+ return 0; -+} -+ -+static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) -+ -+{ -+ struct sdmmc_idma *idma = host->dma_priv; -+ struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; -+ struct mmc_data *data = host->data; -+ struct scatterlist *sg; -+ int i; -+ -+ if (!host->variant->dma_lli || data->sg_len == 1) { -+ writel_relaxed(sg_dma_address(data->sg), -+ host->base + MMCI_STM32_IDMABASE0R); -+ writel_relaxed(MMCI_STM32_IDMAEN, -+ host->base + MMCI_STM32_IDMACTRLR); -+ return 0; -+ } -+ -+ for_each_sg(data->sg, sg, data->sg_len, i) { -+ desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc); -+ desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS -+ | MMCI_STM32_ABR; -+ desc[i].idmabase = sg_dma_address(sg); -+ desc[i].idmasize = sg_dma_len(sg); -+ } -+ -+ /* notice the end of link list */ -+ desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA; -+ -+ dma_wmb(); -+ writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR); -+ writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR); -+ writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R); -+ writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER); -+ writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN, -+ host->base + MMCI_STM32_IDMACTRLR); -+ -+ return 0; -+} -+ -+static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) -+{ -+ writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); -+} -+ -+static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) -+{ -+ unsigned int clk = 0, ddr = 0; -+ -+ if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 || -+ host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) -+ ddr = MCI_STM32_CLK_DDR; -+ -+ /* -+ * cclk = mclk / (2 * clkdiv) -+ * clkdiv 0 => bypass -+ * in ddr mode bypass is not possible -+ */ -+ if (desired) { -+ if (desired >= host->mclk && !ddr) { -+ host->cclk = host->mclk; -+ } else { -+ clk = DIV_ROUND_UP(host->mclk, 2 * desired); -+ if (clk > MCI_STM32_CLK_CLKDIV_MSK) -+ clk = MCI_STM32_CLK_CLKDIV_MSK; -+ host->cclk = host->mclk / (2 * clk); -+ } -+ } else { -+ /* -+ * while power-on phase the clock can't be define to 0, -+ * Only power-off and power-cyc deactivate the clock. -+ * if desired clock is 0, set max divider -+ */ -+ clk = MCI_STM32_CLK_CLKDIV_MSK; -+ host->cclk = host->mclk / (2 * clk); -+ } -+ -+ /* Set actual clock for debug */ -+ if (host->mmc->ios.power_mode == MMC_POWER_ON) -+ host->mmc->actual_clock = host->cclk; -+ else -+ host->mmc->actual_clock = 0; -+ -+ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) -+ clk |= MCI_STM32_CLK_WIDEBUS_4; -+ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) -+ clk |= MCI_STM32_CLK_WIDEBUS_8; -+ -+ clk |= MCI_STM32_CLK_HWFCEN; -+ clk |= host->clk_reg_add; -+ clk |= ddr; -+ -+ /* -+ * SDMMC_FBCK is selected when an external Delay Block is needed -+ * with SDR104. -+ */ -+ if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) { -+ clk |= MCI_STM32_CLK_BUSSPEED; -+ if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { -+ clk &= ~MCI_STM32_CLK_SEL_MSK; -+ clk |= MCI_STM32_CLK_SELFBCK; -+ } -+ } -+ -+ mmci_write_clkreg(host, clk); -+} -+ -+static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb) -+{ -+ if (!dlyb || !dlyb->base) -+ return; -+ -+ /* Output clock = Input clock */ -+ writel_relaxed(0, dlyb->base + DLYB_CR); -+} -+ -+static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) -+{ -+ struct mmc_ios ios = host->mmc->ios; -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ -+ pwr = host->pwr_reg_add; -+ -+ sdmmc_dlyb_input_ck(dlyb); -+ -+ if (ios.power_mode == MMC_POWER_OFF) { -+ /* Only a reset could power-off sdmmc */ -+ reset_control_assert(host->rst); -+ udelay(2); -+ reset_control_deassert(host->rst); -+ -+ /* -+ * 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. -+ */ -+ mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr); -+ } else if (ios.power_mode == MMC_POWER_ON) { -+ /* -+ * After power-off (reset): the irq mask defined in probe -+ * functionis lost -+ * ault irq mask (probe) must be activated -+ */ -+ writel(MCI_IRQENABLE | host->variant->start_err, -+ host->base + MMCIMASK0); -+ -+ /* -+ * After a power-cycle state, we must set the SDMMC in -+ * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are -+ * driven high. Then we can set the SDMMC to Power-on state -+ */ -+ mmci_write_pwrreg(host, MCI_PWR_OFF | pwr); -+ mdelay(1); -+ mmci_write_pwrreg(host, MCI_PWR_ON | pwr); -+ } -+} -+ -+static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, -+ int unit, int phase, bool sampler) -+{ -+ u32 cfgr; -+ -+ writel_relaxed(DLYB_CR_SEN | DLYB_CR_DEN, dlyb->base + DLYB_CR); -+ -+ cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) | -+ FIELD_PREP(DLYB_CFGR_SEL_MASK, phase); -+ writel_relaxed(cfgr, dlyb->base + DLYB_CFGR); -+ -+ if (!sampler) -+ writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); -+} -+ -+static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) -+{ -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ u32 cfgr; -+ int i, lng, ret; -+ -+ for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { -+ sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true); -+ -+ ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, -+ (cfgr & DLYB_CFGR_LNGF), -+ 1, 1000); -+ if (ret) { -+ dev_warn(mmc_dev(host->mmc), -+ "delay line cfg timeout unit:%d cfgr:%d\n", -+ i, cfgr); -+ continue; -+ } -+ -+ lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr); -+ if (lng < BIT(DLYB_NB_DELAY) && lng > 0) -+ break; -+ } -+ -+ if (i > DLYB_CFGR_UNIT_MAX) -+ return -EINVAL; -+ -+ dlyb->unit = i; -+ dlyb->max = __fls(lng); -+ -+ return 0; -+} -+ -+static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) -+{ -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ int cur_len = 0, max_len = 0, end_of_len = 0; -+ int phase; -+ -+ for (phase = 0; phase <= dlyb->max; phase++) { -+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); -+ -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) { -+ cur_len = 0; -+ } else { -+ cur_len++; -+ if (cur_len > max_len) { -+ max_len = cur_len; -+ end_of_len = phase; -+ } -+ } -+ } -+ -+ if (!max_len) { -+ dev_err(mmc_dev(host->mmc), "no tuning point found\n"); -+ return -EINVAL; -+ } -+ -+ phase = end_of_len - max_len / 2; -+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); -+ -+ dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", -+ dlyb->unit, dlyb->max, phase); -+ -+ return 0; -+} -+ -+static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct mmci_host *host = mmc_priv(mmc); -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ -+ if (!dlyb || !dlyb->base) -+ return -EINVAL; -+ -+ if (sdmmc_dlyb_lng_tuning(host)) -+ return -EINVAL; -+ -+ return sdmmc_dlyb_phase_tuning(host, opcode); -+} -+ -+static struct mmci_host_ops sdmmc_variant_ops = { -+ .validate_data = sdmmc_idma_validate_data, -+ .prep_data = sdmmc_idma_prep_data, -+ .unprep_data = sdmmc_idma_unprep_data, -+ .dma_setup = sdmmc_idma_setup, -+ .dma_start = sdmmc_idma_start, -+ .dma_finalize = sdmmc_idma_finalize, -+ .set_clkreg = mmci_sdmmc_set_clkreg, -+ .set_pwrreg = mmci_sdmmc_set_pwrreg, -+ .execute_tuning = sdmmc_execute_tuning, -+}; -+ -+void sdmmc_variant_init(struct mmci_host *host) -+{ -+ struct device_node *np = host->mmc->parent->of_node; -+ void __iomem *base_dlyb; -+ struct sdmmc_dlyb *dlyb; -+ -+ host->ops = &sdmmc_variant_ops; -+ -+ base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); -+ if (IS_ERR(base_dlyb)) -+ return; -+ -+ dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL); -+ if (!dlyb) -+ return; -+ -+ dlyb->base = base_dlyb; -+ host->variant_priv = dlyb; -+} -diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig -index 5fc9a1b..70f26c2 100644 ---- a/drivers/mtd/nand/raw/Kconfig -+++ b/drivers/mtd/nand/raw/Kconfig -@@ -561,4 +561,13 @@ config MTD_NAND_TEGRA - is supported. Extra OOB bytes when using HW ECC are currently - not supported. - -+config MTD_NAND_STM32_FMC2 -+ tristate "Support for NAND controller on STM32MP SoCs" -+ depends on MACH_STM32MP157 || COMPILE_TEST -+ 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. -+ - endif # MTD_NAND -diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile -index d5a5f98..4ef7559 100644 ---- a/drivers/mtd/nand/raw/Makefile -+++ b/drivers/mtd/nand/raw/Makefile -@@ -57,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ - obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o - obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o - obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o -+obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o - - nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o - nand-objs += nand_amd.o -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 0000000..ce1a15a ---- /dev/null -+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c -@@ -0,0 +1,2041 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 -+ * Author: Christophe Kerello -+ */ -+ -+#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 -+ -+/* BCHDSRx registers length */ -+#define FMC2_BCHDSRS_LEN 20 -+ -+/* HECCR length */ -+#define FMC2_HECCR_LEN 4 -+ -+/* Max requests done for a 8k nand page size */ -+#define FMC2_MAX_SG 16 -+ -+/* Max chip enable */ -+#define FMC2_MAX_CE 2 -+ -+/* Max ecc buffer length */ -+#define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG) -+ -+/* 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_ISR 0x184 -+#define FMC2_ICR 0x188 -+#define FMC2_CSQCR 0x200 -+#define FMC2_CSQCFGR1 0x204 -+#define FMC2_CSQCFGR2 0x208 -+#define FMC2_CSQCFGR3 0x20c -+#define FMC2_CSQAR1 0x210 -+#define FMC2_CSQAR2 0x214 -+#define FMC2_CSQIER 0x220 -+#define FMC2_CSQISR 0x224 -+#define FMC2_CSQICR 0x228 -+#define FMC2_CSQEMSR 0x230 -+#define FMC2_BCHIER 0x250 -+#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_ISR */ -+#define FMC2_ISR_IHLF BIT(1) -+ -+/* Register: FMC2_ICR */ -+#define FMC2_ICR_CIHLF BIT(1) -+ -+/* Register: FMC2_CSQCR */ -+#define FMC2_CSQCR_CSQSTART BIT(0) -+ -+/* Register: FMC2_CSQCFGR1 */ -+#define FMC2_CSQCFGR1_CMD2EN BIT(1) -+#define FMC2_CSQCFGR1_DMADEN BIT(2) -+#define FMC2_CSQCFGR1_ACYNBR(x) (((x) & 0x7) << 4) -+#define FMC2_CSQCFGR1_CMD1(x) (((x) & 0xff) << 8) -+#define FMC2_CSQCFGR1_CMD2(x) (((x) & 0xff) << 16) -+#define FMC2_CSQCFGR1_CMD1T BIT(24) -+#define FMC2_CSQCFGR1_CMD2T BIT(25) -+ -+/* Register: FMC2_CSQCFGR2 */ -+#define FMC2_CSQCFGR2_SQSDTEN BIT(0) -+#define FMC2_CSQCFGR2_RCMD2EN BIT(1) -+#define FMC2_CSQCFGR2_DMASEN BIT(2) -+#define FMC2_CSQCFGR2_RCMD1(x) (((x) & 0xff) << 8) -+#define FMC2_CSQCFGR2_RCMD2(x) (((x) & 0xff) << 16) -+#define FMC2_CSQCFGR2_RCMD1T BIT(24) -+#define FMC2_CSQCFGR2_RCMD2T BIT(25) -+ -+/* Register: FMC2_CSQCFGR3 */ -+#define FMC2_CSQCFGR3_SNBR(x) (((x) & 0x1f) << 8) -+#define FMC2_CSQCFGR3_AC1T BIT(16) -+#define FMC2_CSQCFGR3_AC2T BIT(17) -+#define FMC2_CSQCFGR3_AC3T BIT(18) -+#define FMC2_CSQCFGR3_AC4T BIT(19) -+#define FMC2_CSQCFGR3_AC5T BIT(20) -+#define FMC2_CSQCFGR3_SDT BIT(21) -+#define FMC2_CSQCFGR3_RAC1T BIT(22) -+#define FMC2_CSQCFGR3_RAC2T BIT(23) -+ -+/* Register: FMC2_CSQCAR1 */ -+#define FMC2_CSQCAR1_ADDC1(x) (((x) & 0xff) << 0) -+#define FMC2_CSQCAR1_ADDC2(x) (((x) & 0xff) << 8) -+#define FMC2_CSQCAR1_ADDC3(x) (((x) & 0xff) << 16) -+#define FMC2_CSQCAR1_ADDC4(x) (((x) & 0xff) << 24) -+ -+/* Register: FMC2_CSQCAR2 */ -+#define FMC2_CSQCAR2_ADDC5(x) (((x) & 0xff) << 0) -+#define FMC2_CSQCAR2_NANDCEN(x) (((x) & 0x3) << 10) -+#define FMC2_CSQCAR2_SAO(x) (((x) & 0xffff) << 16) -+ -+/* Register: FMC2_CSQIER */ -+#define FMC2_CSQIER_TCIE BIT(0) -+ -+/* Register: FMC2_CSQICR */ -+#define FMC2_CSQICR_CLEAR_IRQ GENMASK(4, 0) -+ -+/* Register: FMC2_CSQEMSR */ -+#define FMC2_CSQEMSR_SEM GENMASK(15, 0) -+ -+/* Register: FMC2_BCHIER */ -+#define FMC2_BCHIER_DERIE BIT(1) -+#define FMC2_BCHIER_EPBRIE BIT(4) -+ -+/* Register: FMC2_BCHICR */ -+#define FMC2_BCHICR_CLEAR_IRQ GENMASK(4, 0) -+ -+/* Register: FMC2_BCHDSR0 */ -+#define FMC2_BCHDSR0_DUE BIT(0) -+#define FMC2_BCHDSR0_DEF BIT(1) -+#define FMC2_BCHDSR0_DEN_MASK GENMASK(7, 4) -+#define FMC2_BCHDSR0_DEN_SHIFT 4 -+ -+/* Register: FMC2_BCHDSR1 */ -+#define FMC2_BCHDSR1_EBP1_MASK GENMASK(12, 0) -+#define FMC2_BCHDSR1_EBP2_MASK GENMASK(28, 16) -+#define FMC2_BCHDSR1_EBP2_SHIFT 16 -+ -+/* Register: FMC2_BCHDSR2 */ -+#define FMC2_BCHDSR2_EBP3_MASK GENMASK(12, 0) -+#define FMC2_BCHDSR2_EBP4_MASK GENMASK(28, 16) -+#define FMC2_BCHDSR2_EBP4_SHIFT 16 -+ -+/* Register: FMC2_BCHDSR3 */ -+#define FMC2_BCHDSR3_EBP5_MASK GENMASK(12, 0) -+#define FMC2_BCHDSR3_EBP6_MASK GENMASK(28, 16) -+#define FMC2_BCHDSR3_EBP6_SHIFT 16 -+ -+/* Register: FMC2_BCHDSR4 */ -+#define FMC2_BCHDSR4_EBP7_MASK GENMASK(12, 0) -+#define FMC2_BCHDSR4_EBP8_MASK GENMASK(28, 16) -+#define FMC2_BCHDSR4_EBP8_SHIFT 16 -+ -+enum stm32_fmc2_ecc { -+ FMC2_ECC_HAM = 1, -+ FMC2_ECC_BCH4 = 4, -+ FMC2_ECC_BCH8 = 8 -+}; -+ -+enum stm32_fmc2_irq_state { -+ FMC2_IRQ_UNKNOWN = 0, -+ FMC2_IRQ_BCH, -+ FMC2_IRQ_SEQ -+}; -+ -+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_controller base; -+ struct stm32_fmc2_nand nand; -+ struct device *dev; -+ 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]; -+ phys_addr_t io_phys_addr; -+ phys_addr_t data_phys_addr[FMC2_MAX_CE]; -+ struct clk *clk; -+ u8 irq_state; -+ -+ struct dma_chan *dma_tx_ch; -+ struct dma_chan *dma_rx_ch; -+ struct dma_chan *dma_ecc_ch; -+ struct sg_table dma_data_sg; -+ struct sg_table dma_ecc_sg; -+ u8 *ecc_buf; -+ int dma_ecc_len; -+ -+ struct completion complete; -+ struct completion dma_data_complete; -+ struct completion dma_ecc_complete; -+ -+ u8 cs_assigned; -+ int cs_sel; -+}; -+ -+static inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_controller *base) -+{ -+ return container_of(base, struct stm32_fmc2_nfc, base); -+} -+ -+/* Enable irq sources in case of the sequencer is used */ -+static inline void stm32_fmc2_enable_seq_irq(struct stm32_fmc2_nfc *fmc2) -+{ -+ u32 csqier = readl_relaxed(fmc2->io_base + FMC2_CSQIER); -+ -+ csqier |= FMC2_CSQIER_TCIE; -+ -+ fmc2->irq_state = FMC2_IRQ_SEQ; -+ -+ writel_relaxed(csqier, fmc2->io_base + FMC2_CSQIER); -+} -+ -+/* Disable irq sources in case of the sequencer is used */ -+static inline void stm32_fmc2_disable_seq_irq(struct stm32_fmc2_nfc *fmc2) -+{ -+ u32 csqier = readl_relaxed(fmc2->io_base + FMC2_CSQIER); -+ -+ csqier &= ~FMC2_CSQIER_TCIE; -+ -+ writel_relaxed(csqier, fmc2->io_base + FMC2_CSQIER); -+ -+ fmc2->irq_state = FMC2_IRQ_UNKNOWN; -+} -+ -+/* Clear irq sources in case of the sequencer is used */ -+static inline void stm32_fmc2_clear_seq_irq(struct stm32_fmc2_nfc *fmc2) -+{ -+ writel_relaxed(FMC2_CSQICR_CLEAR_IRQ, fmc2->io_base + FMC2_CSQICR); -+} -+ -+/* Enable irq sources in case of bch is used */ -+static inline void stm32_fmc2_enable_bch_irq(struct stm32_fmc2_nfc *fmc2, -+ int mode) -+{ -+ u32 bchier = readl_relaxed(fmc2->io_base + FMC2_BCHIER); -+ -+ if (mode == NAND_ECC_WRITE) -+ bchier |= FMC2_BCHIER_EPBRIE; -+ else -+ bchier |= FMC2_BCHIER_DERIE; -+ -+ fmc2->irq_state = FMC2_IRQ_BCH; -+ -+ writel_relaxed(bchier, fmc2->io_base + FMC2_BCHIER); -+} -+ -+/* Disable irq sources in case of bch is used */ -+static inline void stm32_fmc2_disable_bch_irq(struct stm32_fmc2_nfc *fmc2) -+{ -+ u32 bchier = readl_relaxed(fmc2->io_base + FMC2_BCHIER); -+ -+ bchier &= ~FMC2_BCHIER_DERIE; -+ bchier &= ~FMC2_BCHIER_EPBRIE; -+ -+ writel_relaxed(bchier, fmc2->io_base + FMC2_BCHIER); -+ -+ fmc2->irq_state = FMC2_IRQ_UNKNOWN; -+} -+ -+/* Clear irq sources in case of bch is used */ -+static inline void stm32_fmc2_clear_bch_irq(struct stm32_fmc2_nfc *fmc2) -+{ -+ writel_relaxed(FMC2_BCHICR_CLEAR_IRQ, fmc2->io_base + FMC2_BCHICR); -+} -+ -+/* -+ * 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); -+ u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ -+ pcr &= ~FMC2_PCR_ECCEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ if (chip->ecc.strength != FMC2_ECC_HAM) { -+ if (mode == NAND_ECC_WRITE) -+ pcr |= FMC2_PCR_WEN; -+ else -+ pcr &= ~FMC2_PCR_WEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ reinit_completion(&fmc2->complete); -+ stm32_fmc2_clear_bch_irq(fmc2); -+ stm32_fmc2_enable_bch_irq(fmc2, mode); -+ } -+ -+ pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ pcr |= FMC2_PCR_ECCEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+} -+ -+/* -+ * ECC Hamming calculation -+ * ECC is 3 bytes for 512 bytes of data (supports error correction up to -+ * max of 1-bit) -+ */ -+static inline void stm32_fmc2_ham_set_ecc(const u32 ecc_sta, u8 *ecc) -+{ -+ ecc[0] = ecc_sta; -+ ecc[1] = ecc_sta >> 8; -+ ecc[2] = ecc_sta >> 16; -+} -+ -+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 sr, heccr, pcr; -+ int ret; -+ -+ ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR, -+ sr, sr & FMC2_SR_NWRF, 10, 1000); -+ if (ret) { -+ dev_err(fmc2->dev, "ham timeout\n"); -+ return ret; -+ } -+ -+ heccr = readl_relaxed(fmc2->io_base + FMC2_HECCR); -+ -+ stm32_fmc2_ham_set_ecc(heccr, ecc); -+ -+ /* Disable ecc */ -+ pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ pcr &= ~FMC2_PCR_ECCEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ 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, pcr; -+ -+ /* Wait until the BCH code is ready */ -+ if (!wait_for_completion_timeout(&fmc2->complete, -+ msecs_to_jiffies(1000))) { -+ dev_err(fmc2->dev, "bch timeout\n"); -+ stm32_fmc2_disable_bch_irq(fmc2); -+ return -ETIMEDOUT; -+ } -+ -+ /* Read parity bits */ -+ bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR1); -+ ecc[0] = bchpbr; -+ ecc[1] = bchpbr >> 8; -+ ecc[2] = bchpbr >> 16; -+ ecc[3] = bchpbr >> 24; -+ -+ bchpbr = readl_relaxed(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_relaxed(fmc2->io_base + FMC2_BCHPBR3); -+ ecc[8] = bchpbr; -+ ecc[9] = bchpbr >> 8; -+ ecc[10] = bchpbr >> 16; -+ ecc[11] = bchpbr >> 24; -+ -+ bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR4); -+ ecc[12] = bchpbr; -+ } -+ -+ /* Disable ecc */ -+ pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ pcr &= ~FMC2_PCR_ECCEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ return 0; -+} -+ -+/* BCH algorithm correction */ -+static int stm32_fmc2_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) -+{ -+ u32 bchdsr0 = ecc_sta[0]; -+ u32 bchdsr1 = ecc_sta[1]; -+ u32 bchdsr2 = ecc_sta[2]; -+ u32 bchdsr3 = ecc_sta[3]; -+ u32 bchdsr4 = ecc_sta[4]; -+ u16 pos[8]; -+ int i, den; -+ unsigned int nb_errs = 0; -+ -+ /* 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_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 ecc_sta[5], pcr; -+ -+ /* Wait until the decoding error is ready */ -+ if (!wait_for_completion_timeout(&fmc2->complete, -+ msecs_to_jiffies(1000))) { -+ dev_err(fmc2->dev, "bch timeout\n"); -+ stm32_fmc2_disable_bch_irq(fmc2); -+ return -ETIMEDOUT; -+ } -+ -+ ecc_sta[0] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR0); -+ ecc_sta[1] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR1); -+ ecc_sta[2] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR2); -+ ecc_sta[3] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR3); -+ ecc_sta[4] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR4); -+ -+ /* Disable ecc */ -+ pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ pcr &= ~FMC2_PCR_ECCEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ return stm32_fmc2_bch_decode(chip->ecc.size, dat, ecc_sta); -+} -+ -+static int stm32_fmc2_read_page(struct mtd_info *mtd, -+ struct nand_chip *chip, u8 *buf, -+ int oob_required, int page) -+{ -+ int ret, 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->ecc.calc_buf; -+ u8 *ecc_code = chip->ecc.code_buf; -+ unsigned int max_bitflips = 0; -+ -+ ret = nand_read_page_op(chip, page, 0, NULL, 0); -+ if (ret) -+ return ret; -+ -+ 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) */ -+ ret = nand_change_read_column_op(chip, s * eccsize, p, -+ eccsize, false); -+ if (ret) -+ return ret; -+ -+ /* Read the corresponding ecc bytes */ -+ ret = nand_change_read_column_op(chip, i, ecc_code, -+ eccbytes, false); -+ if (ret) -+ return ret; -+ -+ /* Correct the data */ -+ stat = chip->ecc.correct(mtd, p, ecc_code, ecc_calc); -+ if (stat == -EBADMSG) -+ /* Check for empty pages with bitflips */ -+ stat = nand_check_erased_ecc_chunk(p, eccsize, -+ ecc_code, eccbytes, -+ NULL, 0, -+ eccstrength); -+ -+ if (stat < 0) { -+ mtd->ecc_stats.failed++; -+ } else { -+ mtd->ecc_stats.corrected += stat; -+ max_bitflips = max_t(unsigned int, max_bitflips, stat); -+ } -+ } -+ -+ /* Read oob */ -+ if (oob_required) { -+ ret = nand_change_read_column_op(chip, mtd->writesize, -+ chip->oob_poi, mtd->oobsize, -+ false); -+ if (ret) -+ return ret; -+ } -+ -+ return max_bitflips; -+} -+ -+/* Sequencer read/write configuration */ -+static void stm32_fmc2_rw_page_init(struct nand_chip *chip, int page, -+ int raw, bool write_data) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ struct mtd_info *mtd = nand_to_mtd(chip); -+ u32 csqcfgr1, csqcfgr2, csqcfgr3; -+ u32 csqar1, csqar2; -+ u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN; -+ u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ -+ if (write_data) -+ pcr |= FMC2_PCR_WEN; -+ else -+ pcr &= ~FMC2_PCR_WEN; -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ -+ /* -+ * - Set Program Page/Page Read command -+ * - Enable DMA request data -+ * - Set timings -+ */ -+ csqcfgr1 = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; -+ if (write_data) -+ csqcfgr1 |= FMC2_CSQCFGR1_CMD1(NAND_CMD_SEQIN); -+ else -+ csqcfgr1 |= FMC2_CSQCFGR1_CMD1(NAND_CMD_READ0) | -+ FMC2_CSQCFGR1_CMD2EN | -+ FMC2_CSQCFGR1_CMD2(NAND_CMD_READSTART) | -+ FMC2_CSQCFGR1_CMD2T; -+ -+ /* -+ * - Set Random Data Input/Random Data Read command -+ * - Enable the sequencer to access the Spare data area -+ * - Enable DMA request status decoding for read -+ * - Set timings -+ */ -+ if (write_data) -+ csqcfgr2 = FMC2_CSQCFGR2_RCMD1(NAND_CMD_RNDIN); -+ else -+ csqcfgr2 = FMC2_CSQCFGR2_RCMD1(NAND_CMD_RNDOUT) | -+ FMC2_CSQCFGR2_RCMD2EN | -+ FMC2_CSQCFGR2_RCMD2(NAND_CMD_RNDOUTSTART) | -+ FMC2_CSQCFGR2_RCMD1T | -+ FMC2_CSQCFGR2_RCMD2T; -+ if (!raw) { -+ csqcfgr2 |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; -+ csqcfgr2 |= FMC2_CSQCFGR2_SQSDTEN; -+ } -+ -+ /* -+ * - Set the number of sectors to be written -+ * - Set timings -+ */ -+ csqcfgr3 = FMC2_CSQCFGR3_SNBR(chip->ecc.steps - 1); -+ if (write_data) { -+ csqcfgr3 |= FMC2_CSQCFGR3_RAC2T; -+ if (chip->options & NAND_ROW_ADDR_3) -+ csqcfgr3 |= FMC2_CSQCFGR3_AC5T; -+ else -+ csqcfgr3 |= FMC2_CSQCFGR3_AC4T; -+ } -+ -+ /* -+ * Set the fourth first address cycles -+ * Byte 1 and byte 2 => column, we start at 0x0 -+ * Byte 3 and byte 4 => page -+ */ -+ csqar1 = FMC2_CSQCAR1_ADDC3(page); -+ csqar1 |= FMC2_CSQCAR1_ADDC4(page >> 8); -+ -+ /* -+ * - Set chip enable number -+ * - Set ecc byte offset in the spare area -+ * - Calculate the number of address cycles to be issued -+ * - Set byte 5 of address cycle if needed -+ */ -+ csqar2 = FMC2_CSQCAR2_NANDCEN(fmc2->cs_sel); -+ if (chip->options & NAND_BUSWIDTH_16) -+ csqar2 |= FMC2_CSQCAR2_SAO(ecc_offset >> 1); -+ else -+ csqar2 |= FMC2_CSQCAR2_SAO(ecc_offset); -+ if (chip->options & NAND_ROW_ADDR_3) { -+ csqcfgr1 |= FMC2_CSQCFGR1_ACYNBR(5); -+ csqar2 |= FMC2_CSQCAR2_ADDC5(page >> 16); -+ } else { -+ csqcfgr1 |= FMC2_CSQCFGR1_ACYNBR(4); -+ } -+ -+ writel_relaxed(csqcfgr1, fmc2->io_base + FMC2_CSQCFGR1); -+ writel_relaxed(csqcfgr2, fmc2->io_base + FMC2_CSQCFGR2); -+ writel_relaxed(csqcfgr3, fmc2->io_base + FMC2_CSQCFGR3); -+ writel_relaxed(csqar1, fmc2->io_base + FMC2_CSQAR1); -+ writel_relaxed(csqar2, fmc2->io_base + FMC2_CSQAR2); -+} -+ -+static void stm32_fmc2_dma_callback(void *arg) -+{ -+ complete((struct completion *)arg); -+} -+ -+/* Read/write data from/to a page */ -+static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, -+ int raw, bool write_data) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ struct dma_async_tx_descriptor *desc_data, *desc_ecc; -+ struct scatterlist *sg; -+ struct dma_chan *dma_ch = fmc2->dma_rx_ch; -+ enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE; -+ enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM; -+ u32 csqcr = readl_relaxed(fmc2->io_base + FMC2_CSQCR); -+ int eccsteps = chip->ecc.steps; -+ int eccsize = chip->ecc.size; -+ const u8 *p = buf; -+ int s, ret; -+ -+ /* Configure DMA data */ -+ if (write_data) { -+ dma_data_dir = DMA_TO_DEVICE; -+ dma_transfer_dir = DMA_MEM_TO_DEV; -+ dma_ch = fmc2->dma_tx_ch; -+ } -+ -+ for_each_sg(fmc2->dma_data_sg.sgl, sg, eccsteps, s) { -+ sg_set_buf(sg, p, eccsize); -+ p += eccsize; -+ } -+ -+ ret = dma_map_sg(fmc2->dev, fmc2->dma_data_sg.sgl, -+ eccsteps, dma_data_dir); -+ if (ret < 0) -+ return ret; -+ -+ desc_data = dmaengine_prep_slave_sg(dma_ch, fmc2->dma_data_sg.sgl, -+ eccsteps, dma_transfer_dir, -+ DMA_PREP_INTERRUPT); -+ if (!desc_data) { -+ ret = -ENOMEM; -+ goto err_unmap_data; -+ } -+ -+ reinit_completion(&fmc2->dma_data_complete); -+ reinit_completion(&fmc2->complete); -+ desc_data->callback = stm32_fmc2_dma_callback; -+ desc_data->callback_param = &fmc2->dma_data_complete; -+ ret = dma_submit_error(dmaengine_submit(desc_data)); -+ if (ret) -+ goto err_unmap_data; -+ -+ dma_async_issue_pending(dma_ch); -+ -+ if (!write_data && !raw) { -+ /* Configure DMA ecc status */ -+ p = fmc2->ecc_buf; -+ for_each_sg(fmc2->dma_ecc_sg.sgl, sg, eccsteps, s) { -+ sg_set_buf(sg, p, fmc2->dma_ecc_len); -+ p += fmc2->dma_ecc_len; -+ } -+ -+ ret = dma_map_sg(fmc2->dev, fmc2->dma_ecc_sg.sgl, -+ eccsteps, dma_data_dir); -+ if (ret < 0) -+ goto err_unmap_data; -+ -+ desc_ecc = dmaengine_prep_slave_sg(fmc2->dma_ecc_ch, -+ fmc2->dma_ecc_sg.sgl, -+ eccsteps, dma_transfer_dir, -+ DMA_PREP_INTERRUPT); -+ if (!desc_ecc) { -+ ret = -ENOMEM; -+ goto err_unmap_ecc; -+ } -+ -+ reinit_completion(&fmc2->dma_ecc_complete); -+ desc_ecc->callback = stm32_fmc2_dma_callback; -+ desc_ecc->callback_param = &fmc2->dma_ecc_complete; -+ ret = dma_submit_error(dmaengine_submit(desc_ecc)); -+ if (ret) -+ goto err_unmap_ecc; -+ -+ dma_async_issue_pending(fmc2->dma_ecc_ch); -+ } -+ -+ stm32_fmc2_clear_seq_irq(fmc2); -+ stm32_fmc2_enable_seq_irq(fmc2); -+ -+ /* Start the transfer */ -+ csqcr |= FMC2_CSQCR_CSQSTART; -+ writel_relaxed(csqcr, fmc2->io_base + FMC2_CSQCR); -+ -+ /* Wait end of sequencer transfer */ -+ if (!wait_for_completion_timeout(&fmc2->complete, -+ msecs_to_jiffies(1000))) { -+ dev_err(fmc2->dev, "seq timeout\n"); -+ stm32_fmc2_disable_seq_irq(fmc2); -+ dmaengine_terminate_all(dma_ch); -+ if (!write_data && !raw) -+ dmaengine_terminate_all(fmc2->dma_ecc_ch); -+ ret = -ETIMEDOUT; -+ goto err_unmap_ecc; -+ } -+ -+ /* Wait DMA data transfer completion */ -+ if (!wait_for_completion_timeout(&fmc2->dma_data_complete, -+ msecs_to_jiffies(500))) { -+ dev_err(fmc2->dev, "data DMA timeout\n"); -+ dmaengine_terminate_all(dma_ch); -+ ret = -ETIMEDOUT; -+ } -+ -+ /* Wait DMA ecc transfer completion */ -+ if (!write_data && !raw) { -+ if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete, -+ msecs_to_jiffies(500))) { -+ dev_err(fmc2->dev, "ecc DMA timeout\n"); -+ dmaengine_terminate_all(fmc2->dma_ecc_ch); -+ ret = -ETIMEDOUT; -+ } -+ } -+ -+err_unmap_ecc: -+ if (!write_data && !raw) -+ dma_unmap_sg(fmc2->dev, fmc2->dma_ecc_sg.sgl, -+ eccsteps, dma_data_dir); -+ -+err_unmap_data: -+ dma_unmap_sg(fmc2->dev, fmc2->dma_data_sg.sgl, eccsteps, dma_data_dir); -+ -+ return ret; -+} -+ -+static int stm32_fmc2_sequencer_write(struct nand_chip *chip, -+ const u8 *buf, int oob_required, -+ int page, int raw) -+{ -+ struct mtd_info *mtd = nand_to_mtd(chip); -+ int ret; -+ -+ /* Configure the sequencer */ -+ stm32_fmc2_rw_page_init(chip, page, raw, true); -+ -+ /* Write the page */ -+ ret = stm32_fmc2_xfer(chip, buf, raw, true); -+ if (ret) -+ return ret; -+ -+ /* Write oob */ -+ if (oob_required) { -+ ret = nand_change_write_column_op(chip, mtd->writesize, -+ chip->oob_poi, mtd->oobsize, -+ false); -+ if (ret) -+ return ret; -+ } -+ -+ return nand_prog_page_end_op(chip); -+} -+ -+static int stm32_fmc2_sequencer_write_page(struct mtd_info *mtd, -+ struct nand_chip *chip, -+ const u8 *buf, -+ int oob_required, -+ int page) -+{ -+ return stm32_fmc2_sequencer_write(chip, buf, oob_required, page, false); -+} -+ -+static int stm32_fmc2_sequencer_write_page_raw(struct mtd_info *mtd, -+ struct nand_chip *chip, -+ const u8 *buf, -+ int oob_required, -+ int page) -+{ -+ return stm32_fmc2_sequencer_write(chip, buf, oob_required, page, true); -+} -+ -+/* Get a status indicating which sectors have errors */ -+static inline u16 stm32_fmc2_get_mapping_status(struct stm32_fmc2_nfc *fmc2) -+{ -+ u32 csqemsr = readl_relaxed(fmc2->io_base + FMC2_CSQEMSR); -+ -+ return csqemsr & FMC2_CSQEMSR_SEM; -+} -+ -+static int stm32_fmc2_sequencer_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); -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps; -+ int eccstrength = chip->ecc.strength; -+ int i, s, eccsize = chip->ecc.size; -+ u32 *ecc_sta = (u32 *)fmc2->ecc_buf; -+ u16 sta_map = stm32_fmc2_get_mapping_status(fmc2); -+ unsigned int max_bitflips = 0; -+ -+ for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, dat += eccsize) { -+ int stat = 0; -+ -+ if (eccstrength == FMC2_ECC_HAM) { -+ /* Ecc_sta = FMC2_HECCR */ -+ if (sta_map & BIT(s)) { -+ stm32_fmc2_ham_set_ecc(*ecc_sta, &calc_ecc[i]); -+ stat = stm32_fmc2_ham_correct(mtd, dat, -+ &read_ecc[i], -+ &calc_ecc[i]); -+ } -+ ecc_sta++; -+ } else { -+ /* -+ * Ecc_sta[0] = FMC2_BCHDSR0 -+ * Ecc_sta[1] = FMC2_BCHDSR1 -+ * Ecc_sta[2] = FMC2_BCHDSR2 -+ * Ecc_sta[3] = FMC2_BCHDSR3 -+ * Ecc_sta[4] = FMC2_BCHDSR4 -+ */ -+ if (sta_map & BIT(s)) -+ stat = stm32_fmc2_bch_decode(eccsize, dat, -+ ecc_sta); -+ ecc_sta += 5; -+ } -+ -+ if (stat == -EBADMSG) -+ /* Check for empty pages with bitflips */ -+ stat = nand_check_erased_ecc_chunk(dat, eccsize, -+ &read_ecc[i], -+ 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); -+ } -+ } -+ -+ return max_bitflips; -+} -+ -+static int stm32_fmc2_sequencer_read_page(struct mtd_info *mtd, -+ struct nand_chip *chip, u8 *buf, -+ int oob_required, int page) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ u8 *ecc_calc = chip->ecc.calc_buf; -+ u8 *ecc_code = chip->ecc.code_buf; -+ u16 sta_map; -+ int ret; -+ -+ /* Configure the sequencer */ -+ stm32_fmc2_rw_page_init(chip, page, 0, false); -+ -+ /* Read the page */ -+ ret = stm32_fmc2_xfer(chip, buf, 0, false); -+ if (ret) -+ return ret; -+ -+ sta_map = stm32_fmc2_get_mapping_status(fmc2); -+ -+ /* Check if errors happen */ -+ if (likely(!sta_map)) { -+ if (oob_required) -+ return nand_change_read_column_op(chip, mtd->writesize, -+ chip->oob_poi, -+ mtd->oobsize, false); -+ -+ return 0; -+ } -+ -+ /* Read oob */ -+ ret = nand_change_read_column_op(chip, mtd->writesize, -+ chip->oob_poi, mtd->oobsize, false); -+ if (ret) -+ return ret; -+ -+ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, -+ chip->ecc.total); -+ if (ret) -+ return ret; -+ -+ /* Correct data */ -+ return chip->ecc.correct(mtd, buf, ecc_code, ecc_calc); -+} -+ -+static int stm32_fmc2_sequencer_read_page_raw(struct mtd_info *mtd, -+ struct nand_chip *chip, u8 *buf, -+ int oob_required, int page) -+{ -+ int ret; -+ -+ /* Configure the sequencer */ -+ stm32_fmc2_rw_page_init(chip, page, 1, false); -+ -+ /* Read the page */ -+ ret = stm32_fmc2_xfer(chip, buf, 1, false); -+ if (ret) -+ return ret; -+ -+ /* Read oob */ -+ if (oob_required) -+ return nand_change_read_column_op(chip, mtd->writesize, -+ chip->oob_poi, mtd->oobsize, -+ false); -+ -+ return 0; -+} -+ -+static irqreturn_t stm32_fmc2_irq(int irq, void *dev_id) -+{ -+ struct stm32_fmc2_nfc *fmc2 = (struct stm32_fmc2_nfc *)dev_id; -+ -+ if (fmc2->irq_state == FMC2_IRQ_SEQ) -+ /* Sequencer is used */ -+ stm32_fmc2_disable_seq_irq(fmc2); -+ else if (fmc2->irq_state == FMC2_IRQ_BCH) -+ /* BCH is used */ -+ stm32_fmc2_disable_bch_irq(fmc2); -+ -+ complete(&fmc2->complete); -+ -+ return IRQ_HANDLED; -+} -+ -+static void stm32_fmc2_set_buswidth_16(struct stm32_fmc2_nfc *fmc2, bool set) -+{ -+ u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ -+ pcr &= ~FMC2_PCR_PWID_MASK; -+ if (set) -+ pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+} -+ -+static void stm32_fmc2_read_data(struct nand_chip *chip, void *buf, -+ unsigned int len, bool force_8bit) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ void __iomem *io_addr_r = fmc2->data_base[fmc2->cs_sel]; -+ u8 *p = buf; -+ unsigned int i; -+ -+ if (force_8bit) -+ goto read_8bit; -+ -+ if (IS_ALIGNED(len, sizeof(u32))) { -+ u32 *p = buf; -+ -+ len /= sizeof(u32); -+ for (i = 0; i < len; i++) -+ p[i] = readl_relaxed(io_addr_r); -+ return; -+ } -+ -+ if (chip->options & NAND_BUSWIDTH_16) { -+ u16 *p = buf; -+ -+ len /= sizeof(u16); -+ for (i = 0; i < len; i++) -+ p[i] = readw_relaxed(io_addr_r); -+ return; -+ } -+ -+read_8bit: -+ if (chip->options & NAND_BUSWIDTH_16) -+ /* Reconfigure bus width to 8-bit */ -+ stm32_fmc2_set_buswidth_16(fmc2, false); -+ -+ for (i = 0; i < len; i++) -+ p[i] = readb_relaxed(io_addr_r); -+ -+ if (chip->options & NAND_BUSWIDTH_16) -+ /* Reconfigure bus width to 16-bit */ -+ stm32_fmc2_set_buswidth_16(fmc2, true); -+} -+ -+static void stm32_fmc2_write_data(struct nand_chip *chip, const void *buf, -+ unsigned int len, bool force_8bit) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ void __iomem *io_addr_w = fmc2->data_base[fmc2->cs_sel]; -+ const u8 *p = buf; -+ unsigned int i; -+ -+ if (force_8bit) -+ goto write_8bit; -+ -+ if (IS_ALIGNED(len, sizeof(u32))) { -+ const u32 *p = buf; -+ -+ len /= sizeof(u32); -+ for (i = 0; i < len; i++) -+ writel_relaxed(p[i], io_addr_w); -+ return; -+ } -+ -+ if (chip->options & NAND_BUSWIDTH_16) { -+ const u16 *p = buf; -+ -+ len /= sizeof(u16); -+ for (i = 0; i < len; i++) -+ writew_relaxed(p[i], io_addr_w); -+ return; -+ } -+ -+write_8bit: -+ if (chip->options & NAND_BUSWIDTH_16) -+ /* Reconfigure bus width to 8-bit */ -+ stm32_fmc2_set_buswidth_16(fmc2, false); -+ -+ for (i = 0; i < len; i++) -+ writeb_relaxed(p[i], io_addr_w); -+ -+ if (chip->options & NAND_BUSWIDTH_16) -+ /* Reconfigure bus width to 16-bit */ -+ stm32_fmc2_set_buswidth_16(fmc2, true); -+} -+ -+static int stm32_fmc2_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ const struct nand_sdr_timings *timings; -+ int ret; -+ u32 isr, sr; -+ -+ /* Check if there is no pending requests to the NAND flash */ -+ ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR, -+ sr, sr & FMC2_SR_NWRF, 1, 1000); -+ if (ret) { -+ dev_err(fmc2->dev, "Waitrdy timeout\n"); -+ return ret; -+ } -+ -+ /* Wait tWB before R/B# signal is low */ -+ timings = nand_get_sdr_timings(&chip->data_interface); -+ ndelay(PSEC_TO_NSEC(timings->tWB_max)); -+ -+ /* R/B# signal is low, clear high level flag */ -+ writel_relaxed(FMC2_ICR_CIHLF, fmc2->io_base + FMC2_ICR); -+ -+ /* Wait R/B# signal is high */ -+ return readl_relaxed_poll_timeout(fmc2->io_base + FMC2_ISR, -+ isr, isr & FMC2_ISR_IHLF, -+ 1, 1000 * timeout_ms); -+} -+ -+static int stm32_fmc2_exec_op(struct nand_chip *chip, -+ const struct nand_operation *op, -+ bool check_only) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ const struct nand_op_instr *instr = NULL; -+ unsigned int op_id, i; -+ int ret = 0; -+ -+ if (check_only) -+ return ret; -+ -+ for (op_id = 0; op_id < op->ninstrs; op_id++) { -+ instr = &op->instrs[op_id]; -+ -+ switch (instr->type) { -+ case NAND_OP_CMD_INSTR: -+ writeb_relaxed(instr->ctx.cmd.opcode, -+ fmc2->cmd_base[fmc2->cs_sel]); -+ break; -+ -+ case NAND_OP_ADDR_INSTR: -+ for (i = 0; i < instr->ctx.addr.naddrs; i++) -+ writeb_relaxed(instr->ctx.addr.addrs[i], -+ fmc2->addr_base[fmc2->cs_sel]); -+ break; -+ -+ case NAND_OP_DATA_IN_INSTR: -+ stm32_fmc2_read_data(chip, instr->ctx.data.buf.in, -+ instr->ctx.data.len, -+ instr->ctx.data.force_8bit); -+ break; -+ -+ case NAND_OP_DATA_OUT_INSTR: -+ stm32_fmc2_write_data(chip, instr->ctx.data.buf.out, -+ instr->ctx.data.len, -+ instr->ctx.data.force_8bit); -+ break; -+ -+ case NAND_OP_WAITRDY_INSTR: -+ ret = stm32_fmc2_waitrdy(chip, -+ instr->ctx.waitrdy.timeout_ms); -+ break; -+ } -+ } -+ -+ return ret; -+} -+ -+/* 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_relaxed(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_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ writel_relaxed(pmem, fmc2->io_base + FMC2_PMEM); -+ writel_relaxed(patt, fmc2->io_base + FMC2_PATT); -+} -+ -+/* Controller initialization */ -+static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2) -+{ -+ u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); -+ u32 bcr1 = readl_relaxed(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_relaxed(bcr1, fmc2->io_base + FMC2_BCR1); -+ writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); -+ writel_relaxed(FMC2_PMEM_DEFAULT, fmc2->io_base + FMC2_PMEM); -+ writel_relaxed(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_relaxed(fmc2->io_base + FMC2_PCR); -+ -+ /* Configure ecc algorithm (default configuration is Hamming) */ -+ pcr &= ~FMC2_PCR_ECCALG; -+ pcr &= ~FMC2_PCR_BCHECC; -+ if (chip->ecc.strength == FMC2_ECC_BCH8) { -+ pcr |= FMC2_PCR_ECCALG; -+ pcr |= FMC2_PCR_BCHECC; -+ } else if (chip->ecc.strength == FMC2_ECC_BCH4) { -+ pcr |= FMC2_PCR_ECCALG; -+ } -+ -+ /* Set buswidth */ -+ pcr &= ~FMC2_PCR_PWID_MASK; -+ if (chip->options & NAND_BUSWIDTH_16) -+ pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); -+ -+ /* Set ecc sector size */ -+ pcr &= ~FMC2_PCR_ECCSS_MASK; -+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512); -+ -+ writel_relaxed(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); -+ struct dma_slave_config dma_cfg; -+ -+ if (chipnr < 0 || chipnr >= nand->ncs) -+ return; -+ -+ if (nand->cs_used[chipnr] == fmc2->cs_sel) -+ return; -+ -+ fmc2->cs_sel = nand->cs_used[chipnr]; -+ -+ /* FMC2 setup routine */ -+ stm32_fmc2_setup(chip); -+ -+ /* Apply timings */ -+ stm32_fmc2_timings_init(chip); -+ -+ if (fmc2->dma_tx_ch && fmc2->dma_rx_ch) { -+ memset(&dma_cfg, 0, sizeof(dma_cfg)); -+ dma_cfg.src_addr = fmc2->data_phys_addr[fmc2->cs_sel]; -+ dma_cfg.dst_addr = fmc2->data_phys_addr[fmc2->cs_sel]; -+ dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ dma_cfg.src_maxburst = 32; -+ dma_cfg.dst_maxburst = 32; -+ -+ if (dmaengine_slave_config(fmc2->dma_tx_ch, &dma_cfg)) -+ dev_warn(fmc2->dev, "tx DMA engine slave config failed\n"); -+ -+ if (dmaengine_slave_config(fmc2->dma_rx_ch, &dma_cfg)) -+ dev_warn(fmc2->dev, "rx DMA engine slave config failed\n"); -+ } -+ -+ if (fmc2->dma_ecc_ch) { -+ /* -+ * Hamming: we read HECCR register -+ * BCH4/BCH8: we read BCHDSRSx registers -+ */ -+ memset(&dma_cfg, 0, sizeof(dma_cfg)); -+ dma_cfg.src_addr = fmc2->io_phys_addr; -+ dma_cfg.src_addr += chip->ecc.strength == FMC2_ECC_HAM ? -+ FMC2_HECCR : FMC2_BCHDSR0; -+ dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ -+ if (dmaengine_slave_config(fmc2->dma_ecc_ch, &dma_cfg)) -+ dev_warn(fmc2->dev, "ecc DMA engine slave config failed\n"); -+ -+ /* Calculate ecc length needed for one sector */ -+ fmc2->dma_ecc_len = chip->ecc.strength == FMC2_ECC_HAM ? -+ FMC2_HECCR_LEN : FMC2_BCHDSRS_LEN; -+ } -+} -+ -+/* 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 = NSEC_PER_SEC / (hclk / 1000); -+ 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; -+ -+ /* -+ * tWAIT > tRP -+ * tWAIT > tWP -+ * tWAIT > tREA + tIO -+ */ -+ 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 -+ * 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); -+ 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 = 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; -+ 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); -+ timing = DIV_ROUND_UP(thold_mem, hclkp); -+ tims->thold_mem = clamp_val(timing, 1, 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); -+ timing = DIV_ROUND_UP(tset_att, hclkp); -+ tims->tset_att = clamp_val(timing, 1, 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 = 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; -+ 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); -+ 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, -+ 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; -+} -+ -+/* DMA configuration */ -+static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) -+{ -+ int ret; -+ -+ fmc2->dma_tx_ch = dma_request_slave_channel(fmc2->dev, "tx"); -+ fmc2->dma_rx_ch = dma_request_slave_channel(fmc2->dev, "rx"); -+ fmc2->dma_ecc_ch = dma_request_slave_channel(fmc2->dev, "ecc"); -+ -+ if (!fmc2->dma_tx_ch || !fmc2->dma_rx_ch || !fmc2->dma_ecc_ch) { -+ dev_warn(fmc2->dev, "DMAs not defined in the device tree, manual mode is used\n"); -+ return 0; -+ } -+ -+ ret = sg_alloc_table(&fmc2->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); -+ if (ret) -+ return ret; -+ -+ /* Allocate a buffer to store ecc status registers */ -+ fmc2->ecc_buf = devm_kzalloc(fmc2->dev, FMC2_MAX_ECC_BUF_LEN, -+ GFP_KERNEL); -+ if (!fmc2->ecc_buf) -+ return -ENOMEM; -+ -+ ret = sg_alloc_table(&fmc2->dma_data_sg, FMC2_MAX_SG, GFP_KERNEL); -+ if (ret) -+ return ret; -+ -+ init_completion(&fmc2->dma_data_complete); -+ init_completion(&fmc2->dma_ecc_complete); -+ -+ return 0; -+} -+ -+/* NAND callbacks setup */ -+static void stm32_fmc2_nand_callbacks_setup(struct nand_chip *chip) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ -+ /* -+ * Specific callbacks to read/write a page depending on -+ * the mode (manual/sequencer) and the algo used (Hamming, BCH). -+ */ -+ if (fmc2->dma_tx_ch && fmc2->dma_rx_ch && fmc2->dma_ecc_ch) { -+ /* DMA => use sequencer mode callbacks */ -+ chip->ecc.correct = stm32_fmc2_sequencer_correct; -+ chip->ecc.write_page = stm32_fmc2_sequencer_write_page; -+ chip->ecc.read_page = stm32_fmc2_sequencer_read_page; -+ chip->ecc.write_page_raw = stm32_fmc2_sequencer_write_page_raw; -+ chip->ecc.read_page_raw = stm32_fmc2_sequencer_read_page_raw; -+ } else { -+ /* No DMA => use manual mode callbacks */ -+ chip->ecc.hwctl = stm32_fmc2_hwctl; -+ 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.options |= NAND_ECC_GENERIC_ERASED_CHECK; -+ } else { -+ /* BCH is used */ -+ chip->ecc.calculate = stm32_fmc2_bch_calculate; -+ chip->ecc.correct = stm32_fmc2_bch_correct; -+ chip->ecc.read_page = stm32_fmc2_read_page; -+ } -+ } -+ -+ /* Specific configurations depending on the algo used */ -+ if (chip->ecc.strength == FMC2_ECC_HAM) -+ chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3; -+ else 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 layout */ -+static int stm32_fmc2_nand_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ struct nand_chip *chip = mtd_to_nand(mtd); -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ -+ if (section) -+ return -ERANGE; -+ -+ oobregion->length = ecc->total; -+ oobregion->offset = FMC2_BBM_LEN; -+ -+ return 0; -+} -+ -+static int stm32_fmc2_nand_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ struct nand_chip *chip = mtd_to_nand(mtd); -+ struct nand_ecc_ctrl *ecc = &chip->ecc; -+ -+ if (section) -+ return -ERANGE; -+ -+ oobregion->length = mtd->oobsize - ecc->total - FMC2_BBM_LEN; -+ oobregion->offset = ecc->total + FMC2_BBM_LEN; -+ -+ return 0; -+} -+ -+const struct mtd_ooblayout_ops stm32_fmc2_nand_ooblayout_ops = { -+ .ecc = stm32_fmc2_nand_ooblayout_ecc, -+ .free = stm32_fmc2_nand_ooblayout_free, -+}; -+ -+/* 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 controller ops */ -+static int stm32_fmc2_attach_chip(struct nand_chip *chip) -+{ -+ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); -+ struct mtd_info *mtd = nand_to_mtd(chip); -+ int 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) { -+ dev_err(fmc2->dev, "nand_ecc_mode is not well defined in the DT\n"); -+ return -EINVAL; -+ } -+ -+ ret = nand_ecc_choose_conf(chip, &stm32_fmc2_ecc_caps, -+ mtd->oobsize - FMC2_BBM_LEN); -+ if (ret) { -+ dev_err(fmc2->dev, "no valid ECC settings set\n"); -+ return ret; -+ } -+ -+ if (mtd->writesize / chip->ecc.size > FMC2_MAX_SG) { -+ dev_err(fmc2->dev, "nand page size is not supported\n"); -+ return -EINVAL; -+ } -+ -+ 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 */ -+ mtd_set_ooblayout(mtd, &stm32_fmc2_nand_ooblayout_ops); -+ -+ /* Configure bus width to 16-bit */ -+ if (chip->options & NAND_BUSWIDTH_16) -+ stm32_fmc2_set_buswidth_16(fmc2, true); -+ -+ return 0; -+} -+ -+static const struct nand_controller_ops stm32_fmc2_nand_controller_ops = { -+ .attach_chip = stm32_fmc2_attach_chip, -+}; -+ -+/* FMC2 probe */ -+static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2, -+ struct device_node *dn) -+{ -+ struct stm32_fmc2_nand *nand = &fmc2->nand; -+ u32 cs; -+ int ret, i; -+ -+ if (!of_get_property(dn, "reg", &nand->ncs)) -+ return -EINVAL; -+ -+ nand->ncs /= sizeof(u32); -+ if (!nand->ncs) { -+ dev_err(fmc2->dev, "invalid reg property size\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < nand->ncs; i++) { -+ ret = of_property_read_u32_index(dn, "reg", i, &cs); -+ if (ret) { -+ dev_err(fmc2->dev, "could not retrieve reg property: %d\n", -+ ret); -+ return ret; -+ } -+ -+ if (cs > FMC2_MAX_CE) { -+ dev_err(fmc2->dev, "invalid reg value: %d\n", cs); -+ return -EINVAL; -+ } -+ -+ if (fmc2->cs_assigned & BIT(cs)) { -+ dev_err(fmc2->dev, "cs already assigned: %d\n", cs); -+ return -EINVAL; -+ } -+ -+ fmc2->cs_assigned |= BIT(cs); -+ nand->cs_used[i] = cs; -+ } -+ -+ nand_set_flash_node(&nand->chip, dn); -+ -+ return 0; -+} -+ -+static int stm32_fmc2_parse_dt(struct stm32_fmc2_nfc *fmc2) -+{ -+ struct device_node *dn = fmc2->dev->of_node; -+ struct device_node *child; -+ int nchips = of_get_child_count(dn); -+ int ret = 0; -+ -+ if (!nchips) { -+ dev_err(fmc2->dev, "NAND chip not defined\n"); -+ return -EINVAL; -+ } -+ -+ if (nchips > 1) { -+ dev_err(fmc2->dev, "too many NAND chips defined\n"); -+ return -EINVAL; -+ } -+ -+ for_each_child_of_node(dn, child) { -+ ret = stm32_fmc2_parse_child(fmc2, child); -+ if (ret < 0) { -+ of_node_put(child); -+ return ret; -+ } -+ } -+ -+ return ret; -+} -+ -+static int stm32_fmc2_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct reset_control *rstc; -+ struct stm32_fmc2_nfc *fmc2; -+ struct stm32_fmc2_nand *nand; -+ struct resource *res; -+ struct mtd_info *mtd; -+ struct nand_chip *chip; -+ int chip_cs, mem_region, ret, irq; -+ -+ fmc2 = devm_kzalloc(dev, sizeof(*fmc2), GFP_KERNEL); -+ if (!fmc2) -+ return -ENOMEM; -+ -+ fmc2->dev = dev; -+ nand_controller_init(&fmc2->base); -+ fmc2->base.ops = &stm32_fmc2_nand_controller_ops; -+ -+ ret = stm32_fmc2_parse_dt(fmc2); -+ if (ret) -+ return ret; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ fmc2->io_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(fmc2->io_base)) -+ return PTR_ERR(fmc2->io_base); -+ -+ fmc2->io_phys_addr = res->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; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, mem_region); -+ fmc2->data_base[chip_cs] = devm_ioremap_resource(dev, res); -+ if (IS_ERR(fmc2->data_base[chip_cs])) -+ return PTR_ERR(fmc2->data_base[chip_cs]); -+ -+ fmc2->data_phys_addr[chip_cs] = res->start; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, -+ mem_region + 1); -+ fmc2->cmd_base[chip_cs] = devm_ioremap_resource(dev, res); -+ if (IS_ERR(fmc2->cmd_base[chip_cs])) -+ return PTR_ERR(fmc2->cmd_base[chip_cs]); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, -+ mem_region + 2); -+ fmc2->addr_base[chip_cs] = devm_ioremap_resource(dev, res); -+ if (IS_ERR(fmc2->addr_base[chip_cs])) -+ return PTR_ERR(fmc2->addr_base[chip_cs]); -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ if (irq != -EPROBE_DEFER) -+ dev_err(dev, "IRQ error missing or invalid\n"); -+ return irq; -+ } -+ -+ ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0, -+ dev_name(dev), fmc2); -+ if (ret) { -+ dev_err(dev, "failed to request irq\n"); -+ return ret; -+ } -+ -+ init_completion(&fmc2->complete); -+ -+ fmc2->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(fmc2->clk)) -+ return PTR_ERR(fmc2->clk); -+ -+ ret = clk_prepare_enable(fmc2->clk); -+ if (ret) { -+ dev_err(dev, "can not enable the clock\n"); -+ return ret; -+ } -+ -+ rstc = devm_reset_control_get(dev, NULL); -+ if (!IS_ERR(rstc)) { -+ reset_control_assert(rstc); -+ reset_control_deassert(rstc); -+ } -+ -+ /* DMA setup */ -+ ret = stm32_fmc2_dma_setup(fmc2); -+ if (ret) -+ return ret; -+ -+ /* FMC2 init routine */ -+ stm32_fmc2_init(fmc2); -+ -+ nand = &fmc2->nand; -+ chip = &nand->chip; -+ mtd = nand_to_mtd(chip); -+ mtd->dev.parent = dev; -+ -+ chip->controller = &fmc2->base; -+ chip->exec_op = stm32_fmc2_exec_op; -+ chip->select_chip = stm32_fmc2_select_chip; -+ chip->setup_data_interface = stm32_fmc2_setup_interface; -+ 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(mtd, nand->ncs); -+ if (ret) -+ goto err_scan; -+ -+ ret = mtd_device_register(mtd, NULL, 0); -+ if (ret) -+ goto err_device_register; -+ -+ platform_set_drvdata(pdev, fmc2); -+ -+ return 0; -+ -+err_device_register: -+ nand_cleanup(chip); -+ -+err_scan: -+ if (fmc2->dma_ecc_ch) -+ dma_release_channel(fmc2->dma_ecc_ch); -+ if (fmc2->dma_tx_ch) -+ dma_release_channel(fmc2->dma_tx_ch); -+ if (fmc2->dma_rx_ch) -+ dma_release_channel(fmc2->dma_rx_ch); -+ -+ sg_free_table(&fmc2->dma_data_sg); -+ sg_free_table(&fmc2->dma_ecc_sg); -+ -+ clk_disable_unprepare(fmc2->clk); -+ -+ return ret; -+} -+ -+static int stm32_fmc2_remove(struct platform_device *pdev) -+{ -+ struct stm32_fmc2_nfc *fmc2 = platform_get_drvdata(pdev); -+ struct stm32_fmc2_nand *nand = &fmc2->nand; -+ -+ nand_release(nand_to_mtd(&nand->chip)); -+ -+ if (fmc2->dma_ecc_ch) -+ dma_release_channel(fmc2->dma_ecc_ch); -+ if (fmc2->dma_tx_ch) -+ dma_release_channel(fmc2->dma_tx_ch); -+ if (fmc2->dma_rx_ch) -+ dma_release_channel(fmc2->dma_rx_ch); -+ -+ sg_free_table(&fmc2->dma_data_sg); -+ sg_free_table(&fmc2->dma_ecc_sg); -+ -+ clk_disable_unprepare(fmc2->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_fmc2_suspend(struct device *dev) -+{ -+ struct stm32_fmc2_nfc *fmc2 = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(fmc2->clk); -+ -+ pinctrl_pm_select_sleep_state(dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_fmc2_resume(struct device *dev) -+{ -+ struct stm32_fmc2_nfc *fmc2 = dev_get_drvdata(dev); -+ struct stm32_fmc2_nand *nand = &fmc2->nand; -+ int chip_cs, ret; -+ -+ pinctrl_pm_select_default_state(dev); -+ -+ ret = clk_prepare_enable(fmc2->clk); -+ if (ret) { -+ dev_err(dev, "can not enable the clock\n"); -+ return ret; -+ } -+ -+ stm32_fmc2_init(fmc2); -+ -+ for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) { -+ if (!(fmc2->cs_assigned & BIT(chip_cs))) -+ continue; -+ -+ nand_reset(&nand->chip, chip_cs); -+ } -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(stm32_fmc2_pm_ops, stm32_fmc2_suspend, -+ stm32_fmc2_resume); -+ -+static const struct of_device_id stm32_fmc2_match[] = { -+ {.compatible = "st,stm32mp15-fmc2"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, stm32_fmc2_match); -+ -+static struct platform_driver stm32_fmc2_driver = { -+ .probe = stm32_fmc2_probe, -+ .remove = stm32_fmc2_remove, -+ .driver = { -+ .name = "stm32_fmc2_nand", -+ .of_match_table = stm32_fmc2_match, -+ .pm = &stm32_fmc2_pm_ops, -+ }, -+}; -+module_platform_driver(stm32_fmc2_driver); -+ -+MODULE_ALIAS("platform:stm32_fmc2_nand"); -+MODULE_AUTHOR("Christophe Kerello "); -+MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 nand driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig -index 37775fc..e9757be 100644 ---- a/drivers/mtd/spi-nor/Kconfig -+++ b/drivers/mtd/spi-nor/Kconfig -@@ -122,11 +122,4 @@ config SPI_INTEL_SPI_PLATFORM - To compile this driver as a module, choose M here: the module - will be called intel-spi-platform. - --config SPI_STM32_QUADSPI -- tristate "STM32 Quad SPI controller" -- depends on ARCH_STM32 || COMPILE_TEST -- help -- This enables support for the STM32 Quad SPI controller. -- We only connect the NOR to this controller. -- - endif # MTD_SPI_NOR -diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile -index f4c61d2..5d61422 100644 ---- a/drivers/mtd/spi-nor/Makefile -+++ b/drivers/mtd/spi-nor/Makefile -@@ -10,4 +10,3 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o - obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o - obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o - obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o --obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o -diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c -deleted file mode 100644 -index 13e9fc9..0000000 ---- a/drivers/mtd/spi-nor/stm32-quadspi.c -+++ /dev/null -@@ -1,720 +0,0 @@ --/* -- * Driver for stm32 quadspi controller -- * -- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved -- * Author(s): Ludovic Barre author . -- * -- * License terms: GPL V2.0. -- * -- * 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 . -- */ --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#define QUADSPI_CR 0x00 --#define CR_EN BIT(0) --#define CR_ABORT BIT(1) --#define CR_DMAEN BIT(2) --#define CR_TCEN BIT(3) --#define CR_SSHIFT BIT(4) --#define CR_DFM BIT(6) --#define CR_FSEL BIT(7) --#define CR_FTHRES_SHIFT 8 --#define CR_FTHRES_MASK GENMASK(12, 8) --#define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK) --#define CR_TEIE BIT(16) --#define CR_TCIE BIT(17) --#define CR_FTIE BIT(18) --#define CR_SMIE BIT(19) --#define CR_TOIE BIT(20) --#define CR_PRESC_SHIFT 24 --#define CR_PRESC_MASK GENMASK(31, 24) --#define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK) -- --#define QUADSPI_DCR 0x04 --#define DCR_CSHT_SHIFT 8 --#define DCR_CSHT_MASK GENMASK(10, 8) --#define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK) --#define DCR_FSIZE_SHIFT 16 --#define DCR_FSIZE_MASK GENMASK(20, 16) --#define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK) -- --#define QUADSPI_SR 0x08 --#define SR_TEF BIT(0) --#define SR_TCF BIT(1) --#define SR_FTF BIT(2) --#define SR_SMF BIT(3) --#define SR_TOF BIT(4) --#define SR_BUSY BIT(5) --#define SR_FLEVEL_SHIFT 8 --#define SR_FLEVEL_MASK GENMASK(13, 8) -- --#define QUADSPI_FCR 0x0c --#define FCR_CTCF BIT(1) -- --#define QUADSPI_DLR 0x10 -- --#define QUADSPI_CCR 0x14 --#define CCR_INST_SHIFT 0 --#define CCR_INST_MASK GENMASK(7, 0) --#define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK) --#define CCR_IMODE_NONE (0U << 8) --#define CCR_IMODE_1 (1U << 8) --#define CCR_IMODE_2 (2U << 8) --#define CCR_IMODE_4 (3U << 8) --#define CCR_ADMODE_NONE (0U << 10) --#define CCR_ADMODE_1 (1U << 10) --#define CCR_ADMODE_2 (2U << 10) --#define CCR_ADMODE_4 (3U << 10) --#define CCR_ADSIZE_SHIFT 12 --#define CCR_ADSIZE_MASK GENMASK(13, 12) --#define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK) --#define CCR_ABMODE_NONE (0U << 14) --#define CCR_ABMODE_1 (1U << 14) --#define CCR_ABMODE_2 (2U << 14) --#define CCR_ABMODE_4 (3U << 14) --#define CCR_ABSIZE_8 (0U << 16) --#define CCR_ABSIZE_16 (1U << 16) --#define CCR_ABSIZE_24 (2U << 16) --#define CCR_ABSIZE_32 (3U << 16) --#define CCR_DCYC_SHIFT 18 --#define CCR_DCYC_MASK GENMASK(22, 18) --#define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK) --#define CCR_DMODE_NONE (0U << 24) --#define CCR_DMODE_1 (1U << 24) --#define CCR_DMODE_2 (2U << 24) --#define CCR_DMODE_4 (3U << 24) --#define CCR_FMODE_INDW (0U << 26) --#define CCR_FMODE_INDR (1U << 26) --#define CCR_FMODE_APM (2U << 26) --#define CCR_FMODE_MM (3U << 26) -- --#define QUADSPI_AR 0x18 --#define QUADSPI_ABR 0x1c --#define QUADSPI_DR 0x20 --#define QUADSPI_PSMKR 0x24 --#define QUADSPI_PSMAR 0x28 --#define QUADSPI_PIR 0x2c --#define QUADSPI_LPTR 0x30 --#define LPTR_DFT_TIMEOUT 0x10 -- --#define FSIZE_VAL(size) (__fls(size) - 1) -- --#define STM32_MAX_MMAP_SZ SZ_256M --#define STM32_MAX_NORCHIP 2 -- --#define STM32_QSPI_FIFO_SZ 32 --#define STM32_QSPI_FIFO_TIMEOUT_US 30000 --#define STM32_QSPI_BUSY_TIMEOUT_US 100000 -- --struct stm32_qspi_flash { -- struct spi_nor nor; -- struct stm32_qspi *qspi; -- u32 cs; -- u32 fsize; -- u32 presc; -- u32 read_mode; -- bool registered; -- u32 prefetch_limit; --}; -- --struct stm32_qspi { -- struct device *dev; -- void __iomem *io_base; -- void __iomem *mm_base; -- resource_size_t mm_size; -- u32 nor_num; -- struct clk *clk; -- u32 clk_rate; -- struct stm32_qspi_flash flash[STM32_MAX_NORCHIP]; -- struct completion cmd_completion; -- -- /* -- * to protect device configuration, could be different between -- * 2 flash access (bk1, bk2) -- */ -- struct mutex lock; --}; -- --struct stm32_qspi_cmd { -- u8 addr_width; -- u8 dummy; -- bool tx_data; -- u8 opcode; -- u32 framemode; -- u32 qspimode; -- u32 addr; -- size_t len; -- void *buf; --}; -- --static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi) --{ -- u32 cr; -- int err = 0; -- -- if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF) -- return 0; -- -- reinit_completion(&qspi->cmd_completion); -- cr = readl_relaxed(qspi->io_base + QUADSPI_CR); -- writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR); -- -- if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion, -- msecs_to_jiffies(1000))) -- err = -ETIMEDOUT; -- -- writel_relaxed(cr, qspi->io_base + QUADSPI_CR); -- return err; --} -- --static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) --{ -- u32 sr; -- -- return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr, -- !(sr & SR_BUSY), 10, -- STM32_QSPI_BUSY_TIMEOUT_US); --} -- --static void stm32_qspi_set_framemode(struct spi_nor *nor, -- struct stm32_qspi_cmd *cmd, bool read) --{ -- u32 dmode = CCR_DMODE_1; -- -- cmd->framemode = CCR_IMODE_1; -- -- if (read) { -- switch (nor->read_proto) { -- default: -- case SNOR_PROTO_1_1_1: -- dmode = CCR_DMODE_1; -- break; -- case SNOR_PROTO_1_1_2: -- dmode = CCR_DMODE_2; -- break; -- case SNOR_PROTO_1_1_4: -- dmode = CCR_DMODE_4; -- break; -- } -- } -- -- cmd->framemode |= cmd->tx_data ? dmode : 0; -- cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0; --} -- --static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) --{ -- *val = readb_relaxed(addr); --} -- --static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) --{ -- writeb_relaxed(*val, addr); --} -- --static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, -- const struct stm32_qspi_cmd *cmd) --{ -- void (*tx_fifo)(u8 *, void __iomem *); -- u32 len = cmd->len, sr; -- u8 *buf = cmd->buf; -- int ret; -- -- if (cmd->qspimode == CCR_FMODE_INDW) -- tx_fifo = stm32_qspi_write_fifo; -- else -- tx_fifo = stm32_qspi_read_fifo; -- -- while (len--) { -- ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, -- sr, (sr & SR_FTF), 10, -- STM32_QSPI_FIFO_TIMEOUT_US); -- if (ret) { -- dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); -- return ret; -- } -- tx_fifo(buf++, qspi->io_base + QUADSPI_DR); -- } -- -- return 0; --} -- --static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, -- const struct stm32_qspi_cmd *cmd) --{ -- memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len); -- return 0; --} -- --static int stm32_qspi_tx(struct stm32_qspi *qspi, -- const struct stm32_qspi_cmd *cmd) --{ -- if (!cmd->tx_data) -- return 0; -- -- if (cmd->qspimode == CCR_FMODE_MM) -- return stm32_qspi_tx_mm(qspi, cmd); -- -- return stm32_qspi_tx_poll(qspi, cmd); --} -- --static int stm32_qspi_send(struct stm32_qspi_flash *flash, -- const struct stm32_qspi_cmd *cmd) --{ -- struct stm32_qspi *qspi = flash->qspi; -- u32 ccr, dcr, cr; -- u32 last_byte; -- int err; -- -- err = stm32_qspi_wait_nobusy(qspi); -- if (err) -- goto abort; -- -- dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK; -- dcr |= DCR_FSIZE(flash->fsize); -- writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR); -- -- cr = readl_relaxed(qspi->io_base + QUADSPI_CR); -- cr &= ~CR_PRESC_MASK & ~CR_FSEL; -- cr |= CR_PRESC(flash->presc); -- cr |= flash->cs ? CR_FSEL : 0; -- writel_relaxed(cr, qspi->io_base + QUADSPI_CR); -- -- if (cmd->tx_data) -- writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR); -- -- ccr = cmd->framemode | cmd->qspimode; -- -- if (cmd->dummy) -- ccr |= CCR_DCYC(cmd->dummy); -- -- if (cmd->addr_width) -- ccr |= CCR_ADSIZE(cmd->addr_width - 1); -- -- ccr |= CCR_INST(cmd->opcode); -- writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR); -- -- if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM) -- writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR); -- -- err = stm32_qspi_tx(qspi, cmd); -- if (err) -- goto abort; -- -- if (cmd->qspimode != CCR_FMODE_MM) { -- err = stm32_qspi_wait_cmd(qspi); -- if (err) -- goto abort; -- writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); -- } else { -- last_byte = cmd->addr + cmd->len; -- if (last_byte > flash->prefetch_limit) -- goto abort; -- } -- -- return err; -- --abort: -- cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; -- writel_relaxed(cr, qspi->io_base + QUADSPI_CR); -- -- if (err) -- dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); -- -- return err; --} -- --static int stm32_qspi_read_reg(struct spi_nor *nor, -- u8 opcode, u8 *buf, int len) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct device *dev = flash->qspi->dev; -- struct stm32_qspi_cmd cmd; -- -- dev_dbg(dev, "read_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.opcode = opcode; -- cmd.tx_data = true; -- cmd.len = len; -- cmd.buf = buf; -- cmd.qspimode = CCR_FMODE_INDR; -- -- stm32_qspi_set_framemode(nor, &cmd, false); -- -- return stm32_qspi_send(flash, &cmd); --} -- --static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode, -- u8 *buf, int len) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct device *dev = flash->qspi->dev; -- struct stm32_qspi_cmd cmd; -- -- dev_dbg(dev, "write_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.opcode = opcode; -- cmd.tx_data = !!(buf && len > 0); -- cmd.len = len; -- cmd.buf = buf; -- cmd.qspimode = CCR_FMODE_INDW; -- -- stm32_qspi_set_framemode(nor, &cmd, false); -- -- return stm32_qspi_send(flash, &cmd); --} -- --static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len, -- u_char *buf) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct stm32_qspi *qspi = flash->qspi; -- struct stm32_qspi_cmd cmd; -- int err; -- -- dev_dbg(qspi->dev, "read(%#.2x): buf:%pK from:%#.8x len:%#zx\n", -- nor->read_opcode, buf, (u32)from, len); -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.opcode = nor->read_opcode; -- cmd.addr_width = nor->addr_width; -- cmd.addr = (u32)from; -- cmd.tx_data = true; -- cmd.dummy = nor->read_dummy; -- cmd.len = len; -- cmd.buf = buf; -- cmd.qspimode = flash->read_mode; -- -- stm32_qspi_set_framemode(nor, &cmd, true); -- err = stm32_qspi_send(flash, &cmd); -- -- return err ? err : len; --} -- --static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len, -- const u_char *buf) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct device *dev = flash->qspi->dev; -- struct stm32_qspi_cmd cmd; -- int err; -- -- dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n", -- nor->program_opcode, buf, (u32)to, len); -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.opcode = nor->program_opcode; -- cmd.addr_width = nor->addr_width; -- cmd.addr = (u32)to; -- cmd.tx_data = true; -- cmd.len = len; -- cmd.buf = (void *)buf; -- cmd.qspimode = CCR_FMODE_INDW; -- -- stm32_qspi_set_framemode(nor, &cmd, false); -- err = stm32_qspi_send(flash, &cmd); -- -- return err ? err : len; --} -- --static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct device *dev = flash->qspi->dev; -- struct stm32_qspi_cmd cmd; -- -- dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs); -- -- memset(&cmd, 0, sizeof(cmd)); -- cmd.opcode = nor->erase_opcode; -- cmd.addr_width = nor->addr_width; -- cmd.addr = (u32)offs; -- cmd.qspimode = CCR_FMODE_INDW; -- -- stm32_qspi_set_framemode(nor, &cmd, false); -- -- return stm32_qspi_send(flash, &cmd); --} -- --static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) --{ -- struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; -- u32 cr, sr, fcr = 0; -- -- cr = readl_relaxed(qspi->io_base + QUADSPI_CR); -- sr = readl_relaxed(qspi->io_base + QUADSPI_SR); -- -- if ((cr & CR_TCIE) && (sr & SR_TCF)) { -- /* tx complete */ -- fcr |= FCR_CTCF; -- complete(&qspi->cmd_completion); -- } else { -- dev_info_ratelimited(qspi->dev, "spurious interrupt\n"); -- } -- -- writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR); -- -- return IRQ_HANDLED; --} -- --static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct stm32_qspi *qspi = flash->qspi; -- -- mutex_lock(&qspi->lock); -- return 0; --} -- --static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) --{ -- struct stm32_qspi_flash *flash = nor->priv; -- struct stm32_qspi *qspi = flash->qspi; -- -- mutex_unlock(&qspi->lock); --} -- --static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, -- struct device_node *np) --{ -- struct spi_nor_hwcaps hwcaps = { -- .mask = SNOR_HWCAPS_READ | -- SNOR_HWCAPS_READ_FAST | -- SNOR_HWCAPS_PP, -- }; -- u32 width, presc, cs_num, max_rate = 0; -- struct stm32_qspi_flash *flash; -- struct mtd_info *mtd; -- int ret; -- -- of_property_read_u32(np, "reg", &cs_num); -- if (cs_num >= STM32_MAX_NORCHIP) -- return -EINVAL; -- -- of_property_read_u32(np, "spi-max-frequency", &max_rate); -- if (!max_rate) -- return -EINVAL; -- -- presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1; -- -- if (of_property_read_u32(np, "spi-rx-bus-width", &width)) -- width = 1; -- -- if (width == 4) -- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; -- else if (width == 2) -- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; -- else if (width != 1) -- return -EINVAL; -- -- flash = &qspi->flash[cs_num]; -- flash->qspi = qspi; -- flash->cs = cs_num; -- flash->presc = presc; -- -- flash->nor.dev = qspi->dev; -- spi_nor_set_flash_node(&flash->nor, np); -- flash->nor.priv = flash; -- mtd = &flash->nor.mtd; -- -- flash->nor.read = stm32_qspi_read; -- flash->nor.write = stm32_qspi_write; -- flash->nor.erase = stm32_qspi_erase; -- flash->nor.read_reg = stm32_qspi_read_reg; -- flash->nor.write_reg = stm32_qspi_write_reg; -- flash->nor.prepare = stm32_qspi_prep; -- flash->nor.unprepare = stm32_qspi_unprep; -- -- writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR); -- -- writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT -- | CR_EN, qspi->io_base + QUADSPI_CR); -- -- /* -- * in stm32 qspi controller, QUADSPI_DCR register has a fsize field -- * which define the size of nor flash. -- * if fsize is NULL, the controller can't sent spi-nor command. -- * set a temporary value just to discover the nor flash with -- * "spi_nor_scan". After, the right value (mtd->size) can be set. -- */ -- flash->fsize = FSIZE_VAL(SZ_1K); -- -- ret = spi_nor_scan(&flash->nor, NULL, &hwcaps); -- if (ret) { -- dev_err(qspi->dev, "device scan failed\n"); -- return ret; -- } -- -- flash->fsize = FSIZE_VAL(mtd->size); -- flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ; -- -- flash->read_mode = CCR_FMODE_MM; -- if (mtd->size > qspi->mm_size) -- flash->read_mode = CCR_FMODE_INDR; -- -- writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR); -- -- ret = mtd_device_register(mtd, NULL, 0); -- if (ret) { -- dev_err(qspi->dev, "mtd device parse failed\n"); -- return ret; -- } -- -- flash->registered = true; -- -- dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n", -- flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width); -- -- return 0; --} -- --static void stm32_qspi_mtd_free(struct stm32_qspi *qspi) --{ -- int i; -- -- for (i = 0; i < STM32_MAX_NORCHIP; i++) -- if (qspi->flash[i].registered) -- mtd_device_unregister(&qspi->flash[i].nor.mtd); --} -- --static int stm32_qspi_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct device_node *flash_np; -- struct reset_control *rstc; -- struct stm32_qspi *qspi; -- struct resource *res; -- int ret, irq; -- -- qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); -- if (!qspi) -- return -ENOMEM; -- -- qspi->nor_num = of_get_child_count(dev->of_node); -- if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP) -- return -ENODEV; -- -- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); -- qspi->io_base = devm_ioremap_resource(dev, res); -- if (IS_ERR(qspi->io_base)) -- return PTR_ERR(qspi->io_base); -- -- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); -- qspi->mm_base = devm_ioremap_resource(dev, res); -- if (IS_ERR(qspi->mm_base)) -- return PTR_ERR(qspi->mm_base); -- -- qspi->mm_size = resource_size(res); -- -- irq = platform_get_irq(pdev, 0); -- ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, -- dev_name(dev), qspi); -- if (ret) { -- dev_err(dev, "failed to request irq\n"); -- return ret; -- } -- -- init_completion(&qspi->cmd_completion); -- -- qspi->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(qspi->clk)) -- return PTR_ERR(qspi->clk); -- -- qspi->clk_rate = clk_get_rate(qspi->clk); -- if (!qspi->clk_rate) -- return -EINVAL; -- -- ret = clk_prepare_enable(qspi->clk); -- if (ret) { -- dev_err(dev, "can not enable the clock\n"); -- return ret; -- } -- -- rstc = devm_reset_control_get_exclusive(dev, NULL); -- if (!IS_ERR(rstc)) { -- reset_control_assert(rstc); -- udelay(2); -- reset_control_deassert(rstc); -- } -- -- qspi->dev = dev; -- platform_set_drvdata(pdev, qspi); -- mutex_init(&qspi->lock); -- -- for_each_available_child_of_node(dev->of_node, flash_np) { -- ret = stm32_qspi_flash_setup(qspi, flash_np); -- if (ret) { -- dev_err(dev, "unable to setup flash chip\n"); -- goto err_flash; -- } -- } -- -- return 0; -- --err_flash: -- mutex_destroy(&qspi->lock); -- stm32_qspi_mtd_free(qspi); -- -- clk_disable_unprepare(qspi->clk); -- return ret; --} -- --static int stm32_qspi_remove(struct platform_device *pdev) --{ -- struct stm32_qspi *qspi = platform_get_drvdata(pdev); -- -- /* disable qspi */ -- writel_relaxed(0, qspi->io_base + QUADSPI_CR); -- -- stm32_qspi_mtd_free(qspi); -- mutex_destroy(&qspi->lock); -- -- clk_disable_unprepare(qspi->clk); -- return 0; --} -- --static const struct of_device_id stm32_qspi_match[] = { -- {.compatible = "st,stm32f469-qspi"}, -- {} --}; --MODULE_DEVICE_TABLE(of, stm32_qspi_match); -- --static struct platform_driver stm32_qspi_driver = { -- .probe = stm32_qspi_probe, -- .remove = stm32_qspi_remove, -- .driver = { -- .name = "stm32-quadspi", -- .of_match_table = stm32_qspi_match, -- }, --}; --module_platform_driver(stm32_qspi_driver); -- --MODULE_AUTHOR("Ludovic Barre "); --MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); --MODULE_LICENSE("GPL v2"); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0016-ARM-stm32mp1-r3-NET.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0016-ARM-stm32mp1-r3-NET.patch deleted file mode 100644 index ac1b651..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0016-ARM-stm32mp1-r3-NET.patch +++ /dev/null @@ -1,496 +0,0 @@ -From 61b384e5eaed6c1ef9342e7216ffd2376e0f611d Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:43 +0100 -Subject: [PATCH 16/31] ARM stm32mp1 r3 NET - ---- - drivers/net/ethernet/stmicro/stmmac/common.h | 2 +- - drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 167 +++++++++++++++++---- - drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 45 +++++- - .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 + - .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + - .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 5 + - .../net/wireless/broadcom/brcm80211/brcmutil/d11.c | 3 - - 8 files changed, 191 insertions(+), 42 deletions(-) - -diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h -index b069b3a..272b9ca6 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/common.h -+++ b/drivers/net/ethernet/stmicro/stmmac/common.h -@@ -261,7 +261,7 @@ struct stmmac_safety_stats { - #define STMMAC_COAL_TX_TIMER 1000 - #define STMMAC_MAX_COAL_TX_TICK 100000 - #define STMMAC_TX_MAX_FRAMES 256 --#define STMMAC_TX_FRAMES 1 -+#define STMMAC_TX_FRAMES 25 - - /* Packets types */ - enum packets_types { -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 7e2e79d..dd45026 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -@@ -25,9 +25,24 @@ - - #define SYSCFG_MCU_ETH_MASK BIT(23) - #define SYSCFG_MP1_ETH_MASK GENMASK(23, 16) -+#define SYSCFG_PMCCLRR_OFFSET 0x40 - - #define SYSCFG_PMCR_ETH_CLK_SEL BIT(16) - #define SYSCFG_PMCR_ETH_REF_CLK_SEL BIT(17) -+ -+/* Ethernet PHY interface selection in register SYSCFG Configuration -+ *------------------------------------------ -+ * src |BIT(23)| BIT(22)| BIT(21)|BIT(20)| -+ *------------------------------------------ -+ * MII | 0 | 0 | 0 | 1 | -+ *------------------------------------------ -+ * GMII | 0 | 0 | 0 | 0 | -+ *------------------------------------------ -+ * RGMII | 0 | 0 | 1 | n/a | -+ *------------------------------------------ -+ * RMII | 1 | 0 | 0 | n/a | -+ *------------------------------------------ -+ */ - #define SYSCFG_PMCR_ETH_SEL_MII BIT(20) - #define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21) - #define SYSCFG_PMCR_ETH_SEL_RMII BIT(23) -@@ -35,14 +50,54 @@ - #define SYSCFG_MCU_ETH_SEL_MII 0 - #define SYSCFG_MCU_ETH_SEL_RMII 1 - -+/* STM32MP1 register definitions -+ * -+ * Below table summarizes the clock requirement and clock sources for -+ * supported phy interface modes. -+ * __________________________________________________________________________ -+ *|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 | | -+ * --------------------------------------------------------------------------- -+ * -+ * BIT(17) : set this bit in RMII mode when you have PHY without crystal 50MHz -+ * BIT(16) : set this bit in GMII/RGMII PHY when you do not want use 125Mhz -+ * from PHY -+ *----------------------------------------------------- -+ * src | BIT(17) | BIT(16) | -+ *----------------------------------------------------- -+ * MII | n/a | n/a | -+ *----------------------------------------------------- -+ * GMII | n/a | st,eth_clk_sel | -+ *----------------------------------------------------- -+ * RGMII | n/a | st,eth_clk_sel | -+ *----------------------------------------------------- -+ * RMII | st,eth_ref_clk_sel | n/a | -+ *----------------------------------------------------- -+ * -+ */ -+ - struct stm32_dwmac { - struct clk *clk_tx; - struct clk *clk_rx; - struct clk *clk_eth_ck; - struct clk *clk_ethstp; - struct clk *syscfg_clk; -- bool int_phyclk; /* Clock from RCC to drive PHY */ -- u32 mode_reg; /* MAC glue-logic mode register */ -+ int eth_clk_sel_reg; -+ int eth_ref_clk_sel_reg; -+ int irq_pwr_wakeup; -+ u32 mode_reg; /* MAC glue-logic mode register */ - struct regmap *regmap; - u32 speed; - const struct stm32_ops *ops; -@@ -98,23 +153,32 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) - int ret = 0; - - if (prepare) { -- ret = clk_prepare_enable(dwmac->syscfg_clk); -- if (ret) -- return ret; -- -- if (dwmac->int_phyclk) { -+ if (dwmac->syscfg_clk) { -+ ret = clk_prepare_enable(dwmac->syscfg_clk); -+ if (ret) -+ return ret; -+ } -+ if (dwmac->clk_eth_ck) { - ret = clk_prepare_enable(dwmac->clk_eth_ck); - if (ret) { -- clk_disable_unprepare(dwmac->syscfg_clk); -+ if (dwmac->syscfg_clk) -+ goto unprepare_syscfg; - return ret; - } - } - } else { -- clk_disable_unprepare(dwmac->syscfg_clk); -- if (dwmac->int_phyclk) -+ if (dwmac->syscfg_clk) -+ clk_disable_unprepare(dwmac->syscfg_clk); -+ -+ if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); - } - return ret; -+ -+unprepare_syscfg: -+ clk_disable_unprepare(dwmac->syscfg_clk); -+ -+ return ret; - } - - static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) -@@ -130,19 +194,22 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) - break; - case PHY_INTERFACE_MODE_GMII: - val = SYSCFG_PMCR_ETH_SEL_GMII; -- if (dwmac->int_phyclk) -+ if (dwmac->eth_clk_sel_reg) - val |= SYSCFG_PMCR_ETH_CLK_SEL; - pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n"); - break; - case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_PMCR_ETH_SEL_RMII; -- if (dwmac->int_phyclk) -+ if (dwmac->eth_ref_clk_sel_reg) - val |= SYSCFG_PMCR_ETH_REF_CLK_SEL; - pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n"); - break; - case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: - val = SYSCFG_PMCR_ETH_SEL_RGMII; -- if (dwmac->int_phyclk) -+ if (dwmac->eth_clk_sel_reg) - val |= SYSCFG_PMCR_ETH_CLK_SEL; - pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n"); - break; -@@ -153,6 +220,11 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) - return -EINVAL; - } - -+ /* Need to update PMCCLRR (clear register) */ -+ regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, -+ dwmac->ops->syscfg_eth_mask); -+ -+ /* Update PMCSETR (set register) */ - return regmap_update_bits(dwmac->regmap, reg, - dwmac->ops->syscfg_eth_mask, val); - } -@@ -232,35 +304,65 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, - static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, - struct device *dev) - { -+ struct platform_device *pdev = to_platform_device(dev); - struct device_node *np = dev->of_node; -+ int err; - -- dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk"); -+ /* Gigabit Ethernet 125MHz clock selection. */ -+ dwmac->eth_clk_sel_reg = of_property_read_bool(np, "st,eth_clk_sel"); - -- /* Check if internal clk from RCC selected */ -- if (dwmac->int_phyclk) { -- /* Get ETH_CLK clocks */ -- dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); -- if (IS_ERR(dwmac->clk_eth_ck)) { -- dev_err(dev, "No ETH CK clock provided...\n"); -- return PTR_ERR(dwmac->clk_eth_ck); -- } -+ /* Ethernet 50Mhz RMII clock selection */ -+ dwmac->eth_ref_clk_sel_reg = -+ of_property_read_bool(np, "st,eth_ref_clk_sel"); -+ -+ /* Get ETH_CLK clocks */ -+ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); -+ if (IS_ERR(dwmac->clk_eth_ck)) { -+ dev_warn(dev, "No phy clock provided...\n"); -+ dwmac->clk_eth_ck = NULL; - } - - /* Clock used for low power mode */ - dwmac->clk_ethstp = devm_clk_get(dev, "ethstp"); - if (IS_ERR(dwmac->clk_ethstp)) { -- dev_err(dev, "No ETH peripheral clock provided for CStop mode ...\n"); -+ dev_err(dev, -+ "No ETH peripheral clock provided for CStop mode ...\n"); - return PTR_ERR(dwmac->clk_ethstp); - } - -- /* Clock for sysconfig */ -+ /* Optional Clock for sysconfig */ - dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk"); - if (IS_ERR(dwmac->syscfg_clk)) { -- dev_err(dev, "No syscfg clock provided...\n"); -- return PTR_ERR(dwmac->syscfg_clk); -+ err = PTR_ERR(dwmac->syscfg_clk); -+ if (err != -ENOENT) -+ return err; -+ dwmac->syscfg_clk = NULL; - } - -- return 0; -+ err = 0; -+ /* Get IRQ information early to have an ability to ask for deferred -+ * probe if needed before we went too far with resource allocation. -+ */ -+ dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev, -+ "stm32_pwr_wakeup"); -+ if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ if ((!dwmac->clk_eth_ck) && dwmac->irq_pwr_wakeup >= 0) { -+ err = device_init_wakeup(&pdev->dev, true); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to init wake up irq\n"); -+ return err; -+ } -+ err = dev_pm_set_dedicated_wake_irq(&pdev->dev, -+ dwmac->irq_pwr_wakeup); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to set wake up irq\n"); -+ device_init_wakeup(&pdev->dev, false); -+ } -+ device_set_wakeup_enable(&pdev->dev, false); -+ } -+ return err; - } - - static int stm32_dwmac_probe(struct platform_device *pdev) -@@ -326,9 +428,15 @@ static int stm32_dwmac_remove(struct platform_device *pdev) - struct net_device *ndev = platform_get_drvdata(pdev); - struct stmmac_priv *priv = netdev_priv(ndev); - int ret = stmmac_dvr_remove(&pdev->dev); -+ struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - - stm32_dwmac_clk_disable(priv->plat->bsp_priv); - -+ if (dwmac->irq_pwr_wakeup >= 0) { -+ dev_pm_clear_wake_irq(&pdev->dev); -+ device_init_wakeup(&pdev->dev, false); -+ } -+ - return ret; - } - -@@ -341,8 +449,9 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) - return ret; - - clk_disable_unprepare(dwmac->clk_tx); -- clk_disable_unprepare(dwmac->syscfg_clk); -- if (dwmac->int_phyclk) -+ if (dwmac->syscfg_clk) -+ clk_disable_unprepare(dwmac->syscfg_clk); -+ if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); - - return ret; -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c -index 49f5687..5b35071 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c -@@ -22,7 +22,7 @@ int dwmac4_dma_reset(void __iomem *ioaddr) - /* DMA SW reset */ - value |= DMA_BUS_MODE_SFT_RESET; - writel(value, ioaddr + DMA_BUS_MODE); -- limit = 10; -+ limit = 100; - while (limit--) { - if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) - break; -diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -index 014fe93..ccb512f 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -2713,6 +2713,8 @@ static int stmmac_release(struct net_device *dev) - struct stmmac_priv *priv = netdev_priv(dev); - u32 chan; - -+ stmmac_disable_all_queues(priv); -+ - if (priv->eee_enabled) - del_timer_sync(&priv->eee_ctrl_timer); - -@@ -2724,8 +2726,6 @@ static int stmmac_release(struct net_device *dev) - - stmmac_stop_all_queues(priv); - -- stmmac_disable_all_queues(priv); -- - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) - del_timer_sync(&priv->tx_queue[chan].txtimer); - -@@ -4501,14 +4501,13 @@ int stmmac_suspend(struct device *dev) - if (!ndev || !netif_running(ndev)) - return 0; - -- if (ndev->phydev) -- phy_stop(ndev->phydev); -+ /* call carrier off first to avoid false dev_watchdog timeouts */ -+ netif_carrier_off(ndev); - - mutex_lock(&priv->lock); - - netif_device_detach(ndev); - stmmac_stop_all_queues(priv); -- - stmmac_disable_all_queues(priv); - - /* Stop TX/RX DMA */ -@@ -4532,6 +4531,10 @@ int stmmac_suspend(struct device *dev) - priv->oldlink = false; - priv->speed = SPEED_UNKNOWN; - priv->oldduplex = DUPLEX_UNKNOWN; -+ -+ if (ndev->phydev) -+ phy_stop(ndev->phydev); -+ - return 0; - } - EXPORT_SYMBOL_GPL(stmmac_suspend); -@@ -4572,6 +4575,7 @@ int stmmac_resume(struct device *dev) - { - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); -+ int ret; - - if (!netif_running(ndev)) - return 0; -@@ -4601,11 +4605,32 @@ int stmmac_resume(struct device *dev) - - netif_device_attach(ndev); - -+ if (ndev->phydev) -+ phy_start(ndev->phydev); -+ - mutex_lock(&priv->lock); - - stmmac_reset_queues_param(priv); - -- stmmac_clear_descriptors(priv); -+ /* Stop TX/RX DMA and clear the descriptors */ -+ stmmac_stop_all_dma(priv); -+ -+ /* Release and free the Rx/Tx resources */ -+ free_dma_desc_resources(priv); -+ -+ ret = alloc_dma_desc_resources(priv); -+ if (ret < 0) { -+ netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", -+ __func__); -+ goto dma_desc_error; -+ } -+ -+ ret = init_dma_desc_rings(ndev, GFP_KERNEL); -+ if (ret < 0) { -+ netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", -+ __func__); -+ goto init_error; -+ } - - stmmac_hw_setup(ndev, false); - stmmac_init_tx_coalesce(priv); -@@ -4617,10 +4642,14 @@ int stmmac_resume(struct device *dev) - - mutex_unlock(&priv->lock); - -+ return 0; -+init_error: -+ free_dma_desc_resources(priv); -+dma_desc_error: - if (ndev->phydev) -- phy_start(ndev->phydev); -+ phy_disconnect(ndev->phydev); - -- return 0; -+ return -1; - } - EXPORT_SYMBOL_GPL(stmmac_resume); - -diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -index 2b800ce..3031f2b 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -408,6 +408,9 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) - /* Default to phy auto-detection */ - plat->phy_addr = -1; - -+ /* Get clk_csr from device tree */ -+ of_property_read_u32(np, "clk_csr", &plat->clk_csr); -+ - /* "snps,phy-addr" is not a standard property. Mark it as deprecated - * and warn of its use. Remove this when phy node support is added. - */ -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -index d2f788d..c7b41ce 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -@@ -1129,7 +1129,10 @@ static int brcmf_ops_sdio_suspend(struct device *dev) - enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); - else - sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; -+ } else { -+ brcmf_sdiod_intr_unregister(sdiodev); - } -+ - if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) - brcmf_err("Failed to set pm_flags %x\n", sdio_flags); - return 0; -@@ -1145,6 +1148,9 @@ static int brcmf_ops_sdio_resume(struct device *dev) - if (func->num != 2) - return 0; - -+ if (!sdiodev->wowl_enabled) -+ brcmf_sdiod_intr_register(sdiodev); -+ - brcmf_sdiod_freezer_off(sdiodev); - return 0; - } -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -index ffa243e..55974a4 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -@@ -496,6 +496,11 @@ int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid) - brcmf_dbg(TRACE, "reqid=%llu\n", reqid); - - pi = ifp_to_pno(ifp); -+ -+ /* No PNO reqeuset */ -+ if (!pi->n_reqs) -+ return 0; -+ - err = brcmf_pno_remove_request(pi, reqid); - if (err) - return err; -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c -index eb5db94..e7584b8 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c -@@ -193,9 +193,6 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) - } - break; - case BRCMU_CHSPEC_D11AC_BW_160: -- ch->bw = BRCMU_CHAN_BW_160; -- ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, -- BRCMU_CHSPEC_D11AC_SB_SHIFT); - switch (ch->sb) { - case BRCMU_CHAN_SB_LLL: - ch->control_ch_num -= CH_70MHZ_APART; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch deleted file mode 100644 index 266f60f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch +++ /dev/null @@ -1,377 +0,0 @@ -From a658fa1ee69e4b233cde37442c25523238b0d001 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:43 +0100 -Subject: [PATCH 17/31] ARM stm32mp1 r3 NVMEM - ---- - drivers/nvmem/Kconfig | 10 ++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/core.c | 74 +++++++++++++++ - drivers/nvmem/stm32-romem.c | 203 +++++++++++++++++++++++++++++++++++++++++ - include/linux/nvmem-consumer.h | 14 +++ - 5 files changed, 303 insertions(+) - create mode 100644 drivers/nvmem/stm32-romem.c - -diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig -index 0a7a470e..f398b18 100644 ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -113,6 +113,16 @@ config NVMEM_BCM_OCOTP - This driver can also be built as a module. If so, the module - will be called nvmem-bcm-ocotp. - -+config NVMEM_STM32_ROMEM -+ tristate "STMicroelectronics STM32 factory-programmed memory support" -+ depends on ARCH_STM32 || COMPILE_TEST -+ help -+ Say y here to enable read-only access for STMicroelectronics STM32 -+ factory-programmed memory area. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-stm32-romem. -+ - config NVMEM_SUNXI_SID - tristate "Allwinner SoCs SID support" - depends on ARCH_SUNXI -diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile -index 4e8c616..e85c946 100644 ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -26,6 +26,8 @@ nvmem_qfprom-y := qfprom.o - obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o - nvmem_rockchip_efuse-y := rockchip-efuse.o - obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o -+nvmem_stm32_romem-y := stm32-romem.o -+obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o - nvmem_sunxi_sid-y := sunxi_sid.o - obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o - nvmem-uniphier-efuse-y := uniphier-efuse.o -diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c -index 30c0407..e5808b8f 100644 ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -1246,6 +1246,80 @@ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) - EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); - - /** -+ * nvmem_cell_read_u16() - Read a cell value as an u16 -+ * -+ * @dev: Device that requests the nvmem cell. -+ * @cell_id: Name of nvmem cell to read. -+ * @val: pointer to output value. -+ * -+ * Return: 0 on success or negative errno. -+ */ -+int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) -+{ -+ struct nvmem_cell *cell; -+ void *buf; -+ size_t len; -+ -+ cell = nvmem_cell_get(dev, cell_id); -+ if (IS_ERR(cell)) -+ return PTR_ERR(cell); -+ -+ buf = nvmem_cell_read(cell, &len); -+ if (IS_ERR(buf)) { -+ nvmem_cell_put(cell); -+ return PTR_ERR(buf); -+ } -+ if (len != sizeof(*val)) { -+ kfree(buf); -+ nvmem_cell_put(cell); -+ return -EINVAL; -+ } -+ memcpy(val, buf, sizeof(*val)); -+ kfree(buf); -+ nvmem_cell_put(cell); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); -+ -+/** -+ * nvmem_cell_read_u8() - Read a cell value as an u8 -+ * -+ * @dev: Device that requests the nvmem cell. -+ * @cell_id: Name of nvmem cell to read. -+ * @val: pointer to output value. -+ * -+ * Return: 0 on success or negative errno. -+ */ -+int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) -+{ -+ struct nvmem_cell *cell; -+ void *buf; -+ size_t len; -+ -+ cell = nvmem_cell_get(dev, cell_id); -+ if (IS_ERR(cell)) -+ return PTR_ERR(cell); -+ -+ buf = nvmem_cell_read(cell, &len); -+ if (IS_ERR(buf)) { -+ nvmem_cell_put(cell); -+ return PTR_ERR(buf); -+ } -+ if (len != sizeof(*val)) { -+ kfree(buf); -+ nvmem_cell_put(cell); -+ return -EINVAL; -+ } -+ memcpy(val, buf, sizeof(*val)); -+ kfree(buf); -+ nvmem_cell_put(cell); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); -+ -+/** - * nvmem_device_cell_read() - Read a given nvmem device and cell - * - * @nvmem: nvmem device to read from. -diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c -new file mode 100644 -index 0000000..34b388c ---- /dev/null -+++ b/drivers/nvmem/stm32-romem.c -@@ -0,0 +1,203 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * STM32 Factory-programmed memory read access driver -+ * -+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved -+ * Author: Fabrice Gasnier for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* BSEC secure service access from non-secure */ -+#define STM32_SMC_BSEC 0x82001003 -+#define STM32_SMC_READ_SHADOW 0x01 -+#define STM32_SMC_PROG_OTP 0x02 -+#define STM32_SMC_WRITE_SHADOW 0x03 -+#define STM32_SMC_READ_OTP 0x04 -+ -+/* shadow registers offest */ -+#define STM32MP15_BSEC_DATA0 0x200 -+ -+/* 32 (x 32-bits) lower shadow registers */ -+#define STM32MP15_BSEC_NUM_LOWER 32 -+ -+struct stm32_romem_cfg { -+ int size; -+}; -+ -+struct stm32_romem_priv { -+ void __iomem *base; -+ struct nvmem_config cfg; -+ struct device *dev; -+}; -+ -+static int stm32_romem_read(void *context, unsigned int offset, void *buf, -+ size_t bytes) -+{ -+ struct stm32_romem_priv *priv = context; -+ u8 *buf8 = buf; -+ int i; -+ -+ for (i = offset; i < offset + bytes; i++) -+ *buf8++ = readb_relaxed(priv->base + i); -+ -+ return 0; -+} -+ -+static int stm32_bsec_smc(u8 op, u32 otp, u32 data, u32 *result) -+{ -+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) -+ struct arm_smccc_res res; -+ -+ arm_smccc_smc(STM32_SMC_BSEC, op, otp, data, 0, 0, 0, 0, &res); -+ if (res.a0) -+ return -EIO; -+ -+ if (result) -+ *result = (u32)res.a1; -+ -+ return 0; -+#else -+ return -ENXIO; -+#endif -+} -+ -+static int stm32_bsec_read(void *context, unsigned int offset, void *buf, -+ size_t bytes) -+{ -+ struct stm32_romem_priv *priv = context; -+ u32 roffset, rbytes, val; -+ u8 *buf8 = buf, *val8 = (u8 *)&val; -+ int i, j = 0, ret, skip_bytes, size; -+ -+ /* Round unaligned access to 32-bits */ -+ roffset = rounddown(offset, 4); -+ skip_bytes = offset & 0x3; -+ rbytes = roundup(bytes + skip_bytes, 4); -+ -+ if (roffset + rbytes > priv->cfg.size) -+ return -EINVAL; -+ -+ for (i = roffset; (i < roffset + rbytes); i += 4) { -+ u32 otp = i >> 2; -+ -+ if (otp < STM32MP15_BSEC_NUM_LOWER) { -+ /* read lower data from shadow registers */ -+ val = readl_relaxed( -+ priv->base + STM32MP15_BSEC_DATA0 + i); -+ } else { -+ ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, otp, 0, -+ &val); -+ if (ret) { -+ dev_err(priv->dev, "Can't read data%d (%d)\n", -+ otp, ret); -+ return ret; -+ } -+ } -+ /* skip first bytes in case of unaligned read */ -+ if (skip_bytes) -+ size = min(bytes, (size_t)(4 - skip_bytes)); -+ else -+ size = min(bytes, (size_t)4); -+ memcpy(&buf8[j], &val8[skip_bytes], size); -+ bytes -= size; -+ j += size; -+ skip_bytes = 0; -+ } -+ -+ return 0; -+} -+ -+static int stm32_bsec_write(void *context, unsigned int offset, void *buf, -+ size_t bytes) -+{ -+ struct stm32_romem_priv *priv = context; -+ u32 *buf32 = buf; -+ int ret, i; -+ -+ /* Allow only writing complete 32-bits aligned words */ -+ if ((bytes % 4) || (offset % 4)) -+ return -EINVAL; -+ -+ for (i = offset; i < offset + bytes; i += 4) { -+ ret = stm32_bsec_smc(STM32_SMC_PROG_OTP, i >> 2, *buf32++, -+ NULL); -+ if (ret) { -+ dev_err(priv->dev, "Failed to write data%d (%d)\n", -+ i >> 2, ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int stm32_romem_probe(struct platform_device *pdev) -+{ -+ const struct stm32_romem_cfg *cfg; -+ struct device *dev = &pdev->dev; -+ struct stm32_romem_priv *priv; -+ struct resource *res; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->base)) -+ return PTR_ERR(priv->base); -+ -+ priv->dev = dev; -+ priv->cfg.name = "stm32-romem"; -+ priv->cfg.word_size = 1; -+ priv->cfg.stride = 1; -+ priv->cfg.dev = &pdev->dev; -+ priv->cfg.priv = priv; -+ priv->cfg.owner = THIS_MODULE; -+ -+ cfg = (const struct stm32_romem_cfg *) -+ of_match_device(dev->driver->of_match_table, dev)->data; -+ if (!cfg) { -+ priv->cfg.read_only = true; -+ priv->cfg.size = resource_size(res); -+ priv->cfg.reg_read = stm32_romem_read; -+ } else { -+ priv->cfg.size = cfg->size; -+ priv->cfg.reg_read = stm32_bsec_read; -+ priv->cfg.reg_write = stm32_bsec_write; -+ } -+ -+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); -+} -+ -+static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { -+ .size = 384, /* 96 x 32-bits data words */ -+}; -+ -+static const struct of_device_id stm32_romem_of_match[] = { -+ { .compatible = "st,stm32-romem", }, { -+ .compatible = "st,stm32mp15-bsec", -+ .data = (void *)&stm32mp15_bsec_cfg, -+ }, { -+ }, -+}; -+MODULE_DEVICE_TABLE(of, stm32_romem_of_match); -+ -+static struct platform_driver stm32_romem_driver = { -+ .probe = stm32_romem_probe, -+ .driver = { -+ .name = "stm32-romem", -+ .of_match_table = of_match_ptr(stm32_romem_of_match), -+ }, -+}; -+module_platform_driver(stm32_romem_driver); -+ -+MODULE_AUTHOR("Fabrice Gasnier "); -+MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM"); -+MODULE_ALIAS("platform:nvmem-stm32-romem"); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h -index 4e85447..c97f1e9 100644 ---- a/include/linux/nvmem-consumer.h -+++ b/include/linux/nvmem-consumer.h -@@ -39,6 +39,8 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); - void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); - int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); - int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); -+int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); -+int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); - - /* direct nvmem device read/write interface */ - struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); -@@ -95,6 +97,18 @@ static inline int nvmem_cell_read_u32(struct device *dev, - return -ENOSYS; - } - -+static inline int nvmem_cell_read_u16(struct device *dev, -+ const char *cell_id, u16 *val) -+{ -+ return -ENOSYS; -+} -+ -+static inline int nvmem_cell_read_u8(struct device *dev, -+ const char *cell_id, u8 *val) -+{ -+ return -EOPNOTSUPP; -+} -+ - static inline struct nvmem_device *nvmem_device_get(struct device *dev, - const char *name) - { --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch deleted file mode 100644 index 636541d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch +++ /dev/null @@ -1,5533 +0,0 @@ -From 65b46b4c2bf2b5d86f210f337e1ca8471034019c Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:44 +0100 -Subject: [PATCH 19/31] ARM stm32mp1 r3 PHY PINCTRL PWM - ---- - drivers/phy/st/phy-stm32-usbphyc.c | 451 +++++++++-- - drivers/pinctrl/Kconfig | 14 + - drivers/pinctrl/Makefile | 1 + - drivers/pinctrl/core.c | 28 +- - drivers/pinctrl/pinctrl-stmfx.c | 858 +++++++++++++++++++++ - drivers/pinctrl/stm32/pinctrl-stm32.c | 435 +++++++++-- - drivers/pinctrl/stm32/pinctrl-stm32.h | 53 +- - drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1095 ++++++++++++++++----------- - drivers/pwm/pwm-stm32-lp.c | 38 + - drivers/pwm/pwm-stm32.c | 105 ++- - drivers/pwm/sysfs.c | 11 + - include/dt-bindings/pinctrl/stm32-pinfunc.h | 7 + - include/linux/pinctrl/pinctrl.h | 7 + - 13 files changed, 2498 insertions(+), 605 deletions(-) - create mode 100644 drivers/pinctrl/pinctrl-stmfx.c - -diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c -index 1255cd1..c9c3c3e 100644 ---- a/drivers/phy/st/phy-stm32-usbphyc.c -+++ b/drivers/phy/st/phy-stm32-usbphyc.c -@@ -1,4 +1,4 @@ --// SPDX-Licence-Identifier: GPL-2.0 -+// SPDX-License-Identifier: GPL-2.0 - /* - * STMicroelectronics STM32 USB PHY Controller driver - * -@@ -7,6 +7,7 @@ - */ - #include - #include -+#include - #include - #include - #include -@@ -17,6 +18,7 @@ - - #define STM32_USBPHYC_PLL 0x0 - #define STM32_USBPHYC_MISC 0x8 -+#define STM32_USBPHYC_TUNE(X) (0x10C + (X * 0x100)) - #define STM32_USBPHYC_VERSION 0x3F4 - - /* STM32_USBPHYC_PLL bit fields */ -@@ -32,16 +34,86 @@ - /* STM32_USBPHYC_MISC bit fields */ - #define SWITHOST BIT(0) - --/* STM32_USBPHYC_VERSION bit fields */ --#define MINREV GENMASK(3, 0) --#define MAJREV GENMASK(7, 4) -+/* STM32_USBPHYC_TUNE bit fields */ -+#define INCURREN BIT(0) -+#define INCURRINT BIT(1) -+#define LFSCAPEN BIT(2) -+#define HSDRVSLEW BIT(3) -+#define HSDRVDCCUR BIT(4) -+#define HSDRVDCLEV BIT(5) -+#define HSDRVCURINCR BIT(6) -+#define FSDRVRFADJ BIT(7) -+#define HSDRVRFRED BIT(8) -+#define HSDRVCHKITRM GENMASK(12, 9) -+#define HSDRVCHKZTRM GENMASK(14, 13) -+#define OTPCOMP GENMASK(19, 15) -+#define SQLCHCTL GENMASK(21, 20) -+#define HDRXGNEQEN BIT(22) -+#define HSRXOFF GENMASK(24, 23) -+#define HSFALLPREEM BIT(25) -+#define SHTCCTCTLPROT BIT(26) -+#define STAGSEL BIT(27) -+ -+enum boosting_vals { -+ BOOST_1_MA = 1, -+ BOOST_2_MA, -+ BOOST_MAX, -+}; -+ -+enum dc_level_vals { -+ DC_MINUS_5_TO_7_MV, -+ DC_PLUS_5_TO_7_MV, -+ DC_PLUS_10_TO_14_MV, -+ DC_MAX, -+}; - --static const char * const supplies_names[] = { -- "vdda1v1", /* 1V1 */ -- "vdda1v8", /* 1V8 */ -+enum current_trim { -+ CUR_NOMINAL, -+ CUR_PLUS_1_56_PCT, -+ CUR_PLUS_3_12_PCT, -+ CUR_PLUS_4_68_PCT, -+ CUR_PLUS_6_24_PCT, -+ CUR_PLUS_7_8_PCT, -+ CUR_PLUS_9_36_PCT, -+ CUR_PLUS_10_92_PCT, -+ CUR_PLUS_12_48_PCT, -+ CUR_PLUS_14_04_PCT, -+ CUR_PLUS_15_6_PCT, -+ CUR_PLUS_17_16_PCT, -+ CUR_PLUS_19_01_PCT, -+ CUR_PLUS_20_58_PCT, -+ CUR_PLUS_22_16_PCT, -+ CUR_PLUS_23_73_PCT, -+ CUR_MAX, - }; - --#define NUM_SUPPLIES ARRAY_SIZE(supplies_names) -+enum impedance_trim { -+ IMP_NOMINAL, -+ IMP_MINUS_2_OHMS, -+ IMP_MINUS_4_OMHS, -+ IMP_MINUS_6_OHMS, -+ IMP_MAX, -+}; -+ -+enum squelch_level { -+ SQLCH_NOMINAL, -+ SQLCH_PLUS_7_MV, -+ SQLCH_MINUS_5_MV, -+ SQLCH_PLUS_14_MV, -+ SQLCH_MAX, -+}; -+ -+enum rx_offset { -+ NO_RX_OFFSET, -+ RX_OFFSET_PLUS_5_MV, -+ RX_OFFSET_PLUS_10_MV, -+ RX_OFFSET_MINUS_5_MV, -+ RX_OFFSET_MAX, -+}; -+ -+/* STM32_USBPHYC_VERSION bit fields */ -+#define MINREV GENMASK(3, 0) -+#define MAJREV GENMASK(7, 4) - - #define PLL_LOCK_TIME_US 100 - #define PLL_PWR_DOWN_TIME_US 5 -@@ -58,7 +130,6 @@ struct pll_params { - struct stm32_usbphyc_phy { - struct phy *phy; - struct stm32_usbphyc *usbphyc; -- struct regulator_bulk_data supplies[NUM_SUPPLIES]; - u32 index; - bool active; - }; -@@ -70,6 +141,10 @@ struct stm32_usbphyc { - struct reset_control *rst; - struct stm32_usbphyc_phy **phys; - int nphys; -+ struct regulator *vdda1v1; -+ struct regulator *vdda1v8; -+ struct regulator *vdd3v3; -+ struct clk_hw clk48_hw; - int switch_setup; - }; - -@@ -83,6 +158,49 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) - writel_relaxed(readl_relaxed(reg) & ~bits, reg); - } - -+static int stm32_usbphyc_regulators_enable(struct stm32_usbphyc *usbphyc) -+{ -+ int ret; -+ -+ ret = regulator_enable(usbphyc->vdda1v1); -+ if (ret) -+ return ret; -+ -+ ret = regulator_enable(usbphyc->vdda1v8); -+ if (ret) -+ goto vdda1v1_disable; -+ -+ ret = regulator_enable(usbphyc->vdd3v3); -+ if (ret) -+ goto vdda1v8_disable; -+ -+ return 0; -+ -+vdda1v8_disable: -+ regulator_disable(usbphyc->vdda1v8); -+vdda1v1_disable: -+ regulator_disable(usbphyc->vdda1v1); -+ -+ return ret; -+} -+ -+static int stm32_usbphyc_regulators_disable(struct stm32_usbphyc *usbphyc) -+{ -+ int ret; -+ -+ ret = regulator_disable(usbphyc->vdd3v3); -+ if (ret) -+ return ret; -+ ret = regulator_disable(usbphyc->vdda1v8); -+ if (ret) -+ return ret; -+ ret = regulator_disable(usbphyc->vdda1v1); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ - static void stm32_usbphyc_get_pll_params(u32 clk_rate, - struct pll_params *pll_params) - { -@@ -142,7 +260,7 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) - return 0; - } - --static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) -+static bool stm32_usbphyc_has_one_pll_consumer(struct stm32_usbphyc *usbphyc) - { - int i; - -@@ -150,60 +268,72 @@ static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) - if (usbphyc->phys[i]->active) - return true; - -+ if (clk_hw_is_enabled(&usbphyc->clk48_hw)) -+ return true; -+ - return false; - } - -+static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) -+{ -+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -+ -+ /* Check if a phy port is still active or clk48 in use */ -+ if (stm32_usbphyc_has_one_pll_consumer(usbphyc)) -+ return 0; -+ -+ stm32_usbphyc_clr_bits(pll_reg, PLLEN); -+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -+ udelay(PLL_PWR_DOWN_TIME_US); -+ -+ if (readl_relaxed(pll_reg) & PLLEN) { -+ dev_err(usbphyc->dev, "PLL not reset\n"); -+ return -EIO; -+ } -+ -+ return stm32_usbphyc_regulators_disable(usbphyc); -+} -+ - static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) - { - void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -- bool pllen = (readl_relaxed(pll_reg) & PLLEN); -+ bool pllen = readl_relaxed(pll_reg) & PLLEN; - int ret; - -- /* Check if one phy port has already configured the pll */ -- if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc)) -+ /* Check if a phy port or clk48 enable has configured the pll */ -+ if (pllen && stm32_usbphyc_has_one_pll_consumer(usbphyc)) - return 0; - - if (pllen) { -- stm32_usbphyc_clr_bits(pll_reg, PLLEN); -- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -- udelay(PLL_PWR_DOWN_TIME_US); -+ ret = stm32_usbphyc_pll_disable(usbphyc); -+ if (ret) -+ return ret; - } - -- ret = stm32_usbphyc_pll_init(usbphyc); -+ ret = stm32_usbphyc_regulators_enable(usbphyc); - if (ret) - return ret; - -- stm32_usbphyc_set_bits(pll_reg, PLLEN); -+ ret = stm32_usbphyc_pll_init(usbphyc); -+ if (ret) -+ goto reg_disable; - -+ stm32_usbphyc_set_bits(pll_reg, PLLEN); - /* Wait for maximum lock time */ - udelay(PLL_LOCK_TIME_US); - - if (!(readl_relaxed(pll_reg) & PLLEN)) { - dev_err(usbphyc->dev, "PLLEN not set\n"); -- return -EIO; -+ ret = -EIO; -+ goto reg_disable; - } - - return 0; --} -- --static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) --{ -- void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -- -- /* Check if other phy port active */ -- if (stm32_usbphyc_has_one_phy_active(usbphyc)) -- return 0; -- -- stm32_usbphyc_clr_bits(pll_reg, PLLEN); -- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -- udelay(PLL_PWR_DOWN_TIME_US); - -- if (readl_relaxed(pll_reg) & PLLEN) { -- dev_err(usbphyc->dev, "PLL not reset\n"); -- return -EIO; -- } -+reg_disable: -+ stm32_usbphyc_regulators_disable(usbphyc); - -- return 0; -+ return ret; - } - - static int stm32_usbphyc_phy_init(struct phy *phy) -@@ -231,28 +361,180 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) - return stm32_usbphyc_pll_disable(usbphyc); - } - --static int stm32_usbphyc_phy_power_on(struct phy *phy) -+static const struct phy_ops stm32_usbphyc_phy_ops = { -+ .init = stm32_usbphyc_phy_init, -+ .exit = stm32_usbphyc_phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) - { -- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); - -- return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ return stm32_usbphyc_pll_enable(usbphyc); - } - --static int stm32_usbphyc_phy_power_off(struct phy *phy) -+static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) - { -- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); - -- return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ stm32_usbphyc_pll_disable(usbphyc); - } - --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, -- .owner = THIS_MODULE, -+static int stm32_usbphyc_clk48_is_enabled(struct clk_hw *hw) -+{ -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); -+ -+ return readl_relaxed(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN; -+} -+ -+static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return 48000000; -+} -+ -+static const struct clk_ops usbphyc_clk48_ops = { -+ .prepare = stm32_usbphyc_clk48_prepare, -+ .unprepare = stm32_usbphyc_clk48_unprepare, -+ .is_enabled = stm32_usbphyc_clk48_is_enabled, -+ .recalc_rate = stm32_usbphyc_clk48_recalc_rate, - }; - -+static void stm32_usbphyc_clk48_unregister(void *data) -+{ -+ struct stm32_usbphyc *usbphyc = data; -+ -+ of_clk_del_provider(usbphyc->dev->of_node); -+ clk_hw_unregister(&usbphyc->clk48_hw); -+} -+ -+static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) -+{ -+ struct device_node *node = usbphyc->dev->of_node; -+ struct clk_init_data init = { }; -+ int ret = 0; -+ -+ init.name = "ck_usbo_48m"; -+ init.ops = &usbphyc_clk48_ops; -+ -+ usbphyc->clk48_hw.init = &init; -+ -+ ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); -+ if (ret) -+ return ret; -+ -+ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, -+ &usbphyc->clk48_hw); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action(usbphyc->dev, stm32_usbphyc_clk48_unregister, -+ usbphyc); -+ -+ return ret; -+} -+ -+static void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc, -+ struct device_node *np, u32 index) -+{ -+ struct device_node *tune_np; -+ u32 reg = STM32_USBPHYC_TUNE(index); -+ u32 otpcomp, val, tune = 0; -+ int ret; -+ -+ tune_np = of_parse_phandle(np, "st,phy-tuning", 0); -+ if (!tune_np) -+ return; -+ -+ /* Backup OTP compensation code */ -+ otpcomp = FIELD_GET(OTPCOMP, readl_relaxed(usbphyc->base + reg)); -+ -+ ret = of_property_read_u32(tune_np, "st,current-boost", &val); -+ if (!ret && val < BOOST_MAX) { -+ val = (val == BOOST_2_MA) ? 1 : 0; -+ tune |= INCURREN | FIELD_PREP(INCURRINT, val); -+ } else if (ret != -EINVAL) { -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,current-boost value\n", index); -+ } -+ -+ if (!of_property_read_bool(tune_np, "st,no-lsfs-fb-cap")) -+ tune |= LFSCAPEN; -+ -+ if (of_property_read_bool(tune_np, "st,hs-slew-ctrl")) -+ tune |= HSDRVSLEW; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-dc-level", &val); -+ if (!ret && val < DC_MAX) { -+ if (val == DC_MINUS_5_TO_7_MV) { -+ tune |= HSDRVDCCUR; -+ } else { -+ val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; -+ tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); -+ } -+ } else if (ret != -EINVAL) { -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-dc-level value\n", index); -+ } -+ -+ if (of_property_read_bool(tune_np, "st,fs-rftime-tuning")) -+ tune |= FSDRVRFADJ; -+ -+ if (of_property_read_bool(tune_np, "st,hs-rftime-reduction")) -+ tune |= HSDRVRFRED; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-current-trim", &val); -+ if (!ret && val < CUR_MAX) -+ tune |= FIELD_PREP(HSDRVCHKITRM, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-current-trim value\n", index); -+ -+ ret = of_property_read_u32(tune_np, "st,hs-impedance-trim", &val); -+ if (!ret && val < IMP_MAX) -+ tune |= FIELD_PREP(HSDRVCHKZTRM, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid hs-impedance-trim value\n", index); -+ -+ ret = of_property_read_u32(tune_np, "st,squelch-level", &val); -+ if (!ret && val < SQLCH_MAX) -+ tune |= FIELD_PREP(SQLCHCTL, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,squelch-level value\n", index); -+ -+ if (of_property_read_bool(tune_np, "st,hs-rx-gain-eq")) -+ tune |= HDRXGNEQEN; -+ -+ ret = of_property_read_u32(tune_np, "st,hs-rx-offset", &val); -+ if (!ret && val < RX_OFFSET_MAX) -+ tune |= FIELD_PREP(HSRXOFF, val); -+ else if (ret != -EINVAL) -+ dev_warn(usbphyc->dev, -+ "phy%d: invalid st,hs-rx-offset value\n", index); -+ -+ if (of_property_read_bool(tune_np, "st,no-hs-ftime-ctrl")) -+ tune |= HSFALLPREEM; -+ -+ if (!of_property_read_bool(tune_np, "st,no-lsfs-sc")) -+ tune |= SHTCCTCTLPROT; -+ -+ if (of_property_read_bool(tune_np, "st,hs-tx-staggering")) -+ tune |= STAGSEL; -+ -+ of_node_put(tune_np); -+ -+ /* Restore OTP compensation code */ -+ tune |= FIELD_PREP(OTPCOMP, otpcomp); -+ -+ writel_relaxed(tune, usbphyc->base + reg); -+} -+ - static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, - u32 utmi_switch) - { -@@ -345,7 +627,16 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - reset_control_assert(usbphyc->rst); - udelay(2); - reset_control_deassert(usbphyc->rst); -+ } else { -+ stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_PLL, -+ PLLEN); - } -+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ -+ udelay(PLL_PWR_DOWN_TIME_US); -+ -+ /* We have to ensure the PLL is disabled before phys initialization */ -+ if (readl_relaxed(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN) -+ return -EPROBE_DEFER; - - usbphyc->switch_setup = -EINVAL; - usbphyc->nphys = of_get_child_count(np); -@@ -356,11 +647,34 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto clk_disable; - } - -+ usbphyc->vdda1v1 = devm_regulator_get(dev, "vdda1v1"); -+ if (IS_ERR(usbphyc->vdda1v1)) { -+ ret = PTR_ERR(usbphyc->vdda1v1); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get vdda1v1 supply: %d\n", ret); -+ goto clk_disable; -+ } -+ -+ usbphyc->vdda1v8 = devm_regulator_get(dev, "vdda1v8"); -+ if (IS_ERR(usbphyc->vdda1v8)) { -+ ret = PTR_ERR(usbphyc->vdda1v8); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get vdda1v8 supply: %d\n", ret); -+ goto clk_disable; -+ } -+ -+ usbphyc->vdd3v3 = devm_regulator_get(dev, "vdd3v3"); -+ if (IS_ERR(usbphyc->vdd3v3)) { -+ ret = PTR_ERR(usbphyc->vdd3v3); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get vdd3v3 supply: %d\n", ret); -+ goto clk_disable; -+ } -+ - for_each_child_of_node(np, child) { - struct stm32_usbphyc_phy *usbphyc_phy; - struct phy *phy; - u32 index; -- int i; - - phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); - if (IS_ERR(phy)) { -@@ -378,24 +692,15 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto put_child; - } - -- for (i = 0; i < NUM_SUPPLIES; i++) -- usbphyc_phy->supplies[i].supply = supplies_names[i]; -- -- ret = devm_regulator_bulk_get(&phy->dev, NUM_SUPPLIES, -- usbphyc_phy->supplies); -- if (ret) { -- if (ret != -EPROBE_DEFER) -- dev_err(&phy->dev, -- "failed to get regulators: %d\n", ret); -- goto put_child; -- } -- - ret = of_property_read_u32(child, "reg", &index); - if (ret || index > usbphyc->nphys) { - dev_err(&phy->dev, "invalid reg property: %d\n", ret); - goto put_child; - } - -+ /* Configure phy tuning */ -+ stm32_usbphyc_phy_tuning(usbphyc, child, index); -+ - usbphyc->phys[port] = usbphyc_phy; - phy_set_bus_width(phy, 8); - phy_set_drvdata(phy, usbphyc_phy); -@@ -416,6 +721,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) - goto clk_disable; - } - -+ ret = stm32_usbphyc_clk48_register(usbphyc); -+ if (ret) { -+ dev_err(dev, -+ "failed to register ck_usbo_48m clock: %d\n", ret); -+ goto clk_disable; -+ } -+ - version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); - dev_info(dev, "registered rev:%lu.%lu\n", - FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); -@@ -439,6 +751,20 @@ static int stm32_usbphyc_remove(struct platform_device *pdev) - return 0; - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_usbphyc_resume(struct device *dev) -+{ -+ struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); -+ -+ if (usbphyc->switch_setup >= 0) -+ stm32_usbphyc_switch_setup(usbphyc, usbphyc->switch_setup); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_usbphyc_pm_ops, NULL, stm32_usbphyc_resume); -+ - static const struct of_device_id stm32_usbphyc_of_match[] = { - { .compatible = "st,stm32mp1-usbphyc", }, - { }, -@@ -451,6 +777,7 @@ static struct platform_driver stm32_usbphyc_driver = { - .driver = { - .of_match_table = stm32_usbphyc_of_match, - .name = "stm32-usbphyc", -+ .pm = &stm32_usbphyc_pm_ops, - } - }; - module_platform_driver(stm32_usbphyc_driver); -diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig -index e86752b..70ea304 100644 ---- a/drivers/pinctrl/Kconfig -+++ b/drivers/pinctrl/Kconfig -@@ -244,6 +244,20 @@ config PINCTRL_ST - select PINCONF - select GPIOLIB_IRQCHIP - -+config PINCTRL_STMFX -+ tristate "STMicroelectronics STMFX GPIO expander pinctrl driver" -+ depends on I2C -+ depends on OF_GPIO -+ select GENERIC_PINCONF -+ select GPIOLIB_IRQCHIP -+ select MFD_STMFX -+ help -+ Driver for STMicroelectronics Multi-Function eXpander (STMFX) -+ GPIO expander. -+ This provides a GPIO interface supporting inputs and outputs, -+ and configuring push-pull, open-drain, and can also be used as -+ interrupt-controller. -+ - config PINCTRL_U300 - bool "U300 pin controller driver" - depends on ARCH_U300 -diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile -index 46ef9bd..9abcaa59 100644 ---- a/drivers/pinctrl/Makefile -+++ b/drivers/pinctrl/Makefile -@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o - obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl-lpc18xx.o - obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o - obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o -+obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o - obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o - obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o - obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o -diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c -index c6ff4d5..7e747ac 100644 ---- a/drivers/pinctrl/core.c -+++ b/drivers/pinctrl/core.c -@@ -1216,6 +1216,15 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, - } - EXPORT_SYMBOL_GPL(pinctrl_lookup_state); - -+static void pinctrl_link_add(struct pinctrl_dev *pctldev, -+ struct device *consumer) -+{ -+ if (pctldev->desc->link_consumers) -+ device_link_add(consumer, pctldev->dev, -+ DL_FLAG_PM_RUNTIME | -+ DL_FLAG_AUTOREMOVE_CONSUMER); -+} -+ - /** - * pinctrl_commit_state() - select/activate/program a pinctrl state to HW - * @p: the pinctrl handle for the device that requests configuration -@@ -1261,6 +1270,10 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) - if (ret < 0) { - goto unapply_new_state; - } -+ -+ /* Do not link hogs (circular dependency) */ -+ if (p != setting->pctldev->p) -+ pinctrl_link_add(setting->pctldev, p->dev); - } - - p->state = state; -@@ -1992,7 +2005,7 @@ pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev, - return ERR_PTR(ret); - } - --static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev) -+int pinctrl_claim_hogs(struct pinctrl_dev *pctldev) - { - pctldev->p = create_pinctrl(pctldev->dev, pctldev); - if (PTR_ERR(pctldev->p) == -ENODEV) { -@@ -2030,21 +2043,10 @@ static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev) - - return 0; - } -+EXPORT_SYMBOL_GPL(pinctrl_claim_hogs); - - int pinctrl_enable(struct pinctrl_dev *pctldev) - { -- int error; -- -- error = pinctrl_claim_hogs(pctldev); -- if (error) { -- dev_err(pctldev->dev, "could not claim hogs: %i\n", -- error); -- mutex_destroy(&pctldev->mutex); -- kfree(pctldev); -- -- return error; -- } -- - mutex_lock(&pinctrldev_list_mutex); - list_add_tail(&pctldev->node, &pinctrldev_list); - mutex_unlock(&pinctrldev_list_mutex); -diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c -new file mode 100644 -index 0000000..b4c232a ---- /dev/null -+++ b/drivers/pinctrl/pinctrl-stmfx.c -@@ -0,0 +1,858 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander -+ * -+ * Copyright (C) 2019 STMicroelectronics -+ * Author(s): Amelie Delaunay . -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "core.h" -+#include "pinctrl-utils.h" -+ -+/* GPIOs expander */ -+/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */ -+#define STMFX_REG_GPIO_STATE STMFX_REG_GPIO_STATE1 /* R */ -+/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */ -+#define STMFX_REG_GPIO_DIR STMFX_REG_GPIO_DIR1 /* RW */ -+/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */ -+#define STMFX_REG_GPIO_TYPE STMFX_REG_GPIO_TYPE1 /* RW */ -+/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */ -+#define STMFX_REG_GPIO_PUPD STMFX_REG_GPIO_PUPD1 /* RW */ -+/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */ -+#define STMFX_REG_GPO_SET STMFX_REG_GPO_SET1 /* RW */ -+/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */ -+#define STMFX_REG_GPO_CLR STMFX_REG_GPO_CLR1 /* RW */ -+/* IRQ_GPI_SRC1 0x48, IRQ_GPI_SRC2 0x49, IRQ_GPI_SRC3 0x4A */ -+#define STMFX_REG_IRQ_GPI_SRC STMFX_REG_IRQ_GPI_SRC1 /* RW */ -+/* IRQ_GPI_EVT1 0x4C, IRQ_GPI_EVT2 0x4D, IRQ_GPI_EVT3 0x4E */ -+#define STMFX_REG_IRQ_GPI_EVT STMFX_REG_IRQ_GPI_EVT1 /* RW */ -+/* IRQ_GPI_TYPE1 0x50, IRQ_GPI_TYPE2 0x51, IRQ_GPI_TYPE3 0x52 */ -+#define STMFX_REG_IRQ_GPI_TYPE STMFX_REG_IRQ_GPI_TYPE1 /* RW */ -+/* IRQ_GPI_PENDING1 0x0C, IRQ_GPI_PENDING2 0x0D, IRQ_GPI_PENDING3 0x0E*/ -+#define STMFX_REG_IRQ_GPI_PENDING STMFX_REG_IRQ_GPI_PENDING1 /* R */ -+/* IRQ_GPI_ACK1 0x54, IRQ_GPI_ACK2 0x55, IRQ_GPI_ACK3 0x56 */ -+#define STMFX_REG_IRQ_GPI_ACK STMFX_REG_IRQ_GPI_ACK1 /* RW */ -+ -+#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))) -+ -+/* -+ * STMFX pinctrl can have up to 24 pins if STMFX other functions are not used. -+ * Pins availability is managed thanks to gpio-ranges property. -+ */ -+static const struct pinctrl_pin_desc stmfx_pins[] = { -+ PINCTRL_PIN(0, "gpio0"), -+ PINCTRL_PIN(1, "gpio1"), -+ PINCTRL_PIN(2, "gpio2"), -+ PINCTRL_PIN(3, "gpio3"), -+ PINCTRL_PIN(4, "gpio4"), -+ PINCTRL_PIN(5, "gpio5"), -+ PINCTRL_PIN(6, "gpio6"), -+ PINCTRL_PIN(7, "gpio7"), -+ PINCTRL_PIN(8, "gpio8"), -+ PINCTRL_PIN(9, "gpio9"), -+ PINCTRL_PIN(10, "gpio10"), -+ PINCTRL_PIN(11, "gpio11"), -+ PINCTRL_PIN(12, "gpio12"), -+ PINCTRL_PIN(13, "gpio13"), -+ PINCTRL_PIN(14, "gpio14"), -+ PINCTRL_PIN(15, "gpio15"), -+ PINCTRL_PIN(16, "agpio0"), -+ PINCTRL_PIN(17, "agpio1"), -+ PINCTRL_PIN(18, "agpio2"), -+ PINCTRL_PIN(19, "agpio3"), -+ PINCTRL_PIN(20, "agpio4"), -+ PINCTRL_PIN(21, "agpio5"), -+ PINCTRL_PIN(22, "agpio6"), -+ PINCTRL_PIN(23, "agpio7"), -+}; -+ -+struct stmfx_pinctrl { -+ struct device *dev; -+ struct stmfx *stmfx; -+ struct pinctrl_dev *pctl_dev; -+ struct pinctrl_desc pctl_desc; -+ struct gpio_chip gpio_chip; -+ struct irq_chip irq_chip; -+ struct mutex lock; /* IRQ bus lock */ -+ unsigned long gpio_valid_mask; -+ /* Cache of IRQ_GPI_* registers for bus_lock */ -+ u8 irq_gpi_src[NR_GPIO_REGS]; -+ u8 irq_gpi_type[NR_GPIO_REGS]; -+ u8 irq_gpi_evt[NR_GPIO_REGS]; -+ u8 irq_toggle_edge[NR_GPIO_REGS]; -+#ifdef CONFIG_PM -+ /* Backup of GPIO_* registers for suspend/resume */ -+ u8 bkp_gpio_state[NR_GPIO_REGS]; -+ u8 bkp_gpio_dir[NR_GPIO_REGS]; -+ u8 bkp_gpio_type[NR_GPIO_REGS]; -+ u8 bkp_gpio_pupd[NR_GPIO_REGS]; -+#endif -+}; -+ -+static int stmfx_gpio_get(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); -+ u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset); -+ u32 mask = get_mask(offset); -+ u32 value; -+ int ret; -+ -+ ret = regmap_read(pctl->stmfx->map, reg, &value); -+ -+ return ret ? ret : !!(value & mask); -+} -+ -+static void stmfx_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) -+{ -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); -+ u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR; -+ u32 mask = get_mask(offset); -+ -+ regmap_write_bits(pctl->stmfx->map, reg + get_reg(offset), -+ mask, mask); -+} -+ -+static int stmfx_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); -+ u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); -+ u32 mask = get_mask(offset); -+ u32 val; -+ int ret; -+ -+ ret = regmap_read(pctl->stmfx->map, reg, &val); -+ /* -+ * On stmfx, gpio pins direction is (0)input, (1)output. -+ * .get_direction returns 0=out, 1=in -+ */ -+ -+ return ret ? ret : !(val & mask); -+} -+ -+static int stmfx_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); -+ u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); -+ u32 mask = get_mask(offset); -+ -+ return regmap_write_bits(pctl->stmfx->map, reg, mask, 0); -+} -+ -+static int stmfx_gpio_direction_output(struct gpio_chip *gc, -+ unsigned int offset, int value) -+{ -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); -+ u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); -+ u32 mask = get_mask(offset); -+ -+ stmfx_gpio_set(gc, offset, value); -+ -+ return regmap_write_bits(pctl->stmfx->map, reg, mask, mask); -+} -+ -+static int stmfx_pinconf_get_pupd(struct stmfx_pinctrl *pctl, -+ unsigned int offset) -+{ -+ u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset); -+ u32 pupd, mask = get_mask(offset); -+ int ret; -+ -+ ret = regmap_read(pctl->stmfx->map, reg, &pupd); -+ if (ret) -+ return ret; -+ -+ return !!(pupd & mask); -+} -+ -+static int stmfx_pinconf_set_pupd(struct stmfx_pinctrl *pctl, -+ unsigned int offset, u32 pupd) -+{ -+ u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset); -+ u32 mask = get_mask(offset); -+ -+ return regmap_write_bits(pctl->stmfx->map, reg, mask, pupd ? mask : 0); -+} -+ -+static int stmfx_pinconf_get_type(struct stmfx_pinctrl *pctl, -+ unsigned int offset) -+{ -+ u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset); -+ u32 type, mask = get_mask(offset); -+ int ret; -+ -+ ret = regmap_read(pctl->stmfx->map, reg, &type); -+ if (ret) -+ return ret; -+ -+ return !!(type & mask); -+} -+ -+static int stmfx_pinconf_set_type(struct stmfx_pinctrl *pctl, -+ unsigned int offset, u32 type) -+{ -+ u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset); -+ u32 mask = get_mask(offset); -+ -+ return regmap_write_bits(pctl->stmfx->map, reg, mask, type ? mask : 0); -+} -+ -+static int stmfx_pinconf_get(struct pinctrl_dev *pctldev, -+ unsigned int pin, unsigned long *config) -+{ -+ struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ u32 param = pinconf_to_config_param(*config); -+ struct pinctrl_gpio_range *range; -+ u32 arg = 0; -+ int ret, dir, type, pupd; -+ -+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); -+ if (!range) -+ return -EINVAL; -+ -+ dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin); -+ if (dir < 0) -+ return dir; -+ type = stmfx_pinconf_get_type(pctl, pin); -+ if (type < 0) -+ return type; -+ pupd = stmfx_pinconf_get_pupd(pctl, pin); -+ if (pupd < 0) -+ return pupd; -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ if ((!dir && (!type || !pupd)) || (dir && !type)) -+ arg = 1; -+ break; -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ if (dir && type && !pupd) -+ arg = 1; -+ break; -+ case PIN_CONFIG_BIAS_PULL_UP: -+ if (type && pupd) -+ arg = 1; -+ break; -+ case PIN_CONFIG_DRIVE_OPEN_DRAIN: -+ if ((!dir && type) || (dir && !type)) -+ arg = 1; -+ break; -+ case PIN_CONFIG_DRIVE_PUSH_PULL: -+ if ((!dir && !type) || (dir && type)) -+ arg = 1; -+ break; -+ case PIN_CONFIG_OUTPUT: -+ if (dir) -+ return -EINVAL; -+ -+ ret = stmfx_gpio_get(&pctl->gpio_chip, pin); -+ if (ret < 0) -+ return ret; -+ -+ arg = ret; -+ break; -+ default: -+ return -ENOTSUPP; -+ } -+ -+ *config = pinconf_to_config_packed(param, arg); -+ -+ return 0; -+} -+ -+static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *configs, unsigned int num_configs) -+{ -+ struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ struct pinctrl_gpio_range *range; -+ enum pin_config_param param; -+ u32 arg; -+ int dir, i, ret; -+ -+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); -+ if (!range) { -+ dev_err(pctldev->dev, "pin %d is not available\n", pin); -+ return -EINVAL; -+ } -+ -+ dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin); -+ if (dir < 0) -+ return dir; -+ -+ for (i = 0; i < num_configs; i++) { -+ param = pinconf_to_config_param(configs[i]); -+ arg = pinconf_to_config_argument(configs[i]); -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: -+ case PIN_CONFIG_BIAS_DISABLE: -+ case PIN_CONFIG_DRIVE_PUSH_PULL: -+ ret = stmfx_pinconf_set_type(pctl, pin, 0); -+ if (ret) -+ return ret; -+ break; -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ ret = stmfx_pinconf_set_type(pctl, pin, 1); -+ if (ret) -+ return ret; -+ ret = stmfx_pinconf_set_pupd(pctl, pin, 0); -+ if (ret) -+ return ret; -+ break; -+ case PIN_CONFIG_BIAS_PULL_UP: -+ ret = stmfx_pinconf_set_type(pctl, pin, 1); -+ if (ret) -+ return ret; -+ ret = stmfx_pinconf_set_pupd(pctl, pin, 1); -+ if (ret) -+ return ret; -+ break; -+ case PIN_CONFIG_DRIVE_OPEN_DRAIN: -+ ret = stmfx_pinconf_set_type(pctl, pin, 1); -+ if (ret) -+ return ret; -+ break; -+ case PIN_CONFIG_OUTPUT: -+ ret = stmfx_gpio_direction_output(&pctl->gpio_chip, -+ pin, arg); -+ if (ret) -+ return ret; -+ break; -+ default: -+ return -ENOTSUPP; -+ } -+ } -+ -+ return 0; -+} -+ -+static void stmfx_pinconf_dbg_show(struct pinctrl_dev *pctldev, -+ struct seq_file *s, unsigned int offset) -+{ -+ struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ struct pinctrl_gpio_range *range; -+ int dir, type, pupd, val; -+ -+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, offset); -+ if (!range) -+ return; -+ -+ dir = stmfx_gpio_get_direction(&pctl->gpio_chip, offset); -+ if (dir < 0) -+ return; -+ type = stmfx_pinconf_get_type(pctl, offset); -+ if (type < 0) -+ return; -+ pupd = stmfx_pinconf_get_pupd(pctl, offset); -+ if (pupd < 0) -+ return; -+ val = stmfx_gpio_get(&pctl->gpio_chip, offset); -+ if (val < 0) -+ return; -+ -+ if (!dir) { -+ seq_printf(s, "output %s ", val ? "high" : "low"); -+ if (type) -+ seq_printf(s, "open drain %s internal pull-up ", -+ pupd ? "with" : "without"); -+ else -+ seq_puts(s, "push pull no pull "); -+ } else { -+ seq_printf(s, "input %s ", val ? "high" : "low"); -+ if (type) -+ seq_printf(s, "with internal pull-%s ", -+ pupd ? "up" : "down"); -+ else -+ seq_printf(s, "%s ", pupd ? "floating" : "analog"); -+ } -+} -+ -+static const struct pinconf_ops stmfx_pinconf_ops = { -+ .pin_config_get = stmfx_pinconf_get, -+ .pin_config_set = stmfx_pinconf_set, -+ .pin_config_dbg_show = stmfx_pinconf_dbg_show, -+}; -+ -+static int stmfx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) -+{ -+ return 0; -+} -+ -+static const char *stmfx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, -+ unsigned int selector) -+{ -+ return NULL; -+} -+ -+static int stmfx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, -+ unsigned int selector, -+ const unsigned int **pins, -+ unsigned int *num_pins) -+{ -+ return -ENOTSUPP; -+} -+ -+static const struct pinctrl_ops stmfx_pinctrl_ops = { -+ .get_groups_count = stmfx_pinctrl_get_groups_count, -+ .get_group_name = stmfx_pinctrl_get_group_name, -+ .get_group_pins = stmfx_pinctrl_get_group_pins, -+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, -+ .dt_free_map = pinctrl_utils_free_map, -+}; -+ -+static void stmfx_pinctrl_irq_mask(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ u32 reg = get_reg(data->hwirq); -+ u32 mask = get_mask(data->hwirq); -+ -+ pctl->irq_gpi_src[reg] &= ~mask; -+} -+ -+static void stmfx_pinctrl_irq_unmask(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ u32 reg = get_reg(data->hwirq); -+ u32 mask = get_mask(data->hwirq); -+ -+ pctl->irq_gpi_src[reg] |= mask; -+} -+ -+static int stmfx_pinctrl_irq_set_type(struct irq_data *data, unsigned int type) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ u32 reg = get_reg(data->hwirq); -+ u32 mask = get_mask(data->hwirq); -+ -+ if (type == IRQ_TYPE_NONE) -+ return -EINVAL; -+ -+ if (type & IRQ_TYPE_EDGE_BOTH) { -+ pctl->irq_gpi_evt[reg] |= mask; -+ irq_set_handler_locked(data, handle_edge_irq); -+ } else { -+ pctl->irq_gpi_evt[reg] &= ~mask; -+ irq_set_handler_locked(data, handle_level_irq); -+ } -+ -+ if ((type & IRQ_TYPE_EDGE_RISING) || (type & IRQ_TYPE_LEVEL_HIGH)) -+ pctl->irq_gpi_type[reg] |= mask; -+ else -+ pctl->irq_gpi_type[reg] &= ~mask; -+ -+ /* -+ * In case of (type & IRQ_TYPE_EDGE_BOTH), we need to know current -+ * GPIO value to set the right edge trigger. But in atomic context -+ * here we can't access registers over I2C. That's why (type & -+ * IRQ_TYPE_EDGE_BOTH) will be managed in .irq_sync_unlock. -+ */ -+ -+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) -+ pctl->irq_toggle_edge[reg] |= mask; -+ else -+ pctl->irq_toggle_edge[reg] &= mask; -+ -+ return 0; -+} -+ -+static void stmfx_pinctrl_irq_bus_lock(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ -+ mutex_lock(&pctl->lock); -+} -+ -+static void stmfx_pinctrl_irq_bus_sync_unlock(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ u32 reg = get_reg(data->hwirq); -+ u32 mask = get_mask(data->hwirq); -+ -+ /* -+ * In case of IRQ_TYPE_EDGE_BOTH), read the current GPIO value -+ * (this couldn't be done in .irq_set_type because of atomic context) -+ * to set the right irq trigger type. -+ */ -+ if (pctl->irq_toggle_edge[reg] & mask) { -+ if (stmfx_gpio_get(gpio_chip, data->hwirq)) -+ pctl->irq_gpi_type[reg] &= ~mask; -+ else -+ pctl->irq_gpi_type[reg] |= mask; -+ } -+ -+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT, -+ pctl->irq_gpi_evt, NR_GPIO_REGS); -+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE, -+ pctl->irq_gpi_type, NR_GPIO_REGS); -+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, -+ pctl->irq_gpi_src, NR_GPIO_REGS); -+ -+ mutex_unlock(&pctl->lock); -+} -+ -+static int stmfx_gpio_irq_request_resources(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ int ret; -+ -+ ret = stmfx_gpio_direction_input(&pctl->gpio_chip, data->hwirq); -+ if (ret) -+ return ret; -+ -+ ret = gpiochip_lock_as_irq(&pctl->gpio_chip, data->hwirq); -+ if (ret) { -+ dev_err(pctl->dev, "Unable to lock gpio %lu as IRQ: %d\n", -+ data->hwirq, ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void stmfx_gpio_irq_release_resources(struct irq_data *data) -+{ -+ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); -+ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); -+ -+ gpiochip_unlock_as_irq(&pctl->gpio_chip, data->hwirq); -+} -+ -+static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl, -+ unsigned int offset) -+{ -+ u32 reg = get_reg(offset); -+ u32 mask = get_mask(offset); -+ int val; -+ -+ if (!(pctl->irq_toggle_edge[reg] & mask)) -+ return; -+ -+ val = stmfx_gpio_get(&pctl->gpio_chip, offset); -+ if (val < 0) -+ return; -+ -+ if (val) { -+ pctl->irq_gpi_type[reg] &= mask; -+ regmap_write_bits(pctl->stmfx->map, -+ STMFX_REG_IRQ_GPI_TYPE + reg, -+ mask, 0); -+ -+ } else { -+ pctl->irq_gpi_type[reg] |= mask; -+ regmap_write_bits(pctl->stmfx->map, -+ STMFX_REG_IRQ_GPI_TYPE + reg, -+ mask, mask); -+ } -+} -+ -+static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id) -+{ -+ struct stmfx_pinctrl *pctl = (struct stmfx_pinctrl *)dev_id; -+ struct gpio_chip *gc = &pctl->gpio_chip; -+ u8 pending[NR_GPIO_REGS]; -+ u8 src[NR_GPIO_REGS] = {0, 0, 0}; -+ unsigned long n, status; -+ int ret; -+ -+ ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_IRQ_GPI_PENDING, -+ &pending, NR_GPIO_REGS); -+ if (ret) -+ return IRQ_NONE; -+ -+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, -+ src, NR_GPIO_REGS); -+ -+ status = *(unsigned long *)pending; -+ for_each_set_bit(n, &status, gc->ngpio) { -+ handle_nested_irq(irq_find_mapping(gc->irq.domain, n)); -+ stmfx_pinctrl_irq_toggle_trigger(pctl, n); -+ } -+ -+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, -+ pctl->irq_gpi_src, NR_GPIO_REGS); -+ -+ return IRQ_HANDLED; -+} -+ -+static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl) -+{ -+ struct pinctrl_gpio_range *gpio_range; -+ struct pinctrl_dev *pctl_dev = pctl->pctl_dev; -+ u32 func = STMFX_FUNC_GPIO; -+ -+ pctl->gpio_valid_mask = GENMASK(15, 0); -+ -+ gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 16); -+ if (gpio_range) { -+ func |= STMFX_FUNC_ALTGPIO_LOW; -+ pctl->gpio_valid_mask |= GENMASK(19, 16); -+ } -+ -+ gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 20); -+ if (gpio_range) { -+ func |= STMFX_FUNC_ALTGPIO_HIGH; -+ pctl->gpio_valid_mask |= GENMASK(23, 20); -+ } -+ -+ return stmfx_function_enable(pctl->stmfx, func); -+} -+ -+static int stmfx_pinctrl_probe(struct platform_device *pdev) -+{ -+ struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent); -+ struct device_node *np = pdev->dev.of_node; -+ struct stmfx_pinctrl *pctl; -+ u32 n; -+ int irq, ret; -+ -+ pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL); -+ if (!pctl) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, pctl); -+ -+ pctl->dev = &pdev->dev; -+ pctl->stmfx = stmfx; -+ -+ if (!of_find_property(np, "gpio-ranges", NULL)) { -+ dev_err(pctl->dev, "missing required gpio-ranges property\n"); -+ return -EINVAL; -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq <= 0) { -+ dev_err(pctl->dev, "failed to get irq\n"); -+ return -ENXIO; -+ } -+ -+ mutex_init(&pctl->lock); -+ -+ /* Register pin controller */ -+ pctl->pctl_desc.name = "stmfx-pinctrl"; -+ pctl->pctl_desc.pctlops = &stmfx_pinctrl_ops; -+ pctl->pctl_desc.confops = &stmfx_pinconf_ops; -+ pctl->pctl_desc.pins = stmfx_pins; -+ pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins); -+ pctl->pctl_desc.owner = THIS_MODULE; -+ pctl->pctl_desc.link_consumers = true; -+ -+ ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc, -+ pctl, &pctl->pctl_dev); -+ if (ret) { -+ dev_err(pctl->dev, "pinctrl registration failed\n"); -+ return ret; -+ } -+ -+ ret = pinctrl_enable(pctl->pctl_dev); -+ if (ret) { -+ dev_err(pctl->dev, "pinctrl enable failed\n"); -+ return ret; -+ } -+ -+ /* Register gpio controller */ -+ pctl->gpio_chip.label = "stmfx-gpio"; -+ pctl->gpio_chip.parent = pctl->dev; -+ pctl->gpio_chip.get_direction = stmfx_gpio_get_direction; -+ pctl->gpio_chip.direction_input = stmfx_gpio_direction_input; -+ pctl->gpio_chip.direction_output = stmfx_gpio_direction_output; -+ pctl->gpio_chip.get = stmfx_gpio_get; -+ pctl->gpio_chip.set = stmfx_gpio_set; -+ pctl->gpio_chip.set_config = gpiochip_generic_config; -+ pctl->gpio_chip.base = -1; -+ pctl->gpio_chip.ngpio = pctl->pctl_desc.npins; -+ pctl->gpio_chip.can_sleep = true; -+ pctl->gpio_chip.of_node = np; -+ pctl->gpio_chip.need_valid_mask = true; -+ -+ ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl); -+ if (ret) { -+ dev_err(pctl->dev, "gpio_chip registration failed\n"); -+ return ret; -+ } -+ -+ ret = stmfx_pinctrl_gpio_function_enable(pctl); -+ if (ret) -+ return ret; -+ -+ /* -+ * Claim hogs after enabling gpio function, otherwise pin -+ * configuration will not apply -+ */ -+ ret = pinctrl_claim_hogs(pctl->pctl_dev); -+ if (ret) -+ return ret; -+ -+ pctl->irq_chip.name = dev_name(pctl->dev); -+ pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask; -+ pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask; -+ pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type; -+ pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock; -+ pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock; -+ pctl->irq_chip.irq_request_resources = stmfx_gpio_irq_request_resources; -+ pctl->irq_chip.irq_release_resources = stmfx_gpio_irq_release_resources; -+ for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio) -+ clear_bit(n, pctl->gpio_chip.valid_mask); -+ -+ ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip, -+ 0, handle_bad_irq, IRQ_TYPE_NONE); -+ if (ret) { -+ dev_err(pctl->dev, "cannot add irqchip to gpiochip\n"); -+ return ret; -+ } -+ -+ ret = devm_request_threaded_irq(pctl->dev, irq, NULL, -+ stmfx_pinctrl_irq_thread_fn, -+ IRQF_ONESHOT, -+ pctl->irq_chip.name, pctl); -+ if (ret) { -+ dev_err(pctl->dev, "cannot request irq%d\n", irq); -+ return ret; -+ } -+ -+ gpiochip_set_nested_irqchip(&pctl->gpio_chip, &pctl->irq_chip, irq); -+ -+ dev_info(pctl->dev, -+ "%ld GPIOs available\n", hweight_long(pctl->gpio_valid_mask)); -+ -+ return 0; -+} -+ -+static int stmfx_pinctrl_remove(struct platform_device *pdev) -+{ -+ struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent); -+ -+ return stmfx_function_disable(stmfx, -+ STMFX_FUNC_GPIO | -+ STMFX_FUNC_ALTGPIO_LOW | -+ STMFX_FUNC_ALTGPIO_HIGH); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stmfx_pinctrl_backup_regs(struct stmfx_pinctrl *pctl) -+{ -+ int ret; -+ -+ ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_STATE, -+ &pctl->bkp_gpio_state, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_DIR, -+ &pctl->bkp_gpio_dir, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_TYPE, -+ &pctl->bkp_gpio_type, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_PUPD, -+ &pctl->bkp_gpio_pupd, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int stmfx_pinctrl_restore_regs(struct stmfx_pinctrl *pctl) -+{ -+ int ret; -+ -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_DIR, -+ pctl->bkp_gpio_dir, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_TYPE, -+ pctl->bkp_gpio_type, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_PUPD, -+ pctl->bkp_gpio_pupd, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPO_SET, -+ pctl->bkp_gpio_state, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT, -+ pctl->irq_gpi_evt, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE, -+ pctl->irq_gpi_type, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, -+ pctl->irq_gpi_src, NR_GPIO_REGS); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int stmfx_pinctrl_suspend(struct device *dev) -+{ -+ struct stmfx_pinctrl *pctl = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = stmfx_pinctrl_backup_regs(pctl); -+ if (ret) { -+ dev_err(pctl->dev, "registers backup failure\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int stmfx_pinctrl_resume(struct device *dev) -+{ -+ struct stmfx_pinctrl *pctl = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = stmfx_pinctrl_restore_regs(pctl); -+ if (ret) { -+ dev_err(pctl->dev, "registers restoration failure\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stmfx_pinctrl_dev_pm_ops, -+ stmfx_pinctrl_suspend, stmfx_pinctrl_resume); -+ -+static const struct of_device_id stmfx_pinctrl_of_match[] = { -+ { .compatible = "st,stmfx-0300-pinctrl", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stmfx_pinctrl_of_match); -+ -+static struct platform_driver stmfx_pinctrl_driver = { -+ .driver = { -+ .name = "stmfx-pinctrl", -+ .of_match_table = stmfx_pinctrl_of_match, -+ .pm = &stmfx_pinctrl_dev_pm_ops, -+ }, -+ .probe = stmfx_pinctrl_probe, -+ .remove = stmfx_pinctrl_remove, -+}; -+module_platform_driver(stmfx_pinctrl_driver); -+ -+MODULE_DESCRIPTION("STMFX pinctrl/GPIO driver"); -+MODULE_AUTHOR("Amelie Delaunay "); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index 14dfbbd..4f2676b 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -7,7 +7,9 @@ - * Heavily based on Mediatek's pinctrl driver - */ - #include -+#include - #include -+#include - #include - #include - #include -@@ -31,6 +33,7 @@ - #include "../pinconf.h" - #include "../pinctrl-utils.h" - #include "pinctrl-stm32.h" -+#include "../pinmux.h" - - #define STM32_GPIO_MODER 0x00 - #define STM32_GPIO_TYPER 0x04 -@@ -43,6 +46,18 @@ - #define STM32_GPIO_AFRL 0x20 - #define STM32_GPIO_AFRH 0x24 - -+/* custom bitfield to backup pin status */ -+#define STM32_GPIO_BKP_MODE_SHIFT 0 -+#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0) -+#define STM32_GPIO_BKP_ALT_SHIFT 2 -+#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2) -+#define STM32_GPIO_BKP_SPEED_SHIFT 6 -+#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6) -+#define STM32_GPIO_BKP_PUPD_SHIFT 8 -+#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8) -+#define STM32_GPIO_BKP_TYPE 10 -+#define STM32_GPIO_BKP_VAL 11 -+ - #define STM32_GPIO_PINS_PER_BANK 16 - #define STM32_GPIO_IRQ_LINE 16 - -@@ -51,6 +66,9 @@ - #define gpio_range_to_bank(chip) \ - container_of(chip, struct stm32_gpio_bank, range) - -+#define HWSPNLCK_TIMEOUT 1000 /* usec */ -+#define HWSPNLCK_RETRY_DELAY 100 /* usec */ -+ - static const char * const stm32_gpio_functions[] = { - "gpio", "af0", "af1", - "af2", "af3", "af4", -@@ -58,6 +76,7 @@ static const char * const stm32_gpio_functions[] = { - "af8", "af9", "af10", - "af11", "af12", "af13", - "af14", "af15", "analog", -+ "reserved", - }; - - struct stm32_pinctrl_group { -@@ -76,6 +95,9 @@ struct stm32_gpio_bank { - struct irq_domain *domain; - u32 bank_nr; - u32 bank_ioport_nr; -+#ifdef CONFIG_PM -+ u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; -+#endif - }; - - struct stm32_pinctrl { -@@ -91,6 +113,13 @@ struct stm32_pinctrl { - struct irq_domain *domain; - struct regmap *regmap; - struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK]; -+ u16 irqmux_map; -+ spinlock_t irqmux_lock; /* interrupt mux lock */ -+ struct stm32_desc_pin *pins; -+ u32 npins; -+ u32 pkg; -+ u32 pin_base_shift; -+ struct hwspinlock *hwlock; - }; - - static inline int stm32_gpio_pin(int gpio) -@@ -126,11 +155,33 @@ static inline u32 stm32_gpio_get_alt(u32 function) - return 0; - } - -+static int stm32_pctrl_hwspin_lock_timeout(struct hwspinlock *hwlock) -+{ -+ int ret, timeout = 0; -+ -+ /* -+ * Use the x_raw API since we are under spin_lock protection and do not -+ * use the x_timeout API because we are under irq_disable mode -+ */ -+ do { -+ ret = hwspin_trylock_raw(hwlock); -+ if (!ret) -+ return ret; -+ -+ udelay(HWSPNLCK_RETRY_DELAY); -+ timeout += HWSPNLCK_RETRY_DELAY; -+ } while (timeout < HWSPNLCK_TIMEOUT); -+ -+ return ret == -EBUSY ? -ETIMEDOUT : ret; -+} -+ - /* GPIO functions */ - - static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank, - unsigned offset, int value) - { -+ stm32_gpio_backup_value(bank, offset, value); -+ - if (!value) - offset += STM32_GPIO_PINS_PER_BANK; - -@@ -300,9 +351,40 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, - { - struct stm32_gpio_bank *bank = d->host_data; - struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -+ unsigned long flags; -+ int ret = 0; -+ -+ /* -+ * gpio irq mux is shared between several banks, a lock has to be done -+ * to avoid overriding. -+ */ -+ spin_lock_irqsave(&pctl->irqmux_lock, flags); -+ -+ if (pctl->irqmux_map & BIT(irq_data->hwirq)) { -+ dev_err(pctl->dev, "irq line %ld already requested.\n", -+ irq_data->hwirq); -+ ret = -EBUSY; -+ goto unlock; -+ } else { -+ pctl->irqmux_map |= BIT(irq_data->hwirq); -+ } - - regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); -- return 0; -+unlock: -+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); -+ return ret; -+} -+ -+static void stm32_gpio_domain_deactivate(struct irq_domain *d, -+ struct irq_data *irq_data) -+{ -+ struct stm32_gpio_bank *bank = d->host_data; -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&pctl->irqmux_lock, flags); -+ pctl->irqmux_map &= ~BIT(irq_data->hwirq); -+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); - } - - static int stm32_gpio_domain_alloc(struct irq_domain *d, -@@ -331,6 +413,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = { - .alloc = stm32_gpio_domain_alloc, - .free = irq_domain_free_irqs_common, - .activate = stm32_gpio_domain_activate, -+ .deactivate = stm32_gpio_domain_deactivate, - }; - - /* Pinctrl functions */ -@@ -352,16 +435,19 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) - static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, - u32 pin_num, u32 fnum) - { -- int i; -+ int i, k; - -- for (i = 0; i < pctl->match_data->npins; i++) { -- const struct stm32_desc_pin *pin = pctl->match_data->pins + i; -+ for (i = 0; i < pctl->npins; i++) { -+ const struct stm32_desc_pin *pin = pctl->pins + i; - const struct stm32_desc_function *func = pin->functions; - - if (pin->pin.number != pin_num) - continue; - -- while (func && func->name) { -+ if (fnum == STM32_PIN_RSVD) -+ return true; -+ -+ for (k = 0; k < STM32_CONFIG_NUM; k++) { - if (func->num == fnum) - return true; - func++; -@@ -579,17 +665,27 @@ static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev, - return 0; - } - --static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, -- int pin, u32 mode, u32 alt) -+static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, -+ int pin, u32 mode, u32 alt) - { -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); - u32 val; - int alt_shift = (pin % 8) * 4; - int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4; - unsigned long flags; -+ int err = 0; - - clk_enable(bank->clk); - spin_lock_irqsave(&bank->lock, flags); - -+ if (pctl->hwlock) { -+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock); -+ if (err) { -+ dev_err(pctl->dev, "Can't get hwspinlock\n"); -+ goto unlock; -+ } -+ } -+ - val = readl_relaxed(bank->base + alt_offset); - val &= ~GENMASK(alt_shift + 3, alt_shift); - val |= (alt << alt_shift); -@@ -600,8 +696,15 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, - val |= mode << (pin * 2); - writel_relaxed(val, bank->base + STM32_GPIO_MODER); - -+ stm32_gpio_backup_mode(bank, pin, mode, alt); -+ -+ if (pctl->hwlock) -+ hwspin_unlock_raw(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); -+ return err; - } - - void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, -@@ -652,15 +755,18 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, - return -EINVAL; - } - -+ if (function == STM32_PIN_RSVD) { -+ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); -+ return 0; -+ } -+ - bank = gpiochip_get_data(range->gc); - pin = stm32_gpio_pin(g->pin); - - mode = stm32_gpio_get_mode(function); - alt = stm32_gpio_get_alt(function); - -- stm32_pmx_set_mode(bank, pin, mode, alt); -- -- return 0; -+ return stm32_pmx_set_mode(bank, pin, mode, alt); - } - - static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, -@@ -670,9 +776,7 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, - struct stm32_gpio_bank *bank = gpiochip_get_data(range->gc); - int pin = stm32_gpio_pin(gpio); - -- stm32_pmx_set_mode(bank, pin, !input, 0); -- -- return 0; -+ return stm32_pmx_set_mode(bank, pin, !input, 0); - } - - static const struct pinmux_ops stm32_pmx_ops = { -@@ -686,22 +790,39 @@ static const struct pinmux_ops stm32_pmx_ops = { - - /* Pinconf functions */ - --static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank, -- unsigned offset, u32 drive) -+static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, -+ unsigned offset, u32 drive) - { -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); - unsigned long flags; - u32 val; -+ int err = 0; - - clk_enable(bank->clk); - spin_lock_irqsave(&bank->lock, flags); - -+ if (pctl->hwlock) { -+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock); -+ if (err) { -+ dev_err(pctl->dev, "Can't get hwspinlock\n"); -+ goto unlock; -+ } -+ } -+ - val = readl_relaxed(bank->base + STM32_GPIO_TYPER); - val &= ~BIT(offset); - val |= drive << offset; - writel_relaxed(val, bank->base + STM32_GPIO_TYPER); - -+ stm32_gpio_backup_driving(bank, offset, drive); -+ -+ if (pctl->hwlock) -+ hwspin_unlock_raw(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); -+ return err; - } - - static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, -@@ -722,22 +843,39 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, - return (val >> offset); - } - --static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank, -- unsigned offset, u32 speed) -+static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, -+ unsigned offset, u32 speed) - { -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); - unsigned long flags; - u32 val; -+ int err = 0; - - clk_enable(bank->clk); - spin_lock_irqsave(&bank->lock, flags); - -+ if (pctl->hwlock) { -+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock); -+ if (err) { -+ dev_err(pctl->dev, "Can't get hwspinlock\n"); -+ goto unlock; -+ } -+ } -+ - val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); - val &= ~GENMASK(offset * 2 + 1, offset * 2); - val |= speed << (offset * 2); - writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR); - -+ stm32_gpio_backup_speed(bank, offset, speed); -+ -+ if (pctl->hwlock) -+ hwspin_unlock_raw(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); -+ return err; - } - - static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, -@@ -758,22 +896,39 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, - return (val >> (offset * 2)); - } - --static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank, -- unsigned offset, u32 bias) -+static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, -+ unsigned offset, u32 bias) - { -+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); - unsigned long flags; - u32 val; -+ int err = 0; - - clk_enable(bank->clk); - spin_lock_irqsave(&bank->lock, flags); - -+ if (pctl->hwlock) { -+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock); -+ if (err) { -+ dev_err(pctl->dev, "Can't get hwspinlock\n"); -+ goto unlock; -+ } -+ } -+ - val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); - val &= ~GENMASK(offset * 2 + 1, offset * 2); - val |= bias << (offset * 2); - writel_relaxed(val, bank->base + STM32_GPIO_PUPDR); - -+ stm32_gpio_backup_bias(bank, offset, bias); -+ -+ if (pctl->hwlock) -+ hwspin_unlock_raw(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); -+ return err; - } - - static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank, -@@ -836,22 +991,22 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, - - switch (param) { - case PIN_CONFIG_DRIVE_PUSH_PULL: -- stm32_pconf_set_driving(bank, offset, 0); -+ ret = stm32_pconf_set_driving(bank, offset, 0); - break; - case PIN_CONFIG_DRIVE_OPEN_DRAIN: -- stm32_pconf_set_driving(bank, offset, 1); -+ ret = stm32_pconf_set_driving(bank, offset, 1); - break; - case PIN_CONFIG_SLEW_RATE: -- stm32_pconf_set_speed(bank, offset, arg); -+ ret = stm32_pconf_set_speed(bank, offset, arg); - break; - case PIN_CONFIG_BIAS_DISABLE: -- stm32_pconf_set_bias(bank, offset, 0); -+ ret = stm32_pconf_set_bias(bank, offset, 0); - break; - case PIN_CONFIG_BIAS_PULL_UP: -- stm32_pconf_set_bias(bank, offset, 1); -+ ret = stm32_pconf_set_bias(bank, offset, 1); - break; - case PIN_CONFIG_BIAS_PULL_DOWN: -- stm32_pconf_set_bias(bank, offset, 2); -+ ret = stm32_pconf_set_bias(bank, offset, 2); - break; - case PIN_CONFIG_OUTPUT: - __stm32_gpio_set(bank, offset, arg); -@@ -899,6 +1054,8 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned int pin) - { -+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ const struct stm32_desc_pin *pin_desc; - struct pinctrl_gpio_range *range; - struct stm32_gpio_bank *bank; - int offset; -@@ -948,7 +1105,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - case 2: - drive = stm32_pconf_get_driving(bank, offset); - speed = stm32_pconf_get_speed(bank, offset); -- seq_printf(s, "%d - %s - %s - %s %s", alt, -+ pin_desc = pctl->pins + (pin - pctl->pin_base_shift); -+ seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, -+ pin_desc->functions[alt + 1].name, - drive ? "open drain" : "push pull", - biasing[bias], - speeds[speed], "speed"); -@@ -1055,23 +1214,35 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, - return 0; - } - -+static struct irq_domain *stm32_pctrl_get_irq_domain(struct device_node *np) -+{ -+ struct device_node *parent; -+ struct irq_domain *domain; -+ -+ if (!of_find_property(np, "interrupt-parent", NULL)) -+ return NULL; -+ -+ parent = of_irq_find_parent(np); -+ if (!parent) -+ return ERR_PTR(-ENXIO); -+ -+ domain = irq_find_host(parent); -+ if (!domain) -+ /* domain not registered yet */ -+ return ERR_PTR(-EPROBE_DEFER); -+ -+ return domain; -+} -+ - static int stm32_pctrl_dt_setup_irq(struct platform_device *pdev, - struct stm32_pinctrl *pctl) - { -- struct device_node *np = pdev->dev.of_node, *parent; -+ struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct regmap *rm; - int offset, ret, i; - int mask, mask_width; - -- parent = of_irq_find_parent(np); -- if (!parent) -- return -ENXIO; -- -- pctl->domain = irq_find_host(parent); -- if (!pctl->domain) -- return -ENXIO; -- - pctl->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); - if (IS_ERR(pctl->regmap)) - return PTR_ERR(pctl->regmap); -@@ -1111,7 +1282,7 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) - struct stm32_pinctrl *pctl = platform_get_drvdata(pdev); - int i; - -- pctl->ngroups = pctl->match_data->npins; -+ pctl->ngroups = pctl->npins; - - /* Allocate groups */ - pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups, -@@ -1125,19 +1296,51 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) - if (!pctl->grp_names) - return -ENOMEM; - -- for (i = 0; i < pctl->match_data->npins; i++) { -- const struct stm32_desc_pin *pin = pctl->match_data->pins + i; -+ for (i = 0; i < pctl->npins; i++) { -+ const struct stm32_desc_pin *pin = pctl->pins + i; - struct stm32_pinctrl_group *group = pctl->groups + i; - - group->name = pin->pin.name; - group->pin = pin->pin.number; -- - pctl->grp_names[i] = pin->pin.name; - } - - return 0; - } - -+static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, -+ struct stm32_desc_pin *pins) -+{ -+ const struct stm32_desc_pin *p; -+ int i, nb_pins_available = 0; -+ -+ for (i = 0; i < pctl->match_data->npins; i++) { -+ p = pctl->match_data->pins + i; -+ if (pctl->pkg && !(pctl->pkg & p->pkg)) -+ continue; -+ pins->pin = p->pin; -+ memcpy((struct stm32_desc_pin *)pins->functions, p->functions, -+ STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); -+ pins++; -+ nb_pins_available++; -+ } -+ -+ pctl->npins = nb_pins_available; -+ -+ return 0; -+} -+ -+static void stm32_pctl_get_package(struct device_node *np, -+ struct stm32_pinctrl *pctl) -+{ -+ if (of_property_read_u32(np, "st,package", &pctl->pkg)) { -+ pctl->pkg = 0; -+ dev_warn(pctl->dev, "No package detected, use default one\n"); -+ } else { -+ dev_dbg(pctl->dev, "package detected: %x\n", pctl->pkg); -+ } -+} -+ - int stm32_pctl_probe(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; -@@ -1146,7 +1349,7 @@ int stm32_pctl_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct stm32_pinctrl *pctl; - struct pinctrl_pin_desc *pins; -- int i, ret, banks = 0; -+ int i, ret, hwlock_id, banks = 0; - - if (!np) - return -EINVAL; -@@ -1166,36 +1369,66 @@ int stm32_pctl_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, pctl); - -+ /* check for IRQ controller (may require deferred probe) */ -+ pctl->domain = stm32_pctrl_get_irq_domain(np); -+ if (IS_ERR(pctl->domain)) -+ return PTR_ERR(pctl->domain); -+ -+ /* hwspinlock is optional */ -+ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); -+ if (hwlock_id < 0) { -+ if (hwlock_id == -EPROBE_DEFER) -+ return hwlock_id; -+ } else { -+ pctl->hwlock = hwspin_lock_request_specific(hwlock_id); -+ } -+ -+ spin_lock_init(&pctl->irqmux_lock); -+ - pctl->dev = dev; - pctl->match_data = match->data; -+ -+ /* get package information */ -+ stm32_pctl_get_package(np, pctl); -+ -+ pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins, -+ sizeof(*pctl->pins), GFP_KERNEL); -+ if (!pctl->pins) -+ return -ENOMEM; -+ -+ ret = stm32_pctrl_create_pins_tab(pctl, pctl->pins); -+ if (ret) -+ return ret; -+ - ret = stm32_pctrl_build_state(pdev); - if (ret) { - dev_err(dev, "build state failed: %d\n", ret); - return -EINVAL; - } - -- if (of_find_property(np, "interrupt-parent", NULL)) { -+ if (pctl->domain) { - ret = stm32_pctrl_dt_setup_irq(pdev, pctl); - if (ret) - return ret; - } - -- pins = devm_kcalloc(&pdev->dev, pctl->match_data->npins, sizeof(*pins), -+ pins = devm_kcalloc(&pdev->dev, pctl->npins, sizeof(*pins), - GFP_KERNEL); - if (!pins) - return -ENOMEM; - -- for (i = 0; i < pctl->match_data->npins; i++) -- pins[i] = pctl->match_data->pins[i].pin; -+ for (i = 0; i < pctl->npins; i++) -+ pins[i] = pctl->pins[i].pin; - - pctl->pctl_desc.name = dev_name(&pdev->dev); - pctl->pctl_desc.owner = THIS_MODULE; - pctl->pctl_desc.pins = pins; -- pctl->pctl_desc.npins = pctl->match_data->npins; -+ pctl->pctl_desc.npins = pctl->npins; - pctl->pctl_desc.confops = &stm32_pconf_ops; - pctl->pctl_desc.pctlops = &stm32_pctrl_ops; - pctl->pctl_desc.pmxops = &stm32_pmx_ops; - pctl->dev = &pdev->dev; -+ pctl->pin_base_shift = pctl->match_data->pin_base_shift; - - pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, - pctl); -@@ -1233,3 +1466,115 @@ int stm32_pctl_probe(struct platform_device *pdev) - return 0; - } - -+#ifdef CONFIG_PM -+void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, -+ u32 offset, u32 value) -+{ -+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL); -+ bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL; -+} -+ -+void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, -+ u32 offset, u32 mode, u32 alt) -+{ -+ bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK | -+ STM32_GPIO_BKP_ALT_MASK); -+ bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT; -+ bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT; -+} -+ -+void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, -+ u32 offset, u32 drive) -+{ -+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE); -+ bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE; -+} -+ -+void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, -+ u32 offset, u32 speed) -+{ -+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK; -+ bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT; -+} -+ -+void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, -+ u32 offset, u32 bias) -+{ -+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK; -+ bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; -+} -+ -+static int stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin) -+{ -+ const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin); -+ struct pinctrl_gpio_range *range; -+ struct stm32_gpio_bank *bank; -+ u32 val, alt, mode, offset = stm32_gpio_pin(pin); -+ bool pin_is_irq; -+ int ret; -+ -+ range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin); -+ if (!range) -+ return 0; -+ -+ pin_is_irq = gpiochip_line_is_irq(range->gc, offset); -+ -+ if (!desc || (!pin_is_irq && !desc->gpio_owner)) -+ return 0; -+ -+ bank = gpiochip_get_data(range->gc); -+ -+ alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK; -+ alt >>= STM32_GPIO_BKP_ALT_SHIFT; -+ mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; -+ mode >>= STM32_GPIO_BKP_MODE_SHIFT; -+ -+ ret = stm32_pmx_set_mode(bank, offset, mode, alt); -+ if (ret) -+ return ret; -+ -+ if (mode == 1) { -+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL); -+ val = val >> STM32_GPIO_BKP_VAL; -+ __stm32_gpio_set(bank, offset, val); -+ } -+ -+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); -+ val >>= STM32_GPIO_BKP_TYPE; -+ ret = stm32_pconf_set_driving(bank, offset, val); -+ if (ret) -+ return ret; -+ -+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK; -+ val >>= STM32_GPIO_BKP_SPEED_SHIFT; -+ ret = stm32_pconf_set_speed(bank, offset, val); -+ if (ret) -+ return ret; -+ -+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK; -+ val >>= STM32_GPIO_BKP_PUPD_SHIFT; -+ ret = stm32_pconf_set_bias(bank, offset, val); -+ if (ret) -+ return ret; -+ -+ if (pin_is_irq) -+ regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr); -+ -+ return 0; -+} -+ -+int stm32_pinctrl_resume(struct device *dev) -+{ -+ struct stm32_pinctrl *pctl = dev_get_drvdata(dev); -+ struct stm32_pinctrl_group *g = pctl->groups; -+ int i, ret; -+ -+ for (i = g->pin; i < g->pin + pctl->ngroups; i++) { -+ ret = stm32_pinctrl_restore_gpio_regs(pctl, i); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_PM */ -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h -index 473a623..bc77a58 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.h -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h -@@ -17,6 +17,16 @@ - #define STM32_PIN_GPIO 0 - #define STM32_PIN_AF(x) ((x) + 1) - #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) -+#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) -+#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) -+ -+/* package information */ -+#define STM32MP157CAA BIT(0) -+#define STM32MP157CAB BIT(1) -+#define STM32MP157CAC BIT(2) -+#define STM32MP157CAD BIT(3) -+ -+#define STM32MP157_Z_BASE_SHIFT 400 - - struct stm32_desc_function { - const char *name; -@@ -25,7 +35,8 @@ struct stm32_desc_function { - - struct stm32_desc_pin { - struct pinctrl_pin_desc pin; -- const struct stm32_desc_function *functions; -+ const struct stm32_desc_function functions[STM32_CONFIG_NUM]; -+ const unsigned int pkg; - }; - - #define STM32_PIN(_pin, ...) \ -@@ -35,8 +46,15 @@ struct stm32_desc_pin { - __VA_ARGS__, { } }, \ - } - --#define STM32_FUNCTION(_num, _name) \ -+#define STM32_PIN_PKG(_pin, _pkg, ...) \ - { \ -+ .pin = _pin, \ -+ .pkg = _pkg, \ -+ .functions = { \ -+ __VA_ARGS__}, \ -+ } -+#define STM32_FUNCTION(_num, _name) \ -+ [_num] = { \ - .num = _num, \ - .name = _name, \ - } -@@ -44,6 +62,7 @@ struct stm32_desc_pin { - struct stm32_pinctrl_match_data { - const struct stm32_desc_pin *pins; - const unsigned int npins; -+ const unsigned int pin_base_shift; - }; - - struct stm32_gpio_bank; -@@ -51,5 +70,35 @@ struct stm32_gpio_bank; - int stm32_pctl_probe(struct platform_device *pdev); - void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, - int pin, u32 *mode, u32 *alt); -+ -+#ifdef CONFIG_PM -+void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, -+ u32 offset, u32 value); -+void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, -+ u32 offset, u32 drive); -+void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, -+ u32 offset, u32 speed); -+void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, -+ u32 offset, u32 mode, u32 alt); -+void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, -+ u32 offset, u32 bias); -+int stm32_pinctrl_resume(struct device *dev); -+#else -+static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, -+ u32 offset, u32 value) -+{} -+static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, -+ u32 offset, u32 drive) -+{} -+static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, -+ u32 offset, u32 speed) -+{} -+static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, -+ u32 offset, u32 mode, u32 alt) -+{} -+static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, -+ u32 offset, u32 bias) -+{} -+#endif /* CONFIG_PM */ - #endif /* __PINCTRL_STM32_H */ - -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -index 7c7d628..e1a8a89 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -@@ -10,77 +10,82 @@ - #include "pinctrl-stm32.h" - - static const struct stm32_desc_pin stm32mp157_pins[] = { -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(0, "PA0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA0"), - STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), - STM32_FUNCTION(3, "TIM5_CH1"), - STM32_FUNCTION(4, "TIM8_ETR"), - STM32_FUNCTION(5, "TIM15_BKIN"), -- STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), -+ STM32_FUNCTION(8, "USART2_CTS USART2_NSS"), - STM32_FUNCTION(9, "UART4_TX"), - STM32_FUNCTION(10, "SDMMC2_CMD"), - STM32_FUNCTION(11, "SAI2_SD_B"), -- STM32_FUNCTION(12, "ETH_GMII_CRS ETH_MII_CRS"), -+ STM32_FUNCTION(12, "ETH1_GMII_CRS ETH1_MII_CRS"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(1, "PA1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA1"), - STM32_FUNCTION(1, "ETH_CLK"), - STM32_FUNCTION(2, "TIM2_CH2"), - STM32_FUNCTION(3, "TIM5_CH2"), - STM32_FUNCTION(4, "LPTIM3_OUT"), - STM32_FUNCTION(5, "TIM15_CH1N"), -- STM32_FUNCTION(8, "USART2_RTS USART_BOOT2_RTS"), -+ STM32_FUNCTION(8, "USART2_RTS USART2_DE"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), -+ STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), - STM32_FUNCTION(11, "SAI2_MCLK_B"), -- STM32_FUNCTION(12, "ETH_GMII_RX_CLK ETH_MII_RX_CLK ETH_RGMII_RX_CLK ETH_RMII_REF_CLK"), -+ STM32_FUNCTION(12, "ETH1_GMII_RX_CLK ETH1_MII_RX_CLK ETH1_RGMII_RX_CLK ETH1_RMII_REF_CLK"), - STM32_FUNCTION(15, "LCD_R2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(2, "PA2"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA2"), - STM32_FUNCTION(2, "TIM2_CH3"), - STM32_FUNCTION(3, "TIM5_CH3"), - STM32_FUNCTION(4, "LPTIM4_OUT"), - STM32_FUNCTION(5, "TIM15_CH1"), -- STM32_FUNCTION(8, "USART2_TX USART_BOOT2_TX"), -+ STM32_FUNCTION(8, "USART2_TX"), - STM32_FUNCTION(9, "SAI2_SCK_B"), -- STM32_FUNCTION(11, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), -- STM32_FUNCTION(12, "ETH_MDIO"), -+ STM32_FUNCTION(11, "SDMMC2_D0DIR"), -+ STM32_FUNCTION(12, "ETH1_MDIO"), - STM32_FUNCTION(13, "MDIOS_MDIO"), - STM32_FUNCTION(15, "LCD_R1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(3, "PA3"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA3"), - STM32_FUNCTION(2, "TIM2_CH4"), - STM32_FUNCTION(3, "TIM5_CH4"), - STM32_FUNCTION(4, "LPTIM5_OUT"), - STM32_FUNCTION(5, "TIM15_CH2"), -- STM32_FUNCTION(8, "USART2_RX USART_BOOT2_RX"), -+ STM32_FUNCTION(8, "USART2_RX"), - STM32_FUNCTION(10, "LCD_B2"), -- STM32_FUNCTION(12, "ETH_GMII_COL ETH_MII_COL"), -+ STM32_FUNCTION(12, "ETH1_GMII_COL ETH1_MII_COL"), - STM32_FUNCTION(15, "LCD_B5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(4, "PA4"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA4"), - STM32_FUNCTION(1, "HDP0"), - STM32_FUNCTION(3, "TIM5_ETR"), - STM32_FUNCTION(5, "SAI4_D2"), - STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), - STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), -- STM32_FUNCTION(8, "USART2_CK USART_BOOT2_CK"), -+ STM32_FUNCTION(8, "USART2_CK"), - STM32_FUNCTION(9, "SPI6_NSS"), - STM32_FUNCTION(13, "SAI4_FS_A"), - STM32_FUNCTION(14, "DCMI_HSYNC"), -@@ -88,8 +93,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(5, "PA5"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA5"), - STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), - STM32_FUNCTION(4, "TIM8_CH1N"), -@@ -101,8 +107,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(6, "PA6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA6"), - STM32_FUNCTION(2, "TIM1_BKIN"), - STM32_FUNCTION(3, "TIM3_CH1"), -@@ -118,8 +125,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(7, "PA7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA7"), - STM32_FUNCTION(2, "TIM1_CH1N"), - STM32_FUNCTION(3, "TIM3_CH2"), -@@ -129,13 +137,14 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(9, "SPI6_MOSI"), - STM32_FUNCTION(10, "TIM14_CH1"), - STM32_FUNCTION(11, "QUADSPI_CLK"), -- STM32_FUNCTION(12, "ETH_GMII_RX_DV ETH_MII_RX_DV ETH_RGMII_RX_CTL ETH_RMII_CRS_DV"), -+ STM32_FUNCTION(12, "ETH1_GMII_RX_DV ETH1_MII_RX_DV ETH1_RGMII_RX_CTL ETH1_RMII_CRS_DV"), - STM32_FUNCTION(13, "SAI4_SD_A"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(8, "PA8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA8"), - STM32_FUNCTION(1, "MCO1"), - STM32_FUNCTION(2, "TIM1_CH1"), -@@ -143,37 +152,37 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(5, "I2C3_SCL"), - STM32_FUNCTION(6, "SPI3_MOSI I2S3_SDO"), - STM32_FUNCTION(8, "USART1_CK"), -- STM32_FUNCTION(9, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), -- STM32_FUNCTION(10, "SDMMC2_D4 SDMMC_BOOT2_D4"), -- STM32_FUNCTION(11, "USBO_SOF"), -+ STM32_FUNCTION(9, "SDMMC2_CKIN"), -+ STM32_FUNCTION(10, "SDMMC2_D4"), -+ STM32_FUNCTION(11, "OTG_FS_SOF OTG_HS_SOF"), - STM32_FUNCTION(13, "SAI4_SD_B"), - STM32_FUNCTION(14, "UART7_RX"), - STM32_FUNCTION(15, "LCD_R6"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(9, "PA9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA9"), - STM32_FUNCTION(2, "TIM1_CH2"), - STM32_FUNCTION(5, "I2C3_SMBA"), - STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), - STM32_FUNCTION(8, "USART1_TX"), -- STM32_FUNCTION(9, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), -- STM32_FUNCTION(10, "CAN1_RXFD"), -- STM32_FUNCTION(11, "SDMMC2_D5 SDMMC_BOOT2_D5"), -+ STM32_FUNCTION(9, "SDMMC2_CDIR"), -+ STM32_FUNCTION(11, "SDMMC2_D5"), - STM32_FUNCTION(14, "DCMI_D0"), - STM32_FUNCTION(15, "LCD_R5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(10, "PA10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA10"), - STM32_FUNCTION(2, "TIM1_CH3"), - STM32_FUNCTION(6, "SPI3_NSS I2S3_WS"), - STM32_FUNCTION(8, "USART1_RX"), -- STM32_FUNCTION(10, "CAN1_TXFD"), - STM32_FUNCTION(12, "MDIOS_MDIO"), - STM32_FUNCTION(13, "SAI4_FS_B"), - STM32_FUNCTION(14, "DCMI_D1"), -@@ -181,37 +190,39 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(11, "PA11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA11"), - STM32_FUNCTION(2, "TIM1_CH4"), - STM32_FUNCTION(3, "I2C6_SCL"), - STM32_FUNCTION(5, "I2C5_SCL"), - STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), - STM32_FUNCTION(7, "UART4_RX"), -- STM32_FUNCTION(8, "USART1_CTS_NSS"), -- STM32_FUNCTION(10, "CAN1_RX"), -+ STM32_FUNCTION(8, "USART1_CTS USART1_NSS"), -+ STM32_FUNCTION(10, "FDCAN1_RX"), - STM32_FUNCTION(15, "LCD_R4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(12, "PA12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA12"), - STM32_FUNCTION(2, "TIM1_ETR"), - STM32_FUNCTION(3, "I2C6_SDA"), - STM32_FUNCTION(5, "I2C5_SDA"), -- STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), - STM32_FUNCTION(7, "UART4_TX"), -- STM32_FUNCTION(8, "USART1_RTS"), -+ STM32_FUNCTION(8, "USART1_RTS USART1_DE"), - STM32_FUNCTION(9, "SAI2_FS_B"), -- STM32_FUNCTION(10, "CAN1_TX"), -+ STM32_FUNCTION(10, "FDCAN1_TX"), - STM32_FUNCTION(15, "LCD_R5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(13, "PA13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA13"), - STM32_FUNCTION(1, "DBTRGO"), - STM32_FUNCTION(2, "DBTRGI"), -@@ -220,8 +231,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(14, "PA14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA14"), - STM32_FUNCTION(1, "DBTRGO"), - STM32_FUNCTION(2, "DBTRGI"), -@@ -229,73 +241,79 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(15, "PA15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOA15"), - STM32_FUNCTION(1, "DBTRGI"), - STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), - STM32_FUNCTION(3, "SAI4_D2"), - STM32_FUNCTION(4, "SDMMC1_CDIR"), -- STM32_FUNCTION(5, "HDMI_CEC"), -+ STM32_FUNCTION(5, "CEC"), - STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), - STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"), - STM32_FUNCTION(8, "SPI6_NSS"), -- STM32_FUNCTION(9, "UART4_RTS UART_BOOT4_RTS"), -- STM32_FUNCTION(10, "SDMMC2_D5 SDMMC_BOOT2_D5"), -- STM32_FUNCTION(11, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), -- STM32_FUNCTION(12, "SDMMC1_D5 SDMMC_BOOT1_D5"), -+ STM32_FUNCTION(9, "UART4_RTS UART4_DE"), -+ STM32_FUNCTION(10, "SDMMC2_D5"), -+ STM32_FUNCTION(11, "SDMMC2_CDIR"), -+ STM32_FUNCTION(12, "SDMMC1_D5"), - STM32_FUNCTION(13, "SAI4_FS_A"), - STM32_FUNCTION(14, "UART7_TX"), -+ STM32_FUNCTION(15, "LCD_R1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(16, "PB0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB0"), - STM32_FUNCTION(2, "TIM1_CH2N"), - STM32_FUNCTION(3, "TIM3_CH3"), - STM32_FUNCTION(4, "TIM8_CH2N"), -- STM32_FUNCTION(7, "DFSDM_CKOUT"), -- STM32_FUNCTION(9, "UART4_CTS UART_BOOT4_CTS"), -+ STM32_FUNCTION(7, "DFSDM1_CKOUT"), -+ STM32_FUNCTION(9, "UART4_CTS"), - STM32_FUNCTION(10, "LCD_R3"), -- STM32_FUNCTION(12, "ETH_GMII_RXD2 ETH_MII_RXD2 ETH_RGMII_RXD2"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD2 ETH1_MII_RXD2 ETH1_RGMII_RXD2"), - STM32_FUNCTION(13, "MDIOS_MDIO"), - STM32_FUNCTION(15, "LCD_G1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(17, "PB1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB1"), - STM32_FUNCTION(2, "TIM1_CH3N"), - STM32_FUNCTION(3, "TIM3_CH4"), - STM32_FUNCTION(4, "TIM8_CH3N"), -- STM32_FUNCTION(7, "DFSDM_DATA1"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN1"), - STM32_FUNCTION(10, "LCD_R6"), -- STM32_FUNCTION(12, "ETH_GMII_RXD3 ETH_MII_RXD3 ETH_RGMII_RXD3"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD3 ETH1_MII_RXD3 ETH1_RGMII_RXD3"), - STM32_FUNCTION(13, "MDIOS_MDC"), - STM32_FUNCTION(15, "LCD_G0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(18, "PB2"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB2"), - STM32_FUNCTION(1, "TRACED4"), - STM32_FUNCTION(2, "RTC_OUT2"), - STM32_FUNCTION(3, "SAI1_D1"), -- STM32_FUNCTION(4, "DFSDM_CK1"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN1"), - STM32_FUNCTION(5, "USART1_RX"), - STM32_FUNCTION(6, "I2S_CKIN"), - STM32_FUNCTION(7, "SAI1_SD_A"), - STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"), -- STM32_FUNCTION(9, "UART4_RX UART_BOOT4_RX"), -+ STM32_FUNCTION(9, "UART4_RX"), - STM32_FUNCTION(10, "QUADSPI_CLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(19, "PB3"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB3"), - STM32_FUNCTION(1, "TRACED9"), - STM32_FUNCTION(2, "TIM2_CH2"), -@@ -303,14 +321,15 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"), - STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), - STM32_FUNCTION(9, "SPI6_SCK"), -- STM32_FUNCTION(10, "SDMMC2_D2 SDMMC_BOOT2_D2"), -+ STM32_FUNCTION(10, "SDMMC2_D2"), - STM32_FUNCTION(13, "SAI4_MCLK_A"), - STM32_FUNCTION(14, "UART7_RX"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(20, "PB4"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB4"), - STM32_FUNCTION(1, "TRACED8"), - STM32_FUNCTION(2, "TIM16_BKIN"), -@@ -320,14 +339,15 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"), - STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"), - STM32_FUNCTION(9, "SPI6_MISO"), -- STM32_FUNCTION(10, "SDMMC2_D3 SDMMC_BOOT2_D3"), -+ STM32_FUNCTION(10, "SDMMC2_D3"), - STM32_FUNCTION(13, "SAI4_SCK_A"), - STM32_FUNCTION(14, "UART7_TX"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(21, "PB5"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB5"), - STM32_FUNCTION(1, "ETH_CLK"), - STM32_FUNCTION(2, "TIM17_BKIN"), -@@ -338,166 +358,175 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(7, "I2C4_SMBA"), - STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"), - STM32_FUNCTION(9, "SPI6_MOSI"), -- STM32_FUNCTION(10, "CAN2_RX"), -+ STM32_FUNCTION(10, "FDCAN2_RX"), - STM32_FUNCTION(11, "SAI4_SD_A"), -- STM32_FUNCTION(12, "ETH_PPS_OUT"), -- STM32_FUNCTION(13, "UART5_RX UART_BOOT5_RX"), -+ STM32_FUNCTION(12, "ETH1_PPS_OUT"), -+ STM32_FUNCTION(13, "UART5_RX"), - STM32_FUNCTION(14, "DCMI_D10"), - STM32_FUNCTION(15, "LCD_G7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(22, "PB6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB6"), - STM32_FUNCTION(2, "TIM16_CH1N"), - STM32_FUNCTION(3, "TIM4_CH1"), - STM32_FUNCTION(5, "I2C1_SCL"), -- STM32_FUNCTION(6, "HDMI_CEC"), -+ STM32_FUNCTION(6, "CEC"), - STM32_FUNCTION(7, "I2C4_SCL"), - STM32_FUNCTION(8, "USART1_TX"), -- STM32_FUNCTION(10, "CAN2_TX"), -- STM32_FUNCTION(11, "QUADSPI_BK1_NCS QUADSPI_BOOTBK1_NCS"), -- STM32_FUNCTION(12, "DFSDM_DATA5"), -+ STM32_FUNCTION(10, "FDCAN2_TX"), -+ STM32_FUNCTION(11, "QUADSPI_BK1_NCS"), -+ STM32_FUNCTION(12, "DFSDM1_DATIN5"), - STM32_FUNCTION(13, "UART5_TX"), - STM32_FUNCTION(14, "DCMI_D5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(23, "PB7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB7"), - STM32_FUNCTION(2, "TIM17_CH1N"), - STM32_FUNCTION(3, "TIM4_CH2"), - STM32_FUNCTION(5, "I2C1_SDA"), - STM32_FUNCTION(7, "I2C4_SDA"), - STM32_FUNCTION(8, "USART1_RX"), -- STM32_FUNCTION(10, "CAN2_TXFD"), -- STM32_FUNCTION(11, "SDMMC2_D1 SDMMC_BOOT2_D1"), -- STM32_FUNCTION(12, "DFSDM_CK5"), -+ STM32_FUNCTION(11, "SDMMC2_D1"), -+ STM32_FUNCTION(12, "DFSDM1_CKIN5"), - STM32_FUNCTION(13, "FMC_NL"), - STM32_FUNCTION(14, "DCMI_VSYNC"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(24, "PB8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB8"), - STM32_FUNCTION(1, "HDP6"), - STM32_FUNCTION(2, "TIM16_CH1"), - STM32_FUNCTION(3, "TIM4_CH3"), -- STM32_FUNCTION(4, "DFSDM_CK7"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN7"), - STM32_FUNCTION(5, "I2C1_SCL"), -- STM32_FUNCTION(6, "SDMMC1_CKIN SDMMC_BOOT1_CKIN"), -+ STM32_FUNCTION(6, "SDMMC1_CKIN"), - STM32_FUNCTION(7, "I2C4_SCL"), -- STM32_FUNCTION(8, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), -+ STM32_FUNCTION(8, "SDMMC2_CKIN"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "CAN1_RX"), -- STM32_FUNCTION(11, "SDMMC2_D4 SDMMC_BOOT2_D4"), -- STM32_FUNCTION(12, "ETH_GMII_TXD3 ETH_MII_TXD3 ETH_RGMII_TXD3"), -- STM32_FUNCTION(13, "SDMMC1_D4 SDMMC_BOOT1_D4"), -+ STM32_FUNCTION(10, "FDCAN1_RX"), -+ STM32_FUNCTION(11, "SDMMC2_D4"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD3 ETH1_MII_TXD3 ETH1_RGMII_TXD3"), -+ STM32_FUNCTION(13, "SDMMC1_D4"), - STM32_FUNCTION(14, "DCMI_D6"), - STM32_FUNCTION(15, "LCD_B6"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(25, "PB9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB9"), - STM32_FUNCTION(1, "HDP7"), - STM32_FUNCTION(2, "TIM17_CH1"), - STM32_FUNCTION(3, "TIM4_CH4"), -- STM32_FUNCTION(4, "DFSDM_DATA7"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN7"), - STM32_FUNCTION(5, "I2C1_SDA"), - STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), - STM32_FUNCTION(7, "I2C4_SDA"), -- STM32_FUNCTION(8, "SDMMC2_CDIR SDMMC_BOOT2_CDIR"), -+ STM32_FUNCTION(8, "SDMMC2_CDIR"), - STM32_FUNCTION(9, "UART4_TX"), -- STM32_FUNCTION(10, "CAN1_TX"), -- STM32_FUNCTION(11, "SDMMC2_D5 SDMMC_BOOT2_D5"), -- STM32_FUNCTION(12, "SDMMC1_CDIR SDMMC_BOOT1_CDIR"), -- STM32_FUNCTION(13, "SDMMC1_D5 SDMMC_BOOT1_D5"), -+ STM32_FUNCTION(10, "FDCAN1_TX"), -+ STM32_FUNCTION(11, "SDMMC2_D5"), -+ STM32_FUNCTION(12, "SDMMC1_CDIR"), -+ STM32_FUNCTION(13, "SDMMC1_D5"), - STM32_FUNCTION(14, "DCMI_D7"), - STM32_FUNCTION(15, "LCD_B7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(26, "PB10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB10"), - STM32_FUNCTION(2, "TIM2_CH3"), - STM32_FUNCTION(4, "LPTIM2_IN1"), - STM32_FUNCTION(5, "I2C2_SCL"), - STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), -- STM32_FUNCTION(7, "DFSDM_DATA7"), -- STM32_FUNCTION(8, "USART3_TX USART_BOOT3_TX"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN7"), -+ STM32_FUNCTION(8, "USART3_TX"), - STM32_FUNCTION(10, "QUADSPI_BK1_NCS"), -- STM32_FUNCTION(12, "ETH_GMII_RX_ER ETH_MII_RX_ER"), -+ STM32_FUNCTION(12, "ETH1_GMII_RX_ER ETH1_MII_RX_ER"), - STM32_FUNCTION(15, "LCD_G4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(27, "PB11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB11"), - STM32_FUNCTION(2, "TIM2_CH4"), - STM32_FUNCTION(4, "LPTIM2_ETR"), - STM32_FUNCTION(5, "I2C2_SDA"), -- STM32_FUNCTION(7, "DFSDM_CK7"), -+ STM32_FUNCTION(7, "DFSDM1_CKIN7"), - STM32_FUNCTION(8, "USART3_RX"), -- STM32_FUNCTION(12, "ETH_GMII_TX_EN ETH_MII_TX_EN ETH_RGMII_TX_CTL ETH_RMII_TX_EN"), -+ STM32_FUNCTION(12, "ETH1_GMII_TX_EN ETH1_MII_TX_EN ETH1_RGMII_TX_CTL ETH1_RMII_TX_EN"), - STM32_FUNCTION(14, "DSI_TE"), - STM32_FUNCTION(15, "LCD_G5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(28, "PB12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB12"), - STM32_FUNCTION(2, "TIM1_BKIN"), - STM32_FUNCTION(3, "I2C6_SMBA"), - STM32_FUNCTION(5, "I2C2_SMBA"), - STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), -- STM32_FUNCTION(7, "DFSDM_DATA1"), -- STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), -- STM32_FUNCTION(9, "USART3_RX USART_BOOT3_RX"), -- STM32_FUNCTION(10, "CAN2_RX"), -- STM32_FUNCTION(12, "ETH_GMII_TXD0 ETH_MII_TXD0 ETH_RGMII_TXD0 ETH_RMII_TXD0"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN1"), -+ STM32_FUNCTION(8, "USART3_CK"), -+ STM32_FUNCTION(9, "USART3_RX"), -+ STM32_FUNCTION(10, "FDCAN2_RX"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD0 ETH1_MII_TXD0 ETH1_RGMII_TXD0 ETH1_RMII_TXD0"), - STM32_FUNCTION(15, "UART5_RX"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(29, "PB13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB13"), - STM32_FUNCTION(2, "TIM1_CH1N"), -- STM32_FUNCTION(4, "DFSDM_CKOUT"), -+ STM32_FUNCTION(4, "DFSDM1_CKOUT"), - STM32_FUNCTION(5, "LPTIM2_OUT"), - STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), -- STM32_FUNCTION(7, "DFSDM_CK1"), -- STM32_FUNCTION(8, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), -- STM32_FUNCTION(10, "CAN2_TX"), -- STM32_FUNCTION(12, "ETH_GMII_TXD1 ETH_MII_TXD1 ETH_RGMII_TXD1 ETH_RMII_TXD1"), -- STM32_FUNCTION(15, "UART5_TX UART_BOOT5_TX"), -+ STM32_FUNCTION(7, "DFSDM1_CKIN1"), -+ STM32_FUNCTION(8, "USART3_CTS USART3_NSS"), -+ STM32_FUNCTION(10, "FDCAN2_TX"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD1 ETH1_MII_TXD1 ETH1_RGMII_TXD1 ETH1_RMII_TXD1"), -+ STM32_FUNCTION(15, "UART5_TX"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(30, "PB14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB14"), - STM32_FUNCTION(2, "TIM1_CH2N"), - STM32_FUNCTION(3, "TIM12_CH1"), - STM32_FUNCTION(4, "TIM8_CH2N"), - STM32_FUNCTION(5, "USART1_TX"), - STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), -- STM32_FUNCTION(7, "DFSDM_DATA2"), -- STM32_FUNCTION(8, "USART3_RTS USART_BOOT3_RTS"), -- STM32_FUNCTION(10, "SDMMC2_D0 SDMMC_BOOT2_D0"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN2"), -+ STM32_FUNCTION(8, "USART3_RTS USART3_DE"), -+ STM32_FUNCTION(10, "SDMMC2_D0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(31, "PB15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOB15"), - STM32_FUNCTION(1, "RTC_REFIN"), - STM32_FUNCTION(2, "TIM1_CH3N"), -@@ -505,523 +534,557 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(4, "TIM8_CH3N"), - STM32_FUNCTION(5, "USART1_RX"), - STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), -- STM32_FUNCTION(7, "DFSDM_CK2"), -- STM32_FUNCTION(10, "SDMMC2_D1 SDMMC_BOOT2_D1"), -+ STM32_FUNCTION(7, "DFSDM1_CKIN2"), -+ STM32_FUNCTION(10, "SDMMC2_D1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(32, "PC0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC0"), -- STM32_FUNCTION(4, "DFSDM_CK0"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN0"), - STM32_FUNCTION(5, "LPTIM2_IN2"), -- STM32_FUNCTION(7, "DFSDM_DATA4"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN4"), - STM32_FUNCTION(9, "SAI2_FS_B"), -- STM32_FUNCTION(11, "QUADSPI_BK2_NCS QUADSPI_BOOTBK2_NCS"), -+ STM32_FUNCTION(11, "QUADSPI_BK2_NCS"), - STM32_FUNCTION(15, "LCD_R5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(33, "PC1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC1"), - STM32_FUNCTION(1, "TRACED0"), - STM32_FUNCTION(3, "SAI1_D1"), -- STM32_FUNCTION(4, "DFSDM_DATA0"), -- STM32_FUNCTION(5, "DFSDM_CK4"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN0"), -+ STM32_FUNCTION(5, "DFSDM1_CKIN4"), - STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), - STM32_FUNCTION(7, "SAI1_SD_A"), - STM32_FUNCTION(10, "SDMMC2_CK"), -- STM32_FUNCTION(12, "ETH_MDC"), -+ STM32_FUNCTION(12, "ETH1_MDC"), - STM32_FUNCTION(13, "MDIOS_MDC"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(34, "PC2"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC2"), -- STM32_FUNCTION(4, "DFSDM_CK1"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN1"), - STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), -- STM32_FUNCTION(7, "DFSDM_CKOUT"), -- STM32_FUNCTION(12, "ETH_GMII_TXD2 ETH_MII_TXD2 ETH_RGMII_TXD2"), -+ STM32_FUNCTION(7, "DFSDM1_CKOUT"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD2 ETH1_MII_TXD2 ETH1_RGMII_TXD2"), -+ STM32_FUNCTION(14, "DCMI_PIXCLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(35, "PC3"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC3"), - STM32_FUNCTION(1, "TRACECLK"), -- STM32_FUNCTION(4, "DFSDM_DATA1"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN1"), - STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), -- STM32_FUNCTION(12, "ETH_GMII_TX_CLK ETH_MII_TX_CLK"), -+ STM32_FUNCTION(12, "ETH1_GMII_TX_CLK ETH1_MII_TX_CLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(36, "PC4"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC4"), -- STM32_FUNCTION(4, "DFSDM_CK2"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN2"), - STM32_FUNCTION(6, "I2S1_MCK"), -- STM32_FUNCTION(10, "SPDIF_IN2"), -- STM32_FUNCTION(12, "ETH_GMII_RXD0 ETH_MII_RXD0 ETH_RGMII_RXD0 ETH_RMII_RXD0"), -+ STM32_FUNCTION(10, "SPDIFRX_IN2"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD0 ETH1_MII_RXD0 ETH1_RGMII_RXD0 ETH1_RMII_RXD0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(37, "PC5"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC5"), - STM32_FUNCTION(3, "SAI1_D3"), -- STM32_FUNCTION(4, "DFSDM_DATA2"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN2"), - STM32_FUNCTION(5, "SAI4_D4"), - STM32_FUNCTION(7, "SAI1_D4"), -- STM32_FUNCTION(10, "SPDIF_IN3"), -- STM32_FUNCTION(12, "ETH_GMII_RXD1 ETH_MII_RXD1 ETH_RGMII_RXD1 ETH_RMII_RXD1"), -+ STM32_FUNCTION(10, "SPDIFRX_IN3"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD1 ETH1_MII_RXD1 ETH1_RGMII_RXD1 ETH1_RMII_RXD1"), - STM32_FUNCTION(13, "SAI4_D3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(38, "PC6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC6"), - STM32_FUNCTION(1, "HDP1"), - STM32_FUNCTION(3, "TIM3_CH1"), - STM32_FUNCTION(4, "TIM8_CH1"), -- STM32_FUNCTION(5, "DFSDM_CK3"), -+ STM32_FUNCTION(5, "DFSDM1_CKIN3"), - STM32_FUNCTION(6, "I2S2_MCK"), -- STM32_FUNCTION(8, "USART6_TX USART_BOOT6_TX"), -- STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), -- STM32_FUNCTION(10, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), -- STM32_FUNCTION(11, "SDMMC2_D6 SDMMC_BOOT2_D6"), -+ STM32_FUNCTION(8, "USART6_TX"), -+ STM32_FUNCTION(9, "SDMMC1_D0DIR"), -+ STM32_FUNCTION(10, "SDMMC2_D0DIR"), -+ STM32_FUNCTION(11, "SDMMC2_D6"), - STM32_FUNCTION(12, "DSI_TE"), -- STM32_FUNCTION(13, "SDMMC1_D6 SDMMC_BOOT1_D6"), -+ STM32_FUNCTION(13, "SDMMC1_D6"), - STM32_FUNCTION(14, "DCMI_D0"), - STM32_FUNCTION(15, "LCD_HSYNC"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(39, "PC7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC7"), - STM32_FUNCTION(1, "HDP4"), - STM32_FUNCTION(3, "TIM3_CH2"), - STM32_FUNCTION(4, "TIM8_CH2"), -- STM32_FUNCTION(5, "DFSDM_DATA3"), -+ STM32_FUNCTION(5, "DFSDM1_DATIN3"), - STM32_FUNCTION(7, "I2S3_MCK"), -- STM32_FUNCTION(8, "USART6_RX USART_BOOT6_RX"), -- STM32_FUNCTION(9, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), -- STM32_FUNCTION(10, "SDMMC2_D123DIR SDMMC_BOOT2_D123DIR"), -- STM32_FUNCTION(11, "SDMMC2_D7 SDMMC_BOOT2_D7"), -- STM32_FUNCTION(13, "SDMMC1_D7 SDMMC_BOOT1_D7"), -+ STM32_FUNCTION(8, "USART6_RX"), -+ STM32_FUNCTION(9, "SDMMC1_D123DIR"), -+ STM32_FUNCTION(10, "SDMMC2_D123DIR"), -+ STM32_FUNCTION(11, "SDMMC2_D7"), -+ STM32_FUNCTION(13, "SDMMC1_D7"), - STM32_FUNCTION(14, "DCMI_D1"), - STM32_FUNCTION(15, "LCD_G6"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(40, "PC8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC8"), - STM32_FUNCTION(1, "TRACED0"), - STM32_FUNCTION(3, "TIM3_CH3"), - STM32_FUNCTION(4, "TIM8_CH3"), - STM32_FUNCTION(7, "UART4_TX"), -- STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), -- STM32_FUNCTION(9, "UART5_RTS UART_BOOT5_RTS"), -- STM32_FUNCTION(13, "SDMMC1_D0 SDMMC_BOOT1_D0"), -+ STM32_FUNCTION(8, "USART6_CK"), -+ STM32_FUNCTION(9, "UART5_RTS UART5_DE"), -+ STM32_FUNCTION(13, "SDMMC1_D0"), - STM32_FUNCTION(14, "DCMI_D2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(41, "PC9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC9"), - STM32_FUNCTION(1, "TRACED1"), - STM32_FUNCTION(3, "TIM3_CH4"), - STM32_FUNCTION(4, "TIM8_CH4"), - STM32_FUNCTION(5, "I2C3_SDA"), - STM32_FUNCTION(6, "I2S_CKIN"), -- STM32_FUNCTION(9, "UART5_CTS UART_BOOT5_CTS"), -+ STM32_FUNCTION(9, "UART5_CTS"), - STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), -- STM32_FUNCTION(13, "SDMMC1_D1 SDMMC_BOOT1_D1"), -+ STM32_FUNCTION(13, "SDMMC1_D1"), - STM32_FUNCTION(14, "DCMI_D3"), - STM32_FUNCTION(15, "LCD_B2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(42, "PC10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC10"), - STM32_FUNCTION(1, "TRACED2"), -- STM32_FUNCTION(4, "DFSDM_CK5"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN5"), - STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"), - STM32_FUNCTION(8, "USART3_TX"), - STM32_FUNCTION(9, "UART4_TX"), - STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), - STM32_FUNCTION(11, "SAI4_MCLK_B"), -- STM32_FUNCTION(13, "SDMMC1_D2 SDMMC_BOOT1_D2"), -+ STM32_FUNCTION(13, "SDMMC1_D2"), - STM32_FUNCTION(14, "DCMI_D8"), - STM32_FUNCTION(15, "LCD_R2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(43, "PC11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC11"), - STM32_FUNCTION(1, "TRACED3"), -- STM32_FUNCTION(4, "DFSDM_DATA5"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN5"), - STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"), - STM32_FUNCTION(8, "USART3_RX"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "QUADSPI_BK2_NCS QUADSPI_BOOTBK2_NCS"), -+ STM32_FUNCTION(10, "QUADSPI_BK2_NCS"), - STM32_FUNCTION(11, "SAI4_SCK_B"), -- STM32_FUNCTION(13, "SDMMC1_D3 SDMMC_BOOT1_D3"), -+ STM32_FUNCTION(13, "SDMMC1_D3"), - STM32_FUNCTION(14, "DCMI_D4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(44, "PC12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC12"), - STM32_FUNCTION(1, "TRACECLK"), - STM32_FUNCTION(2, "MCO2"), - STM32_FUNCTION(3, "SAI4_D3"), - STM32_FUNCTION(7, "SPI3_MOSI I2S3_SDO"), -- STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), -+ STM32_FUNCTION(8, "USART3_CK"), - STM32_FUNCTION(9, "UART5_TX"), - STM32_FUNCTION(11, "SAI4_SD_B"), -- STM32_FUNCTION(13, "SDMMC1_CK SDMMC_BOOT1_CK"), -+ STM32_FUNCTION(13, "SDMMC1_CK"), - STM32_FUNCTION(14, "DCMI_D9"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(45, "PC13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC13"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(46, "PC14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC14"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(47, "PC15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOC15"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(48, "PD0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD0"), - STM32_FUNCTION(3, "I2C6_SDA"), -- STM32_FUNCTION(4, "DFSDM_CK6"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN6"), - STM32_FUNCTION(5, "I2C5_SDA"), - STM32_FUNCTION(7, "SAI3_SCK_A"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "CAN1_RX"), -+ STM32_FUNCTION(10, "FDCAN1_RX"), - STM32_FUNCTION(11, "SDMMC3_CMD"), -- STM32_FUNCTION(12, "DFSDM_DATA7"), -- STM32_FUNCTION(13, "FMC_D2"), -+ STM32_FUNCTION(12, "DFSDM1_DATIN7"), -+ STM32_FUNCTION(13, "FMC_D2 FMC_DA2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(49, "PD1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD1"), - STM32_FUNCTION(3, "I2C6_SCL"), -- STM32_FUNCTION(4, "DFSDM_DATA6"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN6"), - STM32_FUNCTION(5, "I2C5_SCL"), - STM32_FUNCTION(7, "SAI3_SD_A"), - STM32_FUNCTION(9, "UART4_TX"), -- STM32_FUNCTION(10, "CAN1_TX"), -+ STM32_FUNCTION(10, "FDCAN1_TX"), - STM32_FUNCTION(11, "SDMMC3_D0"), -- STM32_FUNCTION(12, "DFSDM_CK7"), -- STM32_FUNCTION(13, "FMC_D3"), -+ STM32_FUNCTION(12, "DFSDM1_CKIN7"), -+ STM32_FUNCTION(13, "FMC_D3 FMC_DA3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(50, "PD2"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD2"), - STM32_FUNCTION(3, "TIM3_ETR"), - STM32_FUNCTION(5, "I2C5_SMBA"), - STM32_FUNCTION(7, "UART4_RX"), - STM32_FUNCTION(9, "UART5_RX"), -- STM32_FUNCTION(13, "SDMMC1_CMD SDMMC_BOOT1_CMD"), -+ STM32_FUNCTION(13, "SDMMC1_CMD"), - STM32_FUNCTION(14, "DCMI_D11"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(51, "PD3"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD3"), - STM32_FUNCTION(1, "HDP5"), -- STM32_FUNCTION(4, "DFSDM_CKOUT"), -+ STM32_FUNCTION(4, "DFSDM1_CKOUT"), - STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), -- STM32_FUNCTION(7, "DFSDM_DATA0"), -- STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), -- STM32_FUNCTION(9, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), -- STM32_FUNCTION(10, "SDMMC2_D7 SDMMC_BOOT2_D7"), -- STM32_FUNCTION(11, "SDMMC2_D123DIR SDMMC_BOOT2_D123DIR"), -- STM32_FUNCTION(12, "SDMMC1_D7 SDMMC_BOOT1_D7"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN0"), -+ STM32_FUNCTION(8, "USART2_CTS USART2_NSS"), -+ STM32_FUNCTION(9, "SDMMC1_D123DIR"), -+ STM32_FUNCTION(10, "SDMMC2_D7"), -+ STM32_FUNCTION(11, "SDMMC2_D123DIR"), -+ STM32_FUNCTION(12, "SDMMC1_D7"), - STM32_FUNCTION(13, "FMC_CLK"), - STM32_FUNCTION(14, "DCMI_D5"), - STM32_FUNCTION(15, "LCD_G7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(52, "PD4"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD4"), - STM32_FUNCTION(7, "SAI3_FS_A"), -- STM32_FUNCTION(8, "USART2_RTS USART_BOOT2_RTS"), -- STM32_FUNCTION(10, "CAN1_RXFD"), -+ STM32_FUNCTION(8, "USART2_RTS USART2_DE"), - STM32_FUNCTION(11, "SDMMC3_D1"), -- STM32_FUNCTION(12, "DFSDM_CK0"), -+ STM32_FUNCTION(12, "DFSDM1_CKIN0"), - STM32_FUNCTION(13, "FMC_NOE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(53, "PD5"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD5"), - STM32_FUNCTION(8, "USART2_TX"), -- STM32_FUNCTION(10, "CAN1_TXFD"), - STM32_FUNCTION(11, "SDMMC3_D2"), - STM32_FUNCTION(13, "FMC_NWE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(54, "PD6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD6"), - STM32_FUNCTION(2, "TIM16_CH1N"), - STM32_FUNCTION(3, "SAI1_D1"), -- STM32_FUNCTION(4, "DFSDM_CK4"), -- STM32_FUNCTION(5, "DFSDM_DATA1"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN4"), -+ STM32_FUNCTION(5, "DFSDM1_DATIN1"), - STM32_FUNCTION(6, "SPI3_MOSI I2S3_SDO"), - STM32_FUNCTION(7, "SAI1_SD_A"), - STM32_FUNCTION(8, "USART2_RX"), -- STM32_FUNCTION(10, "CAN2_RXFD"), -- STM32_FUNCTION(11, "FMC_INT"), - STM32_FUNCTION(13, "FMC_NWAIT"), - STM32_FUNCTION(14, "DCMI_D10"), - STM32_FUNCTION(15, "LCD_B2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(55, "PD7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD7"), - STM32_FUNCTION(1, "TRACED6"), -- STM32_FUNCTION(4, "DFSDM_DATA4"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN4"), - STM32_FUNCTION(5, "I2C2_SCL"), -- STM32_FUNCTION(7, "DFSDM_CK1"), -- STM32_FUNCTION(8, "USART2_CK USART_BOOT2_CK"), -- STM32_FUNCTION(10, "SPDIF_IN0"), -+ STM32_FUNCTION(7, "DFSDM1_CKIN1"), -+ STM32_FUNCTION(8, "USART2_CK"), -+ STM32_FUNCTION(10, "SPDIFRX_IN0"), - STM32_FUNCTION(11, "SDMMC3_D3"), - STM32_FUNCTION(13, "FMC_NE1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(56, "PD8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD8"), -- STM32_FUNCTION(4, "DFSDM_CK3"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN3"), - STM32_FUNCTION(7, "SAI3_SCK_B"), - STM32_FUNCTION(8, "USART3_TX"), -- STM32_FUNCTION(10, "SPDIF_IN1"), -- STM32_FUNCTION(13, "FMC_D13"), -+ STM32_FUNCTION(10, "SPDIFRX_IN1"), -+ STM32_FUNCTION(13, "FMC_D13 FMC_DA13"), - STM32_FUNCTION(15, "LCD_B7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(57, "PD9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD9"), -- STM32_FUNCTION(4, "DFSDM_DATA3"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN3"), - STM32_FUNCTION(7, "SAI3_SD_B"), - STM32_FUNCTION(8, "USART3_RX"), -- STM32_FUNCTION(10, "CAN2_RXFD"), -- STM32_FUNCTION(13, "FMC_D14"), -+ STM32_FUNCTION(13, "FMC_D14 FMC_DA14"), -+ STM32_FUNCTION(14, "DCMI_HSYNC"), - STM32_FUNCTION(15, "LCD_B0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(58, "PD10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD10"), - STM32_FUNCTION(1, "RTC_REFIN"), - STM32_FUNCTION(2, "TIM16_BKIN"), -- STM32_FUNCTION(4, "DFSDM_CKOUT"), -+ STM32_FUNCTION(4, "DFSDM1_CKOUT"), - STM32_FUNCTION(5, "I2C5_SMBA"), - STM32_FUNCTION(6, "SPI3_MISO I2S3_SDI"), - STM32_FUNCTION(7, "SAI3_FS_B"), -- STM32_FUNCTION(8, "USART3_CK USART_BOOT3_CK"), -- STM32_FUNCTION(10, "CAN2_TXFD"), -- STM32_FUNCTION(13, "FMC_D15"), -+ STM32_FUNCTION(8, "USART3_CK"), -+ STM32_FUNCTION(13, "FMC_D15 FMC_DA15"), - STM32_FUNCTION(15, "LCD_B3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(59, "PD11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD11"), - STM32_FUNCTION(4, "LPTIM2_IN2"), - STM32_FUNCTION(5, "I2C4_SMBA"), - STM32_FUNCTION(6, "I2C1_SMBA"), -- STM32_FUNCTION(8, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), -+ STM32_FUNCTION(8, "USART3_CTS USART3_NSS"), - STM32_FUNCTION(10, "QUADSPI_BK1_IO0"), - STM32_FUNCTION(11, "SAI2_SD_A"), -- STM32_FUNCTION(13, "FMC_A16 FMC_CLE"), -+ STM32_FUNCTION(13, "FMC_CLE FMC_A16"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(60, "PD12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD12"), - STM32_FUNCTION(2, "LPTIM1_IN1"), - STM32_FUNCTION(3, "TIM4_CH1"), - STM32_FUNCTION(4, "LPTIM2_IN1"), - STM32_FUNCTION(5, "I2C4_SCL"), - STM32_FUNCTION(6, "I2C1_SCL"), -- STM32_FUNCTION(8, "USART3_RTS USART_BOOT3_RTS"), -+ STM32_FUNCTION(8, "USART3_RTS USART3_DE"), - STM32_FUNCTION(10, "QUADSPI_BK1_IO1"), - STM32_FUNCTION(11, "SAI2_FS_A"), -- STM32_FUNCTION(13, "FMC_A17 FMC_ALE"), -+ STM32_FUNCTION(13, "FMC_ALE FMC_A17"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(61, "PD13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD13"), - STM32_FUNCTION(2, "LPTIM1_OUT"), - STM32_FUNCTION(3, "TIM4_CH2"), - STM32_FUNCTION(5, "I2C4_SDA"), - STM32_FUNCTION(6, "I2C1_SDA"), - STM32_FUNCTION(7, "I2S3_MCK"), -- STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), -+ STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), - STM32_FUNCTION(11, "SAI2_SCK_A"), - STM32_FUNCTION(13, "FMC_A18"), - STM32_FUNCTION(14, "DSI_TE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(62, "PD14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD14"), - STM32_FUNCTION(3, "TIM4_CH3"), - STM32_FUNCTION(7, "SAI3_MCLK_B"), -- STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), -- STM32_FUNCTION(13, "FMC_D0"), -+ STM32_FUNCTION(9, "UART8_CTS"), -+ STM32_FUNCTION(13, "FMC_D0 FMC_DA0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(63, "PD15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOD15"), - STM32_FUNCTION(3, "TIM4_CH4"), - STM32_FUNCTION(7, "SAI3_MCLK_A"), -- STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), -- STM32_FUNCTION(13, "FMC_D1"), -+ STM32_FUNCTION(9, "UART8_CTS"), -+ STM32_FUNCTION(13, "FMC_D1 FMC_DA1"), -+ STM32_FUNCTION(15, "LCD_R1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(64, "PE0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE0"), - STM32_FUNCTION(2, "LPTIM1_ETR"), - STM32_FUNCTION(3, "TIM4_ETR"), - STM32_FUNCTION(5, "LPTIM2_ETR"), - STM32_FUNCTION(6, "SPI3_SCK I2S3_CK"), - STM32_FUNCTION(7, "SAI4_MCLK_B"), -- STM32_FUNCTION(9, "UART8_RX UART_BOOT8_RX"), -- STM32_FUNCTION(10, "CAN1_RXFD"), -+ STM32_FUNCTION(9, "UART8_RX"), - STM32_FUNCTION(11, "SAI2_MCLK_A"), - STM32_FUNCTION(13, "FMC_NBL0"), - STM32_FUNCTION(14, "DCMI_D2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(65, "PE1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE1"), - STM32_FUNCTION(2, "LPTIM1_IN2"), - STM32_FUNCTION(6, "I2S2_MCK"), - STM32_FUNCTION(7, "SAI3_SD_B"), -- STM32_FUNCTION(9, "UART8_TX UART_BOOT8_TX"), -- STM32_FUNCTION(10, "CAN1_TXFD"), -+ STM32_FUNCTION(9, "UART8_TX"), - STM32_FUNCTION(13, "FMC_NBL1"), - STM32_FUNCTION(14, "DCMI_D3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(66, "PE2"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE2"), - STM32_FUNCTION(1, "TRACECLK"), - STM32_FUNCTION(3, "SAI1_CK1"), - STM32_FUNCTION(5, "I2C4_SCL"), - STM32_FUNCTION(6, "SPI4_SCK"), - STM32_FUNCTION(7, "SAI1_MCLK_A"), -- STM32_FUNCTION(10, "QUADSPI_BK1_IO2 QUADSPI_BOOTBK1_IO2"), -- STM32_FUNCTION(12, "ETH_GMII_TXD3 ETH_MII_TXD3 ETH_RGMII_TXD3"), -+ STM32_FUNCTION(10, "QUADSPI_BK1_IO2"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD3 ETH1_MII_TXD3 ETH1_RGMII_TXD3"), - STM32_FUNCTION(13, "FMC_A23"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(67, "PE3"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE3"), - STM32_FUNCTION(1, "TRACED0"), - STM32_FUNCTION(5, "TIM15_BKIN"), - STM32_FUNCTION(7, "SAI1_SD_B"), -- STM32_FUNCTION(10, "SDMMC2_CK SDMMC_BOOT2_CK"), -+ STM32_FUNCTION(10, "SDMMC2_CK"), - STM32_FUNCTION(13, "FMC_A19"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(68, "PE4"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE4"), - STM32_FUNCTION(1, "TRACED1"), - STM32_FUNCTION(3, "SAI1_D2"), -- STM32_FUNCTION(4, "DFSDM_DATA3"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN3"), - STM32_FUNCTION(5, "TIM15_CH1N"), - STM32_FUNCTION(6, "SPI4_NSS"), - STM32_FUNCTION(7, "SAI1_FS_A"), -- STM32_FUNCTION(8, "SDMMC2_CKIN SDMMC_BOOT2_CKIN"), -- STM32_FUNCTION(9, "SDMMC1_CKIN SDMMC_BOOT1_CKIN"), -- STM32_FUNCTION(10, "SDMMC2_D4 SDMMC_BOOT2_D4"), -- STM32_FUNCTION(12, "SDMMC1_D4 SDMMC_BOOT1_D4"), -+ STM32_FUNCTION(8, "SDMMC2_CKIN"), -+ STM32_FUNCTION(9, "SDMMC1_CKIN"), -+ STM32_FUNCTION(10, "SDMMC2_D4"), -+ STM32_FUNCTION(12, "SDMMC1_D4"), - STM32_FUNCTION(13, "FMC_A20"), - STM32_FUNCTION(14, "DCMI_D4"), - STM32_FUNCTION(15, "LCD_B0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(69, "PE5"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE5"), - STM32_FUNCTION(1, "TRACED3"), - STM32_FUNCTION(3, "SAI1_CK2"), -- STM32_FUNCTION(4, "DFSDM_CK3"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN3"), - STM32_FUNCTION(5, "TIM15_CH1"), - STM32_FUNCTION(6, "SPI4_MISO"), - STM32_FUNCTION(7, "SAI1_SCK_A"), -- STM32_FUNCTION(8, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), -- STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), -- STM32_FUNCTION(10, "SDMMC2_D6 SDMMC_BOOT2_D6"), -- STM32_FUNCTION(12, "SDMMC1_D6 SDMMC_BOOT1_D6"), -+ STM32_FUNCTION(8, "SDMMC2_D0DIR"), -+ STM32_FUNCTION(9, "SDMMC1_D0DIR"), -+ STM32_FUNCTION(10, "SDMMC2_D6"), -+ STM32_FUNCTION(12, "SDMMC1_D6"), - STM32_FUNCTION(13, "FMC_A21"), - STM32_FUNCTION(14, "DCMI_D6"), - STM32_FUNCTION(15, "LCD_G0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(70, "PE6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE6"), - STM32_FUNCTION(1, "TRACED2"), - STM32_FUNCTION(2, "TIM1_BKIN2"), -@@ -1030,7 +1093,7 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(6, "SPI4_MOSI"), - STM32_FUNCTION(7, "SAI1_SD_A"), - STM32_FUNCTION(8, "SDMMC2_D0"), -- STM32_FUNCTION(9, "SDMMC1_D2 SDMMC_BOOT1_D2"), -+ STM32_FUNCTION(9, "SDMMC1_D2"), - STM32_FUNCTION(11, "SAI2_MCLK_B"), - STM32_FUNCTION(13, "FMC_A22"), - STM32_FUNCTION(14, "DCMI_D7"), -@@ -1038,119 +1101,132 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(71, "PE7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE7"), - STM32_FUNCTION(2, "TIM1_ETR"), - STM32_FUNCTION(3, "TIM3_ETR"), -- STM32_FUNCTION(4, "DFSDM_DATA2"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN2"), - STM32_FUNCTION(8, "UART7_RX"), -- STM32_FUNCTION(11, "QUADSPI_BK2_IO0 QUADSPI_BOOTBK2_IO0"), -- STM32_FUNCTION(13, "FMC_D4"), -+ STM32_FUNCTION(11, "QUADSPI_BK2_IO0"), -+ STM32_FUNCTION(13, "FMC_D4 FMC_DA4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(72, "PE8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE8"), - STM32_FUNCTION(2, "TIM1_CH1N"), -- STM32_FUNCTION(4, "DFSDM_CK2"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN2"), - STM32_FUNCTION(8, "UART7_TX"), -- STM32_FUNCTION(11, "QUADSPI_BK2_IO1 QUADSPI_BOOTBK2_IO1"), -- STM32_FUNCTION(13, "FMC_D5"), -+ STM32_FUNCTION(11, "QUADSPI_BK2_IO1"), -+ STM32_FUNCTION(13, "FMC_D5 FMC_DA5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(73, "PE9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE9"), - STM32_FUNCTION(2, "TIM1_CH1"), -- STM32_FUNCTION(4, "DFSDM_CKOUT"), -- STM32_FUNCTION(8, "UART7_RTS UART_BOOT7_RTS"), -- STM32_FUNCTION(11, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), -- STM32_FUNCTION(13, "FMC_D6"), -+ STM32_FUNCTION(4, "DFSDM1_CKOUT"), -+ STM32_FUNCTION(8, "UART7_RTS UART7_DE"), -+ STM32_FUNCTION(11, "QUADSPI_BK2_IO2"), -+ STM32_FUNCTION(13, "FMC_D6 FMC_DA6"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(74, "PE10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE10"), - STM32_FUNCTION(2, "TIM1_CH2N"), -- STM32_FUNCTION(4, "DFSDM_DATA4"), -- STM32_FUNCTION(8, "UART7_CTS UART_BOOT7_CTS"), -- STM32_FUNCTION(11, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), -- STM32_FUNCTION(13, "FMC_D7"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN4"), -+ STM32_FUNCTION(8, "UART7_CTS"), -+ STM32_FUNCTION(11, "QUADSPI_BK2_IO3"), -+ STM32_FUNCTION(13, "FMC_D7 FMC_DA7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(75, "PE11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE11"), - STM32_FUNCTION(2, "TIM1_CH2"), -- STM32_FUNCTION(4, "DFSDM_CK4"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN4"), - STM32_FUNCTION(6, "SPI4_NSS"), -- STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), -+ STM32_FUNCTION(8, "USART6_CK"), - STM32_FUNCTION(11, "SAI2_SD_B"), -- STM32_FUNCTION(13, "FMC_D8"), -+ STM32_FUNCTION(13, "FMC_D8 FMC_DA8"), -+ STM32_FUNCTION(14, "DCMI_D4"), - STM32_FUNCTION(15, "LCD_G3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(76, "PE12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE12"), - STM32_FUNCTION(2, "TIM1_CH3N"), -- STM32_FUNCTION(4, "DFSDM_DATA5"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN5"), - STM32_FUNCTION(6, "SPI4_SCK"), -- STM32_FUNCTION(9, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), -+ STM32_FUNCTION(9, "SDMMC1_D0DIR"), - STM32_FUNCTION(11, "SAI2_SCK_B"), -- STM32_FUNCTION(13, "FMC_D9"), -+ STM32_FUNCTION(13, "FMC_D9 FMC_DA9"), - STM32_FUNCTION(15, "LCD_B4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(77, "PE13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE13"), - STM32_FUNCTION(1, "HDP2"), - STM32_FUNCTION(2, "TIM1_CH3"), -- STM32_FUNCTION(4, "DFSDM_CK5"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN5"), - STM32_FUNCTION(6, "SPI4_MISO"), - STM32_FUNCTION(11, "SAI2_FS_B"), -- STM32_FUNCTION(13, "FMC_D10"), -+ STM32_FUNCTION(13, "FMC_D10 FMC_DA10"), -+ STM32_FUNCTION(14, "DCMI_D6"), - STM32_FUNCTION(15, "LCD_DE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(78, "PE14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE14"), - STM32_FUNCTION(2, "TIM1_CH4"), - STM32_FUNCTION(6, "SPI4_MOSI"), -- STM32_FUNCTION(9, "UART8_RTS UART_BOOT8_RTS"), -+ STM32_FUNCTION(9, "UART8_RTS UART8_DE"), - STM32_FUNCTION(11, "SAI2_MCLK_B"), -- STM32_FUNCTION(12, "SDMMC1_D123DIR SDMMC_BOOT1_D123DIR"), -- STM32_FUNCTION(13, "FMC_D11"), -+ STM32_FUNCTION(12, "SDMMC1_D123DIR"), -+ STM32_FUNCTION(13, "FMC_D11 FMC_DA11"), - STM32_FUNCTION(14, "LCD_G0"), - STM32_FUNCTION(15, "LCD_CLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(79, "PE15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOE15"), - STM32_FUNCTION(1, "HDP3"), - STM32_FUNCTION(2, "TIM1_BKIN"), - STM32_FUNCTION(5, "TIM15_BKIN"), -- STM32_FUNCTION(8, "USART2_CTS_NSS USART_BOOT2_CTS_NSS"), -- STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), -- STM32_FUNCTION(13, "FMC_D12"), -+ STM32_FUNCTION(8, "USART2_CTS USART2_NSS"), -+ STM32_FUNCTION(9, "UART8_CTS"), -+ STM32_FUNCTION(11, "FMC_NCE2"), -+ STM32_FUNCTION(13, "FMC_D12 FMC_DA12"), - STM32_FUNCTION(15, "LCD_R7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(80, "PF0"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF0"), - STM32_FUNCTION(5, "I2C2_SDA"), - STM32_FUNCTION(10, "SDMMC3_D0"), -@@ -1159,8 +1235,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(81, "PF1"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF1"), - STM32_FUNCTION(5, "I2C2_SCL"), - STM32_FUNCTION(10, "SDMMC3_CMD"), -@@ -1169,27 +1246,30 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(82, "PF2"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF2"), - STM32_FUNCTION(5, "I2C2_SMBA"), -- STM32_FUNCTION(10, "SDMMC2_D0DIR SDMMC_BOOT2_D0DIR"), -+ STM32_FUNCTION(10, "SDMMC2_D0DIR"), - STM32_FUNCTION(11, "SDMMC3_D0DIR"), -- STM32_FUNCTION(12, "SDMMC1_D0DIR SDMMC_BOOT1_D0DIR"), -+ STM32_FUNCTION(12, "SDMMC1_D0DIR"), - STM32_FUNCTION(13, "FMC_A2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(83, "PF3"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF3"), -- STM32_FUNCTION(12, "ETH_GMII_TX_ER ETH_MII_TX_ER"), -+ STM32_FUNCTION(12, "ETH1_GMII_TX_ER ETH1_MII_TX_ER"), - STM32_FUNCTION(13, "FMC_A3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(84, "PF4"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF4"), - STM32_FUNCTION(8, "USART2_RX"), - STM32_FUNCTION(10, "SDMMC3_D1"), -@@ -1198,8 +1278,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(85, "PF5"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF5"), - STM32_FUNCTION(8, "USART2_TX"), - STM32_FUNCTION(10, "SDMMC3_D2"), -@@ -1207,71 +1288,77 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(86, "PF6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF6"), - STM32_FUNCTION(2, "TIM16_CH1"), - STM32_FUNCTION(6, "SPI5_NSS"), - STM32_FUNCTION(7, "SAI1_SD_B"), -- STM32_FUNCTION(8, "UART7_RX UART_BOOT7_RX"), -- STM32_FUNCTION(10, "QUADSPI_BK1_IO3 QUADSPI_BOOTBK1_IO3"), -+ STM32_FUNCTION(8, "UART7_RX"), -+ STM32_FUNCTION(10, "QUADSPI_BK1_IO3"), - STM32_FUNCTION(13, "SAI4_SCK_B"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(87, "PF7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF7"), - STM32_FUNCTION(2, "TIM17_CH1"), - STM32_FUNCTION(6, "SPI5_SCK"), - STM32_FUNCTION(7, "SAI1_MCLK_B"), -- STM32_FUNCTION(8, "UART7_TX UART_BOOT7_TX"), -- STM32_FUNCTION(10, "QUADSPI_BK1_IO2 QUADSPI_BOOTBK1_IO2"), -+ STM32_FUNCTION(8, "UART7_TX"), -+ STM32_FUNCTION(10, "QUADSPI_BK1_IO2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(88, "PF8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF8"), - STM32_FUNCTION(1, "TRACED12"), - STM32_FUNCTION(2, "TIM16_CH1N"), - STM32_FUNCTION(6, "SPI5_MISO"), - STM32_FUNCTION(7, "SAI1_SCK_B"), -- STM32_FUNCTION(8, "UART7_RTS UART_BOOT7_RTS"), -+ STM32_FUNCTION(8, "UART7_RTS UART7_DE"), - STM32_FUNCTION(10, "TIM13_CH1"), -- STM32_FUNCTION(11, "QUADSPI_BK1_IO0 QUADSPI_BOOTBK1_IO0"), -+ STM32_FUNCTION(11, "QUADSPI_BK1_IO0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(89, "PF9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF9"), - STM32_FUNCTION(1, "TRACED13"), - STM32_FUNCTION(2, "TIM17_CH1N"), - STM32_FUNCTION(6, "SPI5_MOSI"), - STM32_FUNCTION(7, "SAI1_FS_B"), -- STM32_FUNCTION(8, "UART7_CTS UART_BOOT7_CTS"), -+ STM32_FUNCTION(8, "UART7_CTS"), - STM32_FUNCTION(10, "TIM14_CH1"), -- STM32_FUNCTION(11, "QUADSPI_BK1_IO1 QUADSPI_BOOTBK1_IO1"), -+ STM32_FUNCTION(11, "QUADSPI_BK1_IO1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(90, "PF10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF10"), - STM32_FUNCTION(2, "TIM16_BKIN"), - STM32_FUNCTION(3, "SAI1_D3"), - STM32_FUNCTION(4, "SAI4_D4"), - STM32_FUNCTION(7, "SAI1_D4"), -- STM32_FUNCTION(10, "QUADSPI_CLK QUADSPI_BOOTCLK"), -+ STM32_FUNCTION(10, "QUADSPI_CLK"), - STM32_FUNCTION(13, "SAI4_D3"), - STM32_FUNCTION(14, "DCMI_D11"), - STM32_FUNCTION(15, "LCD_DE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(91, "PF11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOF11"), - STM32_FUNCTION(6, "SPI5_MOSI"), - STM32_FUNCTION(11, "SAI2_SD_B"), -@@ -1280,138 +1367,151 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(92, "PF12"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF12"), - STM32_FUNCTION(1, "TRACED4"), -- STM32_FUNCTION(12, "ETH_GMII_RXD4"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD4"), - STM32_FUNCTION(13, "FMC_A6"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(93, "PF13"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF13"), - STM32_FUNCTION(1, "TRACED5"), -- STM32_FUNCTION(4, "DFSDM_DATA6"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN6"), - STM32_FUNCTION(5, "I2C4_SMBA"), - STM32_FUNCTION(6, "I2C1_SMBA"), -- STM32_FUNCTION(7, "DFSDM_DATA3"), -- STM32_FUNCTION(12, "ETH_GMII_RXD5"), -+ STM32_FUNCTION(7, "DFSDM1_DATIN3"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD5"), - STM32_FUNCTION(13, "FMC_A7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(94, "PF14"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF14"), - STM32_FUNCTION(1, "TRACED6"), -- STM32_FUNCTION(4, "DFSDM_CK6"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN6"), - STM32_FUNCTION(5, "I2C4_SCL"), - STM32_FUNCTION(6, "I2C1_SCL"), -- STM32_FUNCTION(12, "ETH_GMII_RXD6"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD6"), - STM32_FUNCTION(13, "FMC_A8"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(95, "PF15"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOF15"), - STM32_FUNCTION(1, "TRACED7"), - STM32_FUNCTION(5, "I2C4_SDA"), - STM32_FUNCTION(6, "I2C1_SDA"), -- STM32_FUNCTION(12, "ETH_GMII_RXD7"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD7"), - STM32_FUNCTION(13, "FMC_A9"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(96, "PG0"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG0"), - STM32_FUNCTION(1, "TRACED0"), -- STM32_FUNCTION(4, "DFSDM_DATA0"), -- STM32_FUNCTION(12, "ETH_GMII_TXD4"), -+ STM32_FUNCTION(4, "DFSDM1_DATIN0"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD4"), - STM32_FUNCTION(13, "FMC_A10"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(97, "PG1"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG1"), - STM32_FUNCTION(1, "TRACED1"), -- STM32_FUNCTION(12, "ETH_GMII_TXD5"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD5"), - STM32_FUNCTION(13, "FMC_A11"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(98, "PG2"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG2"), - STM32_FUNCTION(1, "TRACED2"), - STM32_FUNCTION(2, "MCO2"), - STM32_FUNCTION(4, "TIM8_BKIN"), -- STM32_FUNCTION(12, "ETH_GMII_TXD6"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD6"), - STM32_FUNCTION(13, "FMC_A12"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(99, "PG3"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG3"), - STM32_FUNCTION(1, "TRACED3"), - STM32_FUNCTION(4, "TIM8_BKIN2"), -- STM32_FUNCTION(5, "DFSDM_CK1"), -- STM32_FUNCTION(12, "ETH_GMII_TXD7"), -+ STM32_FUNCTION(5, "DFSDM1_CKIN1"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD7"), - STM32_FUNCTION(13, "FMC_A13"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(100, "PG4"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG4"), - STM32_FUNCTION(2, "TIM1_BKIN2"), -- STM32_FUNCTION(12, "ETH_GMII_GTX_CLK ETH_RGMII_GTX_CLK"), -+ STM32_FUNCTION(12, "ETH1_GMII_GTX_CLK ETH1_RGMII_GTX_CLK"), - STM32_FUNCTION(13, "FMC_A14"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(101, "PG5"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOG5"), - STM32_FUNCTION(2, "TIM1_ETR"), -- STM32_FUNCTION(12, "ETH_GMII_CLK125 ETH_RGMII_CLK125"), -+ STM32_FUNCTION(12, "ETH1_GMII_CLK125 ETH1_RGMII_CLK125"), - STM32_FUNCTION(13, "FMC_A15"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(102, "PG6"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG6"), - STM32_FUNCTION(1, "TRACED14"), - STM32_FUNCTION(2, "TIM17_BKIN"), -- STM32_FUNCTION(11, "SDMMC2_CMD SDMMC_BOOT2_CMD"), -+ STM32_FUNCTION(11, "SDMMC2_CMD"), - STM32_FUNCTION(14, "DCMI_D12"), - STM32_FUNCTION(15, "LCD_R7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(103, "PG7"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG7"), - STM32_FUNCTION(1, "TRACED5"), - STM32_FUNCTION(7, "SAI1_MCLK_A"), -- STM32_FUNCTION(8, "USART6_CK USART_BOOT6_CK"), -- STM32_FUNCTION(9, "UART8_RTS UART_BOOT8_RTS"), -+ STM32_FUNCTION(8, "USART6_CK"), -+ STM32_FUNCTION(9, "UART8_RTS UART8_DE"), - STM32_FUNCTION(10, "QUADSPI_CLK"), -- STM32_FUNCTION(12, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), -+ STM32_FUNCTION(12, "QUADSPI_BK2_IO3"), - STM32_FUNCTION(13, "FMC_INT"), - STM32_FUNCTION(14, "DCMI_D13"), - STM32_FUNCTION(15, "LCD_CLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(104, "PG8"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG8"), - STM32_FUNCTION(1, "TRACED15"), - STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"), -@@ -1419,73 +1519,79 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(4, "TIM8_ETR"), - STM32_FUNCTION(6, "SPI6_NSS"), - STM32_FUNCTION(7, "SAI4_D2"), -- STM32_FUNCTION(8, "USART6_RTS USART_BOOT6_RTS"), -- STM32_FUNCTION(9, "USART3_RTS"), -- STM32_FUNCTION(10, "SPDIF_IN2"), -+ STM32_FUNCTION(8, "USART6_RTS USART6_DE"), -+ STM32_FUNCTION(9, "USART3_RTS USART3_DE"), -+ STM32_FUNCTION(10, "SPDIFRX_IN2"), - STM32_FUNCTION(11, "SAI4_FS_A"), -- STM32_FUNCTION(12, "ETH_PPS_OUT"), -+ STM32_FUNCTION(12, "ETH1_PPS_OUT"), - STM32_FUNCTION(15, "LCD_G7"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(105, "PG9"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG9"), - STM32_FUNCTION(1, "DBTRGO"), - STM32_FUNCTION(8, "USART6_RX"), -- STM32_FUNCTION(9, "SPDIF_IN3"), -- STM32_FUNCTION(10, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), -+ STM32_FUNCTION(9, "SPDIFRX_IN3"), -+ STM32_FUNCTION(10, "QUADSPI_BK2_IO2"), - STM32_FUNCTION(11, "SAI2_FS_B"), -- STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"), -+ STM32_FUNCTION(13, "FMC_NCE FMC_NE2"), - STM32_FUNCTION(14, "DCMI_VSYNC"), -+ STM32_FUNCTION(15, "LCD_R1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(106, "PG10"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG10"), - STM32_FUNCTION(1, "TRACED10"), -- STM32_FUNCTION(9, "UART8_CTS UART_BOOT8_CTS"), -+ STM32_FUNCTION(9, "UART8_CTS"), - STM32_FUNCTION(10, "LCD_G3"), - STM32_FUNCTION(11, "SAI2_SD_B"), -- STM32_FUNCTION(12, "QUADSPI_BK2_IO2 QUADSPI_BOOTBK2_IO2"), -+ STM32_FUNCTION(12, "QUADSPI_BK2_IO2"), - STM32_FUNCTION(13, "FMC_NE3"), - STM32_FUNCTION(14, "DCMI_D2"), - STM32_FUNCTION(15, "LCD_B2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(107, "PG11"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG11"), - STM32_FUNCTION(1, "TRACED11"), - STM32_FUNCTION(5, "USART1_TX"), -- STM32_FUNCTION(7, "UART4_TX UART_BOOT4_TX"), -- STM32_FUNCTION(9, "SPDIF_IN0"), -- STM32_FUNCTION(12, "ETH_GMII_TX_EN ETH_MII_TX_EN ETH_RGMII_TX_CTL ETH_RMII_TX_EN"), -+ STM32_FUNCTION(7, "UART4_TX"), -+ STM32_FUNCTION(9, "SPDIFRX_IN0"), -+ STM32_FUNCTION(12, "ETH1_GMII_TX_EN ETH1_MII_TX_EN ETH1_RGMII_TX_CTL ETH1_RMII_TX_EN"), - STM32_FUNCTION(14, "DCMI_D3"), - STM32_FUNCTION(15, "LCD_B3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(108, "PG12"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG12"), - STM32_FUNCTION(2, "LPTIM1_IN1"), - STM32_FUNCTION(6, "SPI6_MISO"), - STM32_FUNCTION(7, "SAI4_CK2"), -- STM32_FUNCTION(8, "USART6_RTS USART_BOOT6_RTS"), -- STM32_FUNCTION(9, "SPDIF_IN1"), -+ STM32_FUNCTION(8, "USART6_RTS USART6_DE"), -+ STM32_FUNCTION(9, "SPDIFRX_IN1"), - STM32_FUNCTION(10, "LCD_B4"), - STM32_FUNCTION(11, "SAI4_SCK_A"), -- STM32_FUNCTION(12, "ETH_PHY_INTN"), -+ STM32_FUNCTION(12, "ETH1_PHY_INTN"), - STM32_FUNCTION(13, "FMC_NE4"), - STM32_FUNCTION(15, "LCD_B1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(109, "PG13"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG13"), - STM32_FUNCTION(1, "TRACED0"), - STM32_FUNCTION(2, "LPTIM1_OUT"), -@@ -1493,79 +1599,86 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(5, "SAI4_CK1"), - STM32_FUNCTION(6, "SPI6_SCK"), - STM32_FUNCTION(7, "SAI1_SCK_A"), -- STM32_FUNCTION(8, "USART6_CTS_NSS USART_BOOT6_CTS_NSS"), -+ STM32_FUNCTION(8, "USART6_CTS USART6_NSS"), - STM32_FUNCTION(11, "SAI4_MCLK_A"), -- STM32_FUNCTION(12, "ETH_GMII_TXD0 ETH_MII_TXD0 ETH_RGMII_TXD0 ETH_RMII_TXD0"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD0 ETH1_MII_TXD0 ETH1_RGMII_TXD0 ETH1_RMII_TXD0"), - STM32_FUNCTION(13, "FMC_A24"), - STM32_FUNCTION(15, "LCD_R0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(110, "PG14"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG14"), - STM32_FUNCTION(1, "TRACED1"), - STM32_FUNCTION(2, "LPTIM1_ETR"), - STM32_FUNCTION(6, "SPI6_MOSI"), - STM32_FUNCTION(7, "SAI4_D1"), - STM32_FUNCTION(8, "USART6_TX"), -- STM32_FUNCTION(10, "QUADSPI_BK2_IO3 QUADSPI_BOOTBK2_IO3"), -+ STM32_FUNCTION(10, "QUADSPI_BK2_IO3"), - STM32_FUNCTION(11, "SAI4_SD_A"), -- STM32_FUNCTION(12, "ETH_GMII_TXD1 ETH_MII_TXD1 ETH_RGMII_TXD1 ETH_RMII_TXD1"), -+ STM32_FUNCTION(12, "ETH1_GMII_TXD1 ETH1_MII_TXD1 ETH1_RGMII_TXD1 ETH1_RMII_TXD1"), - STM32_FUNCTION(13, "FMC_A25"), - STM32_FUNCTION(15, "LCD_B0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(111, "PG15"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOG15"), - STM32_FUNCTION(1, "TRACED7"), - STM32_FUNCTION(3, "SAI1_D2"), - STM32_FUNCTION(5, "I2C2_SDA"), - STM32_FUNCTION(7, "SAI1_FS_A"), -- STM32_FUNCTION(8, "USART6_CTS_NSS USART_BOOT6_CTS_NSS"), -+ STM32_FUNCTION(8, "USART6_CTS USART6_NSS"), - STM32_FUNCTION(11, "SDMMC3_CK"), - STM32_FUNCTION(14, "DCMI_D13"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(112, "PH0"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOH0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(113, "PH1"), -+ STM32MP157CAA | STM32MP157CAC | STM32MP157CAB | STM32MP157CAD, - STM32_FUNCTION(0, "GPIOH1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(114, "PH2"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH2"), - STM32_FUNCTION(2, "LPTIM1_IN2"), -- STM32_FUNCTION(10, "QUADSPI_BK2_IO0 QUADSPI_BOOTBK2_IO0"), -+ STM32_FUNCTION(10, "QUADSPI_BK2_IO0"), - STM32_FUNCTION(11, "SAI2_SCK_B"), -- STM32_FUNCTION(12, "ETH_GMII_CRS ETH_MII_CRS"), -+ STM32_FUNCTION(12, "ETH1_GMII_CRS ETH1_MII_CRS"), - STM32_FUNCTION(15, "LCD_R0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(115, "PH3"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH3"), -- STM32_FUNCTION(4, "DFSDM_CK4"), -- STM32_FUNCTION(10, "QUADSPI_BK2_IO1 QUADSPI_BOOTBK2_IO1"), -+ STM32_FUNCTION(4, "DFSDM1_CKIN4"), -+ STM32_FUNCTION(10, "QUADSPI_BK2_IO1"), - STM32_FUNCTION(11, "SAI2_MCLK_B"), -- STM32_FUNCTION(12, "ETH_GMII_COL ETH_MII_COL"), -+ STM32_FUNCTION(12, "ETH1_GMII_COL ETH1_MII_COL"), - STM32_FUNCTION(15, "LCD_R1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(116, "PH4"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH4"), - STM32_FUNCTION(5, "I2C2_SCL"), - STM32_FUNCTION(10, "LCD_G5"), -@@ -1573,8 +1686,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(117, "PH5"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH5"), - STM32_FUNCTION(5, "I2C2_SDA"), - STM32_FUNCTION(6, "SPI5_NSS"), -@@ -1582,31 +1696,34 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(118, "PH6"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH6"), - STM32_FUNCTION(3, "TIM12_CH1"), - STM32_FUNCTION(5, "I2C2_SMBA"), - STM32_FUNCTION(6, "SPI5_SCK"), -- STM32_FUNCTION(12, "ETH_GMII_RXD2 ETH_MII_RXD2 ETH_RGMII_RXD2"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD2 ETH1_MII_RXD2 ETH1_RGMII_RXD2"), - STM32_FUNCTION(13, "MDIOS_MDIO"), - STM32_FUNCTION(14, "DCMI_D8"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(119, "PH7"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH7"), - STM32_FUNCTION(5, "I2C3_SCL"), - STM32_FUNCTION(6, "SPI5_MISO"), -- STM32_FUNCTION(12, "ETH_GMII_RXD3 ETH_MII_RXD3 ETH_RGMII_RXD3"), -+ STM32_FUNCTION(12, "ETH1_GMII_RXD3 ETH1_MII_RXD3 ETH1_RGMII_RXD3"), - STM32_FUNCTION(13, "MDIOS_MDC"), - STM32_FUNCTION(14, "DCMI_D9"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(120, "PH8"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH8"), - STM32_FUNCTION(3, "TIM5_ETR"), - STM32_FUNCTION(5, "I2C3_SDA"), -@@ -1615,8 +1732,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(121, "PH9"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH9"), - STM32_FUNCTION(3, "TIM12_CH2"), - STM32_FUNCTION(5, "I2C3_SMBA"), -@@ -1625,8 +1743,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(122, "PH10"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH10"), - STM32_FUNCTION(3, "TIM5_CH1"), - STM32_FUNCTION(5, "I2C4_SMBA"), -@@ -1636,8 +1755,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(123, "PH11"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH11"), - STM32_FUNCTION(3, "TIM5_CH2"), - STM32_FUNCTION(5, "I2C4_SCL"), -@@ -1647,8 +1767,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(124, "PH12"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH12"), - STM32_FUNCTION(1, "HDP2"), - STM32_FUNCTION(3, "TIM5_CH3"), -@@ -1659,50 +1780,53 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(125, "PH13"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH13"), - STM32_FUNCTION(4, "TIM8_CH1N"), - STM32_FUNCTION(9, "UART4_TX"), -- STM32_FUNCTION(10, "CAN1_TX"), -+ STM32_FUNCTION(10, "FDCAN1_TX"), - STM32_FUNCTION(15, "LCD_G2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(126, "PH14"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH14"), - STM32_FUNCTION(4, "TIM8_CH2N"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "CAN1_RX"), -+ STM32_FUNCTION(10, "FDCAN1_RX"), - STM32_FUNCTION(14, "DCMI_D4"), - STM32_FUNCTION(15, "LCD_G3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(127, "PH15"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOH15"), - STM32_FUNCTION(4, "TIM8_CH3N"), -- STM32_FUNCTION(10, "CAN1_TXFD"), - STM32_FUNCTION(14, "DCMI_D11"), - STM32_FUNCTION(15, "LCD_G4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(128, "PI0"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI0"), - STM32_FUNCTION(3, "TIM5_CH4"), - STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"), -- STM32_FUNCTION(10, "CAN1_RXFD"), - STM32_FUNCTION(14, "DCMI_D13"), - STM32_FUNCTION(15, "LCD_G5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(129, "PI1"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI1"), - STM32_FUNCTION(4, "TIM8_BKIN2"), - STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"), -@@ -1711,8 +1835,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(130, "PI2"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI2"), - STM32_FUNCTION(4, "TIM8_CH4"), - STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"), -@@ -1721,8 +1846,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(131, "PI3"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI3"), - STM32_FUNCTION(4, "TIM8_ETR"), - STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"), -@@ -1730,8 +1856,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(132, "PI4"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI4"), - STM32_FUNCTION(4, "TIM8_BKIN"), - STM32_FUNCTION(11, "SAI2_MCLK_A"), -@@ -1740,8 +1867,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(133, "PI5"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI5"), - STM32_FUNCTION(4, "TIM8_CH1"), - STM32_FUNCTION(11, "SAI2_SCK_A"), -@@ -1750,8 +1878,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(134, "PI6"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI6"), - STM32_FUNCTION(4, "TIM8_CH2"), - STM32_FUNCTION(11, "SAI2_SD_A"), -@@ -1760,8 +1889,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(135, "PI7"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI7"), - STM32_FUNCTION(4, "TIM8_CH3"), - STM32_FUNCTION(11, "SAI2_FS_A"), -@@ -1770,35 +1900,38 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(136, "PI8"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI8"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(137, "PI9"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI9"), - STM32_FUNCTION(1, "HDP1"), - STM32_FUNCTION(9, "UART4_RX"), -- STM32_FUNCTION(10, "CAN1_RX"), -+ STM32_FUNCTION(10, "FDCAN1_RX"), - STM32_FUNCTION(15, "LCD_VSYNC"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(138, "PI10"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI10"), - STM32_FUNCTION(1, "HDP0"), -- STM32_FUNCTION(9, "USART3_CTS_NSS USART_BOOT3_CTS_NSS"), -- STM32_FUNCTION(10, "CAN1_RXFD"), -- STM32_FUNCTION(12, "ETH_GMII_RX_ER ETH_MII_RX_ER"), -+ STM32_FUNCTION(9, "USART3_CTS USART3_NSS"), -+ STM32_FUNCTION(12, "ETH1_GMII_RX_ER ETH1_MII_RX_ER"), - STM32_FUNCTION(15, "LCD_HSYNC"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(139, "PI11"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOI11"), - STM32_FUNCTION(1, "MCO1"), - STM32_FUNCTION(6, "I2S_CKIN"), -@@ -1806,8 +1939,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(140, "PI12"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOI12"), - STM32_FUNCTION(1, "TRACED0"), - STM32_FUNCTION(3, "HDP0"), -@@ -1815,8 +1949,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(141, "PI13"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOI13"), - STM32_FUNCTION(1, "TRACED1"), - STM32_FUNCTION(3, "HDP1"), -@@ -1824,24 +1959,27 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(142, "PI14"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOI14"), - STM32_FUNCTION(1, "TRACECLK"), - STM32_FUNCTION(15, "LCD_CLK"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(143, "PI15"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOI15"), - STM32_FUNCTION(10, "LCD_G2"), - STM32_FUNCTION(15, "LCD_R0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(144, "PJ0"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ0"), - STM32_FUNCTION(1, "TRACED8"), - STM32_FUNCTION(10, "LCD_R7"), -@@ -1849,16 +1987,18 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(145, "PJ1"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ1"), - STM32_FUNCTION(1, "TRACED9"), - STM32_FUNCTION(15, "LCD_R2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(146, "PJ2"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ2"), - STM32_FUNCTION(1, "TRACED10"), - STM32_FUNCTION(14, "DSI_TE"), -@@ -1866,24 +2006,27 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(147, "PJ3"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ3"), - STM32_FUNCTION(1, "TRACED11"), - STM32_FUNCTION(15, "LCD_R4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(148, "PJ4"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ4"), - STM32_FUNCTION(1, "TRACED12"), - STM32_FUNCTION(15, "LCD_R5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(149, "PJ5"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ5"), - STM32_FUNCTION(1, "TRACED2"), - STM32_FUNCTION(3, "HDP2"), -@@ -1891,8 +2034,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(150, "PJ6"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ6"), - STM32_FUNCTION(1, "TRACED3"), - STM32_FUNCTION(3, "HDP3"), -@@ -1901,8 +2045,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(151, "PJ7"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ7"), - STM32_FUNCTION(1, "TRACED13"), - STM32_FUNCTION(4, "TIM8_CH2N"), -@@ -1910,8 +2055,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(152, "PJ8"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ8"), - STM32_FUNCTION(1, "TRACED14"), - STM32_FUNCTION(2, "TIM1_CH3N"), -@@ -1921,8 +2067,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(153, "PJ9"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ9"), - STM32_FUNCTION(1, "TRACED15"), - STM32_FUNCTION(2, "TIM1_CH3"), -@@ -1932,8 +2079,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(154, "PJ10"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ10"), - STM32_FUNCTION(2, "TIM1_CH2N"), - STM32_FUNCTION(4, "TIM8_CH2"), -@@ -1942,8 +2090,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(155, "PJ11"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ11"), - STM32_FUNCTION(2, "TIM1_CH2"), - STM32_FUNCTION(4, "TIM8_CH2N"), -@@ -1952,38 +2101,43 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(156, "PJ12"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ12"), - STM32_FUNCTION(10, "LCD_G3"), - STM32_FUNCTION(15, "LCD_B0"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(157, "PJ13"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ13"), - STM32_FUNCTION(10, "LCD_G4"), - STM32_FUNCTION(15, "LCD_B1"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(158, "PJ14"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ14"), - STM32_FUNCTION(15, "LCD_B2"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(159, "PJ15"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOJ15"), - STM32_FUNCTION(15, "LCD_B3"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(160, "PK0"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK0"), - STM32_FUNCTION(2, "TIM1_CH1N"), - STM32_FUNCTION(4, "TIM8_CH3"), -@@ -1992,8 +2146,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(161, "PK1"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK1"), - STM32_FUNCTION(1, "TRACED4"), - STM32_FUNCTION(2, "TIM1_CH1"), -@@ -2004,8 +2159,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(162, "PK2"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK2"), - STM32_FUNCTION(1, "TRACED5"), - STM32_FUNCTION(2, "TIM1_BKIN"), -@@ -2015,22 +2171,25 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(163, "PK3"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK3"), - STM32_FUNCTION(15, "LCD_B4"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(164, "PK4"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK4"), - STM32_FUNCTION(15, "LCD_B5"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(165, "PK5"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK5"), - STM32_FUNCTION(1, "TRACED6"), - STM32_FUNCTION(3, "HDP6"), -@@ -2038,8 +2197,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(166, "PK6"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK6"), - STM32_FUNCTION(1, "TRACED7"), - STM32_FUNCTION(3, "HDP7"), -@@ -2047,8 +2207,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(167, "PK7"), -+ STM32MP157CAA, - STM32_FUNCTION(0, "GPIOK7"), - STM32_FUNCTION(15, "LCD_DE"), - STM32_FUNCTION(16, "EVENTOUT"), -@@ -2057,8 +2218,9 @@ static const struct stm32_desc_pin stm32mp157_pins[] = { - }; - - static const struct stm32_desc_pin stm32mp157_z_pins[] = { -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(400, "PZ0"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ0"), - STM32_FUNCTION(3, "I2C6_SCL"), - STM32_FUNCTION(4, "I2C2_SCL"), -@@ -2068,8 +2230,9 @@ static const struct stm32_desc_pin stm32mp157_z_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(401, "PZ1"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ1"), - STM32_FUNCTION(3, "I2C6_SDA"), - STM32_FUNCTION(4, "I2C2_SDA"), -@@ -2081,8 +2244,9 @@ static const struct stm32_desc_pin stm32mp157_z_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(402, "PZ2"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ2"), - STM32_FUNCTION(3, "I2C6_SCL"), - STM32_FUNCTION(4, "I2C2_SCL"), -@@ -2094,21 +2258,23 @@ static const struct stm32_desc_pin stm32mp157_z_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(403, "PZ3"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ3"), - STM32_FUNCTION(3, "I2C6_SDA"), - STM32_FUNCTION(4, "I2C2_SDA"), - STM32_FUNCTION(5, "I2C5_SDA"), - STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"), - STM32_FUNCTION(7, "I2C4_SDA"), -- STM32_FUNCTION(8, "USART1_CTS_NSS"), -+ STM32_FUNCTION(8, "USART1_CTS USART1_NSS"), - STM32_FUNCTION(9, "SPI6_NSS"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(404, "PZ4"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ4"), - STM32_FUNCTION(3, "I2C6_SCL"), - STM32_FUNCTION(4, "I2C2_SCL"), -@@ -2117,19 +2283,21 @@ static const struct stm32_desc_pin stm32mp157_z_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(405, "PZ5"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ5"), - STM32_FUNCTION(3, "I2C6_SDA"), - STM32_FUNCTION(4, "I2C2_SDA"), - STM32_FUNCTION(5, "I2C5_SDA"), - STM32_FUNCTION(7, "I2C4_SDA"), -- STM32_FUNCTION(8, "USART1_RTS"), -+ STM32_FUNCTION(8, "USART1_RTS USART1_DE"), - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(406, "PZ6"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ6"), - STM32_FUNCTION(3, "I2C6_SCL"), - STM32_FUNCTION(4, "I2C2_SCL"), -@@ -2140,8 +2308,9 @@ static const struct stm32_desc_pin stm32mp157_z_pins[] = { - STM32_FUNCTION(16, "EVENTOUT"), - STM32_FUNCTION(17, "ANALOG") - ), -- STM32_PIN( -+ STM32_PIN_PKG( - PINCTRL_PIN(407, "PZ7"), -+ STM32MP157CAA | STM32MP157CAC, - STM32_FUNCTION(0, "GPIOZ7"), - STM32_FUNCTION(3, "I2C6_SDA"), - STM32_FUNCTION(4, "I2C2_SDA"), -@@ -2159,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { - static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { - .pins = stm32mp157_z_pins, - .npins = ARRAY_SIZE(stm32mp157_z_pins), -+ .pin_base_shift = STM32MP157_Z_BASE_SHIFT, - }; - - static const struct of_device_id stm32mp157_pctrl_match[] = { -@@ -2173,11 +2343,16 @@ static const struct of_device_id stm32mp157_pctrl_match[] = { - { } - }; - -+static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = { -+ SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume) -+}; -+ - static struct platform_driver stm32mp157_pinctrl_driver = { - .probe = stm32_pctl_probe, - .driver = { - .name = "stm32mp157-pinctrl", - .of_match_table = stm32mp157_pctrl_match, -+ .pm = &stm32_pinctrl_dev_pm_ops, - }, - }; - -diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c -index 28e1f64..b461412 100644 ---- a/drivers/pwm/pwm-stm32-lp.c -+++ b/drivers/pwm/pwm-stm32-lp.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -20,6 +21,8 @@ struct stm32_pwm_lp { - struct pwm_chip chip; - struct clk *clk; - struct regmap *regmap; -+ struct pwm_state suspend; -+ bool suspended; - }; - - static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip) -@@ -229,6 +232,40 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev) - return pwmchip_remove(&priv->chip); - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_pwm_lp_suspend(struct device *dev) -+{ -+ struct stm32_pwm_lp *priv = dev_get_drvdata(dev); -+ -+ pwm_get_state(&priv->chip.pwms[0], &priv->suspend); -+ priv->suspended = priv->suspend.enabled; -+ -+ /* safe to call pwm_disable() for already disabled pwm */ -+ pwm_disable(&priv->chip.pwms[0]); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_pwm_lp_resume(struct device *dev) -+{ -+ struct stm32_pwm_lp *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; -+ -+ /* Only restore suspended pwm, not to disrupt other MFD child */ -+ if (!priv->suspended) -+ return 0; -+ -+ return pwm_apply_state(&priv->chip.pwms[0], &priv->suspend); -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend, -+ stm32_pwm_lp_resume); -+ - static const struct of_device_id stm32_pwm_lp_of_match[] = { - { .compatible = "st,stm32-pwm-lp", }, - {}, -@@ -241,6 +278,7 @@ static struct platform_driver stm32_pwm_lp_driver = { - .driver = { - .name = "stm32-pwm-lp", - .of_match_table = of_match_ptr(stm32_pwm_lp_of_match), -+ .pm = &stm32_pwm_lp_pm_ops, - }, - }; - module_platform_driver(stm32_pwm_lp_driver); -diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c -index 4f84255..4688425 100644 ---- a/drivers/pwm/pwm-stm32.c -+++ b/drivers/pwm/pwm-stm32.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -19,6 +20,12 @@ - #define CCMR_CHANNEL_MASK 0xFF - #define MAX_BREAKINPUT 2 - -+struct stm32_breakinput { -+ u32 index; -+ u32 level; -+ u32 filter; -+}; -+ - struct stm32_pwm { - struct pwm_chip chip; - struct mutex lock; /* protect pwm config/enable */ -@@ -26,15 +33,13 @@ struct stm32_pwm { - struct regmap *regmap; - u32 max_arr; - bool have_complementary_output; -+ struct stm32_breakinput breakinput[MAX_BREAKINPUT]; -+ unsigned int nbreakinput; -+ struct pwm_state suspend[4]; -+ bool suspended[4]; - u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */ - }; - --struct stm32_breakinput { -- u32 index; -- u32 level; -- u32 filter; --}; -- - static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip) - { - return container_of(chip, struct stm32_pwm, chip); -@@ -374,9 +379,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, - else - regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); - -- regmap_update_bits(priv->regmap, TIM_BDTR, -- TIM_BDTR_MOE | TIM_BDTR_AOE, -- TIM_BDTR_MOE | TIM_BDTR_AOE); -+ regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE); - - return 0; - } -@@ -512,15 +515,27 @@ static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, - return (bdtr & bke) ? 0 : -EINVAL; - } - --static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv, -+static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv) -+{ -+ int i, ret = 0; -+ -+ for (i = 0; i < priv->nbreakinput && !ret; i++) { -+ ret = stm32_pwm_set_breakinput(priv, -+ priv->breakinput[i].index, -+ priv->breakinput[i].level, -+ priv->breakinput[i].filter); -+ } -+ -+ return ret; -+} -+ -+static int stm32_pwm_probe_breakinputs(struct stm32_pwm *priv, - struct device_node *np) - { -- struct stm32_breakinput breakinput[MAX_BREAKINPUT]; -- int nb, ret, i, array_size; -+ int nb, ret, array_size; - - nb = of_property_count_elems_of_size(np, "st,breakinput", - sizeof(struct stm32_breakinput)); -- - /* - * Because "st,breakinput" parameter is optional do not make probe - * failed if it doesn't exist. -@@ -531,20 +546,14 @@ static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv, - if (nb > MAX_BREAKINPUT) - return -EINVAL; - -+ priv->nbreakinput = nb; - array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32); - ret = of_property_read_u32_array(np, "st,breakinput", -- (u32 *)breakinput, array_size); -+ (u32 *)priv->breakinput, array_size); - if (ret) - return ret; - -- for (i = 0; i < nb && !ret; i++) { -- ret = stm32_pwm_set_breakinput(priv, -- breakinput[i].index, -- breakinput[i].level, -- breakinput[i].filter); -- } -- -- return ret; -+ return stm32_pwm_apply_breakinputs(priv); - } - - static void stm32_pwm_detect_complementary(struct stm32_pwm *priv) -@@ -608,11 +617,13 @@ static int stm32_pwm_probe(struct platform_device *pdev) - priv->regmap = ddata->regmap; - priv->clk = ddata->clk; - priv->max_arr = ddata->max_arr; -+ priv->chip.of_xlate = of_pwm_xlate_with_flags; -+ priv->chip.of_pwm_n_cells = 3; - - if (!priv->regmap || !priv->clk) - return -EINVAL; - -- ret = stm32_pwm_apply_breakinputs(priv, np); -+ ret = stm32_pwm_probe_breakinputs(priv, np); - if (ret) - return ret; - -@@ -645,6 +656,53 @@ static int stm32_pwm_remove(struct platform_device *pdev) - return 0; - } - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_pwm_suspend(struct device *dev) -+{ -+ struct stm32_pwm *priv = dev_get_drvdata(dev); -+ unsigned int i; -+ -+ for (i = 0; i < priv->chip.npwm; i++) { -+ pwm_get_state(&priv->chip.pwms[i], &priv->suspend[i]); -+ priv->suspended[i] = priv->suspend[i].enabled; -+ -+ /* safe to call pwm_disable() for already disabled pwm */ -+ pwm_disable(&priv->chip.pwms[i]); -+ } -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_pwm_resume(struct device *dev) -+{ -+ struct stm32_pwm *priv = dev_get_drvdata(dev); -+ unsigned int i; -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; -+ -+ ret = stm32_pwm_apply_breakinputs(priv); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < priv->chip.npwm; i++) { -+ /* Only resume active pwm, not to disrupt other MFD child */ -+ if (!priv->suspended[i]) -+ continue; -+ -+ ret = pwm_apply_state(&priv->chip.pwms[i], &priv->suspend[i]); -+ if (ret) -+ break; -+ } -+ -+ return ret; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume); -+ - static const struct of_device_id stm32_pwm_of_match[] = { - { .compatible = "st,stm32-pwm", }, - { /* end node */ }, -@@ -657,6 +715,7 @@ static struct platform_driver stm32_pwm_driver = { - .driver = { - .name = "stm32-pwm", - .of_match_table = stm32_pwm_of_match, -+ .pm = &stm32_pwm_pm_ops, - }, - }; - module_platform_driver(stm32_pwm_driver); -diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c -index 72bdda4..13d9bd5 100644 ---- a/drivers/pwm/sysfs.c -+++ b/drivers/pwm/sysfs.c -@@ -249,6 +249,7 @@ static void pwm_export_release(struct device *child) - static int pwm_export_child(struct device *parent, struct pwm_device *pwm) - { - struct pwm_export *export; -+ char *pwm_prop[2]; - int ret; - - if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) -@@ -276,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) - export = NULL; - return ret; - } -+ pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm); -+ pwm_prop[1] = NULL; -+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); -+ kfree(pwm_prop[0]); - - return 0; - } -@@ -288,6 +293,7 @@ static int pwm_unexport_match(struct device *child, void *data) - static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) - { - struct device *child; -+ char *pwm_prop[2]; - - if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) - return -ENODEV; -@@ -296,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) - if (!child) - return -ENODEV; - -+ pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm); -+ pwm_prop[1] = NULL; -+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); -+ kfree(pwm_prop[0]); -+ - /* for device_find_child() */ - put_device(child); - device_unregister(child); -diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h -index b5a2174..e3b45a8 100644 ---- a/include/dt-bindings/pinctrl/stm32-pinfunc.h -+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h -@@ -26,11 +26,18 @@ - #define AF14 0xf - #define AF15 0x10 - #define ANALOG 0x11 -+#define RSVD 0x12 - - /* define Pins number*/ - #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) - - #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/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h -index 8f5dbb8..4349124 100644 ---- a/include/linux/pinctrl/pinctrl.h -+++ b/include/linux/pinctrl/pinctrl.h -@@ -125,6 +125,10 @@ struct pinctrl_ops { - * the hardware description - * @custom_conf_items: Information how to print @params in debugfs, must be - * the same size as the @custom_params, i.e. @num_custom_params -+ * @link_consumers: If true create a device link between pinctrl and its -+ * consumers (i.e. the devices requesting pin control states). This is -+ * sometimes necessary to ascertain the right suspend/resume order for -+ * example. - */ - struct pinctrl_desc { - const char *name; -@@ -139,6 +143,7 @@ struct pinctrl_desc { - const struct pinconf_generic_params *custom_params; - const struct pin_config_item *custom_conf_items; - #endif -+ bool link_consumers; - }; - - /* External interface to pin controller */ -@@ -148,6 +153,8 @@ extern int pinctrl_register_and_init(struct pinctrl_desc *pctldesc, - struct pinctrl_dev **pctldev); - extern int pinctrl_enable(struct pinctrl_dev *pctldev); - -+extern int pinctrl_claim_hogs(struct pinctrl_dev *pctldev); -+ - /* Please use pinctrl_register_and_init() and pinctrl_enable() instead */ - extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, - struct device *dev, void *driver_data); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch deleted file mode 100644 index 7aa58c6..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch +++ /dev/null @@ -1,1232 +0,0 @@ -From 099f59a43431770a338d464c59e26d9e4a2b30eb Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:44 +0100 -Subject: [PATCH 20/31] ARM stm32mp1 r3 REGULATOR - ---- - drivers/regulator/Kconfig | 19 + - drivers/regulator/Makefile | 2 + - drivers/regulator/core.c | 6 + - drivers/regulator/stm32-pwr.c | 245 +++++++++++++ - drivers/regulator/stm32-vrefbuf.c | 126 ++++++- - drivers/regulator/stpmic1_regulator.c | 632 ++++++++++++++++++++++++++++++++++ - include/linux/regulator/driver.h | 1 + - 7 files changed, 1023 insertions(+), 8 deletions(-) - create mode 100644 drivers/regulator/stm32-pwr.c - create mode 100644 drivers/regulator/stpmic1_regulator.c - -diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig -index 329cdd3..9ecafba 100644 ---- a/drivers/regulator/Kconfig -+++ b/drivers/regulator/Kconfig -@@ -803,6 +803,25 @@ config REGULATOR_STM32_VREFBUF - This driver can also be built as a module. If so, the module - will be called stm32-vrefbuf. - -+config REGULATOR_STM32_PWR -+ bool "STMicroelectronics STM32 PWR" -+ depends on ARCH_STM32 -+ help -+ This driver supports internal regulators (1V1 & 1V8) in the -+ STMicroelectronics STM32 chips. -+ -+config REGULATOR_STPMIC1 -+ tristate "STMicroelectronics STPMIC1 PMIC Regulators" -+ depends on MFD_STPMIC1 -+ help -+ This driver supports STMicroelectronics STPMIC1 PMIC voltage -+ regulators and switches. The STPMIC1 regulators supply power to -+ an application processor as well as to external system -+ peripherals such as DDR, Flash memories and system devices. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called stpmic1_regulator. -+ - config REGULATOR_TI_ABB - tristate "TI Adaptive Body Bias on-chip LDO" - depends on ARCH_OMAP -diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile -index bba9c48..a818c5d 100644 ---- a/drivers/regulator/Makefile -+++ b/drivers/regulator/Makefile -@@ -101,6 +101,8 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o - obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o - obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o - obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o -+obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o -+obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o - obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o - obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o - obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o -diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c -index f312764..1a40a4a 100644 ---- a/drivers/regulator/core.c -+++ b/drivers/regulator/core.c -@@ -4605,6 +4605,12 @@ struct device *rdev_get_dev(struct regulator_dev *rdev) - } - EXPORT_SYMBOL_GPL(rdev_get_dev); - -+struct regmap *rdev_get_regmap(struct regulator_dev *rdev) -+{ -+ return rdev->regmap; -+} -+EXPORT_SYMBOL_GPL(rdev_get_regmap); -+ - void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) - { - return reg_init_data->driver_data; -diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c -new file mode 100644 -index 0000000..e6f41eb ---- /dev/null -+++ b/drivers/regulator/stm32-pwr.c -@@ -0,0 +1,245 @@ -+/* -+ * Copyright (C) STMicroelectronics SA 2017 -+ * Author: Gabriel Fernandez -+ * -+ * License terms: GPL V2.0. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope 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 . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Registers -+ */ -+#define REG_PWR_CR3 0x0C -+ -+/* -+ * SYSTEM_PARAMETER -+ */ -+#define REG_1_1_EN BIT(30) -+#define REG_1_8_EN BIT(28) -+#define USB_3_3_EN BIT(24) -+ -+#define STM32_SMC_PWR 0x82001001 -+#define STM32_WRITE 0x1 -+#define STM32_SMC_REG_SET 0x2 -+#define STM32_SMC_REG_CLEAR 0x3 -+ -+#define SMC(class, op, address, val)\ -+ ({\ -+ struct arm_smccc_res res;\ -+ arm_smccc_smc(class, op, address, val,\ -+ 0, 0, 0, 0, &res);\ -+ }) -+ -+static int stm32_pwr_secure_regulator_enable(struct regulator_dev *rdev) -+{ -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, rdev->desc->enable_reg, -+ rdev->desc->enable_mask); -+ -+ return 0; -+} -+ -+static int stm32_pwr_secure_regulator_disable(struct regulator_dev *rdev) -+{ -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, rdev->desc->enable_reg, -+ rdev->desc->enable_mask); -+ -+ return 0; -+} -+ -+static const struct regulator_ops stm32_pwr_reg_ops = { -+ .list_voltage = regulator_list_voltage_linear, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .is_enabled = regulator_is_enabled_regmap, -+}; -+ -+static const struct regulator_ops stm32_pwr_reg_secure_ops = { -+ .list_voltage = regulator_list_voltage_linear, -+ .enable = stm32_pwr_secure_regulator_enable, -+ .disable = stm32_pwr_secure_regulator_disable, -+ .is_enabled = regulator_is_enabled_regmap, -+}; -+ -+static const struct regulator_desc stm32_pwr_reg11 = { -+ .name = "REG11", -+ .of_match = of_match_ptr("reg11"), -+ .n_voltages = 1, -+ .type = REGULATOR_VOLTAGE, -+ .min_uV = 1100000, -+ .fixed_uV = 1100000, -+ .ops = &stm32_pwr_reg_ops, -+ .enable_reg = REG_PWR_CR3, -+ .enable_mask = REG_1_1_EN, -+ .owner = THIS_MODULE, -+ .supply_name = "vdd", -+}; -+ -+static const struct regulator_desc stm32_pwr_reg18 = { -+ .name = "REG18", -+ .of_match = of_match_ptr("reg18"), -+ .n_voltages = 1, -+ .type = REGULATOR_VOLTAGE, -+ .min_uV = 1800000, -+ .fixed_uV = 1800000, -+ .ops = &stm32_pwr_reg_ops, -+ .enable_reg = REG_PWR_CR3, -+ .enable_mask = REG_1_8_EN, -+ .owner = THIS_MODULE, -+ .supply_name = "vdd", -+}; -+ -+static const struct regulator_desc stm32_pwr_usb33 = { -+ .name = "USB33", -+ .of_match = of_match_ptr("usb33"), -+ .n_voltages = 1, -+ .type = REGULATOR_VOLTAGE, -+ .min_uV = 3300000, -+ .fixed_uV = 3300000, -+ .ops = &stm32_pwr_reg_ops, -+ .enable_reg = REG_PWR_CR3, -+ .enable_mask = USB_3_3_EN, -+ .owner = THIS_MODULE, -+ .supply_name = "vdd_3v3_usbfs", -+}; -+ -+static struct of_regulator_match stm32_pwr_reg_matches[] = { -+ { .name = "reg11", .driver_data = (void *)&stm32_pwr_reg11 }, -+ { .name = "reg18", .driver_data = (void *)&stm32_pwr_reg18 }, -+ { .name = "usb33", .driver_data = (void *)&stm32_pwr_usb33 }, -+}; -+ -+#define STM32PWR_REG_NUM_REGS ARRAY_SIZE(stm32_pwr_reg_matches) -+ -+static int is_stm32_soc_secured(struct platform_device *pdev, int *val) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct regmap *syscon; -+ u32 reg, mask; -+ int tzc_val = 0; -+ int err; -+ -+ syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); -+ if (IS_ERR(syscon)) { -+ dev_err(&pdev->dev, "tzcr syscon required !\n"); -+ return PTR_ERR(syscon); -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 1, ®); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr offset required !\n"); -+ return err; -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr mask required !\n"); -+ return err; -+ } -+ -+ err = regmap_read(syscon, reg, &tzc_val); -+ if (err) { -+ dev_err(&pdev->dev, "failed to read tzcr status !\n"); -+ return err; -+ } -+ -+ *val = tzc_val & mask; -+ -+ return 0; -+} -+ -+static int stm32_power_regulator_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct regulator_dev *rdev; -+ struct regulator_config config = { }; -+ struct regmap *regmap; -+ struct regulator_desc *desc; -+ int i, ret = 0; -+ int tzen = 0; -+ -+ of_regulator_match(&pdev->dev, np, stm32_pwr_reg_matches, -+ STM32PWR_REG_NUM_REGS); -+ -+ regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ config.regmap = regmap; -+ config.dev = &pdev->dev; -+ -+ ret = is_stm32_soc_secured(pdev, &tzen); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < STM32PWR_REG_NUM_REGS; i++) { -+ struct of_regulator_match *match = &stm32_pwr_reg_matches[i]; -+ -+ if (!match->init_data || -+ !match->of_node) -+ continue; -+ -+ config.init_data = match->init_data; -+ config.driver_data = match->driver_data; -+ config.of_node = match->of_node; -+ -+ if (tzen) { -+ desc = match->driver_data; -+ desc->ops = &stm32_pwr_reg_secure_ops; -+ } -+ -+ rdev = devm_regulator_register(&pdev->dev, -+ match->driver_data, -+ &config); -+ if (IS_ERR(rdev)) { -+ ret = PTR_ERR(rdev); -+ dev_err(&pdev->dev, -+ "Failed to register regulator: %d\n", ret); -+ break; -+ } -+ } -+ return ret; -+} -+ -+static const struct of_device_id stm32_pwr_reg_of_match[] = { -+ { .compatible = "st,stm32mp1,pwr-reg", }, -+ {}, -+}; -+ -+static struct platform_driver stm32_pwr_reg_driver = { -+ .probe = stm32_power_regulator_probe, -+ .driver = { -+ .name = "stm32-pwr-regulator", -+ .of_match_table = of_match_ptr(stm32_pwr_reg_of_match), -+ }, -+}; -+ -+static int __init stm32_pwr_regulator_init(void) -+{ -+ return platform_driver_register(&stm32_pwr_reg_driver); -+} -+subsys_initcall(stm32_pwr_regulator_init); -diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c -index e0a9c44..a74dffe 100644 ---- a/drivers/regulator/stm32-vrefbuf.c -+++ b/drivers/regulator/stm32-vrefbuf.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - - /* STM32 VREFBUF registers */ - #define STM32_VREFBUF_CSR 0x00 -@@ -25,9 +26,12 @@ - #define STM32_HIZ BIT(1) - #define STM32_ENVR BIT(0) - -+#define STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS 10 -+ - struct stm32_vrefbuf { - void __iomem *base; - struct clk *clk; -+ struct device *dev; - }; - - static const unsigned int stm32_vrefbuf_voltages[] = { -@@ -38,9 +42,16 @@ static const unsigned int stm32_vrefbuf_voltages[] = { - static int stm32_vrefbuf_enable(struct regulator_dev *rdev) - { - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -- u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ u32 val; - int ret; - -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(priv->dev); -+ return ret; -+ } -+ -+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); - val = (val & ~STM32_HIZ) | STM32_ENVR; - writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); - -@@ -59,45 +70,95 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) - writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); - } - -+ pm_runtime_mark_last_busy(priv->dev); -+ pm_runtime_put_autosuspend(priv->dev); -+ - return ret; - } - - static int stm32_vrefbuf_disable(struct regulator_dev *rdev) - { - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -- u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ u32 val; -+ int ret; - -- val = (val & ~STM32_ENVR) | STM32_HIZ; -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(priv->dev); -+ return ret; -+ } -+ -+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ val &= ~STM32_ENVR; - writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); - -+ pm_runtime_mark_last_busy(priv->dev); -+ pm_runtime_put_autosuspend(priv->dev); -+ - return 0; - } - - static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev) - { - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -+ int ret; - -- return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(priv->dev); -+ return ret; -+ } -+ -+ ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; -+ -+ pm_runtime_mark_last_busy(priv->dev); -+ pm_runtime_put_autosuspend(priv->dev); -+ -+ return ret; - } - - static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev, - unsigned sel) - { - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -- u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ u32 val; -+ int ret; - -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(priv->dev); -+ return ret; -+ } -+ -+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); - val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel); - writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); - -+ pm_runtime_mark_last_busy(priv->dev); -+ pm_runtime_put_autosuspend(priv->dev); -+ - return 0; - } - - static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev) - { - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -- u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ u32 val; -+ int ret; - -- return FIELD_GET(STM32_VRS, val); -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(priv->dev); -+ return ret; -+ } -+ -+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -+ ret = FIELD_GET(STM32_VRS, val); -+ -+ pm_runtime_mark_last_busy(priv->dev); -+ pm_runtime_put_autosuspend(priv->dev); -+ -+ return ret; - } - - static const struct regulator_ops stm32_vrefbuf_volt_ops = { -@@ -115,6 +176,7 @@ static const struct regulator_desc stm32_vrefbuf_regu = { - .volt_table = stm32_vrefbuf_voltages, - .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages), - .ops = &stm32_vrefbuf_volt_ops, -+ .off_on_delay = 1000, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }; -@@ -130,6 +192,7 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; -+ priv->dev = &pdev->dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, res); -@@ -140,10 +203,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_set_autosuspend_delay(&pdev->dev, -+ STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ - ret = clk_prepare_enable(priv->clk); - if (ret) { - dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret); -- return ret; -+ goto err_pm_stop; - } - - config.dev = &pdev->dev; -@@ -161,10 +231,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) - } - platform_set_drvdata(pdev, rdev); - -+ pm_runtime_mark_last_busy(&pdev->dev); -+ pm_runtime_put_autosuspend(&pdev->dev); -+ - return 0; - - err_clk_dis: - clk_disable_unprepare(priv->clk); -+err_pm_stop: -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); - - return ret; - } -@@ -174,12 +251,44 @@ static int stm32_vrefbuf_remove(struct platform_device *pdev) - struct regulator_dev *rdev = platform_get_drvdata(pdev); - struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); - -+ pm_runtime_get_sync(&pdev->dev); - regulator_unregister(rdev); - clk_disable_unprepare(priv->clk); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); - - return 0; - }; - -+#if defined(CONFIG_PM) -+static int stm32_vrefbuf_runtime_suspend(struct device *dev) -+{ -+ struct regulator_dev *rdev = dev_get_drvdata(dev); -+ struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -+ -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static int stm32_vrefbuf_runtime_resume(struct device *dev) -+{ -+ struct regulator_dev *rdev = dev_get_drvdata(dev); -+ struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); -+ -+ return clk_prepare_enable(priv->clk); -+} -+#endif -+ -+static const struct dev_pm_ops stm32_vrefbuf_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(stm32_vrefbuf_runtime_suspend, -+ stm32_vrefbuf_runtime_resume, -+ NULL) -+}; -+ - static const struct of_device_id stm32_vrefbuf_of_match[] = { - { .compatible = "st,stm32-vrefbuf", }, - {}, -@@ -192,6 +301,7 @@ static struct platform_driver stm32_vrefbuf_driver = { - .driver = { - .name = "stm32-vrefbuf", - .of_match_table = of_match_ptr(stm32_vrefbuf_of_match), -+ .pm = &stm32_vrefbuf_pm_ops, - }, - }; - module_platform_driver(stm32_vrefbuf_driver); -diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c -new file mode 100644 -index 0000000..29f1584 ---- /dev/null -+++ b/drivers/regulator/stpmic1_regulator.c -@@ -0,0 +1,632 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2018 -+// Author: Pascal Paillet for STMicroelectronics. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/** -+ * stpmic1 regulator description: this structure is used as driver data -+ * @desc: regulator framework description -+ * @mask_reset_reg: mask reset register address -+ * @mask_reset_mask: mask rank and mask reset register mask -+ * @icc_reg: icc register address -+ * @icc_mask: icc register mask -+ */ -+struct stpmic1_regulator_cfg { -+ struct regulator_desc desc; -+ u8 mask_reset_reg; -+ u8 mask_reset_mask; -+ u8 icc_reg; -+ u8 icc_mask; -+}; -+ -+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); -+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); -+static int stpmic1_set_icc(struct regulator_dev *rdev); -+static unsigned int stpmic1_map_mode(unsigned int mode); -+ -+enum { -+ STPMIC1_BUCK1 = 0, -+ STPMIC1_BUCK2 = 1, -+ STPMIC1_BUCK3 = 2, -+ STPMIC1_BUCK4 = 3, -+ STPMIC1_LDO1 = 4, -+ STPMIC1_LDO2 = 5, -+ STPMIC1_LDO3 = 6, -+ STPMIC1_LDO4 = 7, -+ STPMIC1_LDO5 = 8, -+ STPMIC1_LDO6 = 9, -+ STPMIC1_VREF_DDR = 10, -+ STPMIC1_BOOST = 11, -+ STPMIC1_VBUS_OTG = 12, -+ STPMIC1_SW_OUT = 13, -+}; -+ -+/* Enable time worst case is 5000mV/(2250uV/uS) */ -+#define PMIC_ENABLE_TIME_US 2200 -+ -+static const struct regulator_linear_range buck1_ranges[] = { -+ REGULATOR_LINEAR_RANGE(725000, 0, 4, 0), -+ REGULATOR_LINEAR_RANGE(725000, 5, 36, 25000), -+ REGULATOR_LINEAR_RANGE(1500000, 37, 63, 0), -+}; -+ -+static const struct regulator_linear_range buck2_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0), -+ REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0), -+ REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0), -+ REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0), -+ REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0), -+ REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0), -+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), -+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), -+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0), -+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0), -+ REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0), -+}; -+ -+static const struct regulator_linear_range buck3_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0), -+ REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0), -+ REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0), -+ REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0), -+ REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0), -+ REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000), -+ REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0), -+}; -+ -+static const struct regulator_linear_range buck4_ranges[] = { -+ REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000), -+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), -+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), -+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0), -+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0), -+ REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000), -+ REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0), -+}; -+ -+static const struct regulator_linear_range ldo1_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), -+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), -+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), -+}; -+ -+static const struct regulator_linear_range ldo2_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), -+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), -+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), -+}; -+ -+static const struct regulator_linear_range ldo3_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), -+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), -+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), -+ /* with index 31 LDO3 is in DDR mode */ -+ REGULATOR_LINEAR_RANGE(500000, 31, 31, 0), -+}; -+ -+static const struct regulator_linear_range ldo5_ranges[] = { -+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), -+ REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000), -+ REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0), -+}; -+ -+static const struct regulator_linear_range ldo6_ranges[] = { -+ REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000), -+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), -+}; -+ -+static const struct regulator_ops stpmic1_ldo_ops = { -+ .list_voltage = regulator_list_voltage_linear_range, -+ .map_voltage = regulator_map_voltage_linear_range, -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .get_voltage_sel = regulator_get_voltage_sel_regmap, -+ .set_voltage_sel = regulator_set_voltage_sel_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static const struct regulator_ops stpmic1_ldo3_ops = { -+ .list_voltage = regulator_list_voltage_linear_range, -+ .map_voltage = regulator_map_voltage_iterate, -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .get_voltage_sel = regulator_get_voltage_sel_regmap, -+ .set_voltage_sel = regulator_set_voltage_sel_regmap, -+ .get_bypass = regulator_get_bypass_regmap, -+ .set_bypass = regulator_set_bypass_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static const struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static const struct regulator_ops stpmic1_buck_ops = { -+ .list_voltage = regulator_list_voltage_linear_range, -+ .map_voltage = regulator_map_voltage_linear_range, -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .get_voltage_sel = regulator_get_voltage_sel_regmap, -+ .set_voltage_sel = regulator_set_voltage_sel_regmap, -+ .set_pull_down = regulator_set_pull_down_regmap, -+ .set_mode = stpmic1_set_mode, -+ .get_mode = stpmic1_get_mode, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static const struct regulator_ops stpmic1_vref_ddr_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+}; -+ -+static const struct regulator_ops stpmic1_boost_regul_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static const struct regulator_ops stpmic1_switch_regul_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+ .set_active_discharge = regulator_set_active_discharge_regmap, -+}; -+ -+#define REG_LDO(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 32, \ -+ .ops = &stpmic1_ldo_ops, \ -+ .linear_ranges = base ## _ranges, \ -+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .vsel_reg = ids##_ACTIVE_CR, \ -+ .vsel_mask = LDO_VOLTAGE_MASK, \ -+ .enable_reg = ids##_ACTIVE_CR, \ -+ .enable_mask = LDO_ENABLE_MASK, \ -+ .enable_val = 1, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_LDO3(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 32, \ -+ .ops = &stpmic1_ldo3_ops, \ -+ .linear_ranges = ldo3_ranges, \ -+ .n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .vsel_reg = LDO3_ACTIVE_CR, \ -+ .vsel_mask = LDO_VOLTAGE_MASK, \ -+ .enable_reg = LDO3_ACTIVE_CR, \ -+ .enable_mask = LDO_ENABLE_MASK, \ -+ .enable_val = 1, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .bypass_reg = LDO3_ACTIVE_CR, \ -+ .bypass_mask = LDO_BYPASS_MASK, \ -+ .bypass_val_on = LDO_BYPASS_MASK, \ -+ .bypass_val_off = 0, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_LDO4(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 1, \ -+ .ops = &stpmic1_ldo4_fixed_regul_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .min_uV = 3300000, \ -+ .fixed_uV = 3300000, \ -+ .enable_reg = LDO4_ACTIVE_CR, \ -+ .enable_mask = LDO_ENABLE_MASK, \ -+ .enable_val = 1, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_BUCK(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .ops = &stpmic1_buck_ops, \ -+ .n_voltages = 64, \ -+ .linear_ranges = base ## _ranges, \ -+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .vsel_reg = ids##_ACTIVE_CR, \ -+ .vsel_mask = BUCK_VOLTAGE_MASK, \ -+ .enable_reg = ids##_ACTIVE_CR, \ -+ .enable_mask = BUCK_ENABLE_MASK, \ -+ .enable_val = 1, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .of_map_mode = stpmic1_map_mode, \ -+ .pull_down_reg = ids##_PULL_DOWN_REG, \ -+ .pull_down_mask = ids##_PULL_DOWN_MASK, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_VREF_DDR(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 1, \ -+ .ops = &stpmic1_vref_ddr_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .min_uV = 500000, \ -+ .fixed_uV = 500000, \ -+ .enable_reg = VREF_DDR_ACTIVE_CR, \ -+ .enable_mask = BUCK_ENABLE_MASK, \ -+ .enable_val = 1, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_BOOST(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 1, \ -+ .ops = &stpmic1_boost_regul_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .min_uV = 0, \ -+ .fixed_uV = 5000000, \ -+ .enable_reg = BST_SW_CR, \ -+ .enable_mask = BOOST_ENABLED, \ -+ .enable_val = BOOST_ENABLED, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_VBUS_OTG(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 1, \ -+ .ops = &stpmic1_switch_regul_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .min_uV = 0, \ -+ .fixed_uV = 5000000, \ -+ .enable_reg = BST_SW_CR, \ -+ .enable_mask = USBSW_OTG_SWITCH_ENABLED, \ -+ .enable_val = USBSW_OTG_SWITCH_ENABLED, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+ .active_discharge_reg = BST_SW_CR, \ -+ .active_discharge_mask = VBUS_OTG_DISCHARGE, \ -+ .active_discharge_on = VBUS_OTG_DISCHARGE, \ -+} -+ -+#define REG_SW_OUT(ids, base) { \ -+ .name = #ids, \ -+ .id = STPMIC1_##ids, \ -+ .n_voltages = 1, \ -+ .ops = &stpmic1_switch_regul_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ .min_uV = 0, \ -+ .fixed_uV = 5000000, \ -+ .enable_reg = BST_SW_CR, \ -+ .enable_mask = SWIN_SWOUT_ENABLED, \ -+ .enable_val = SWIN_SWOUT_ENABLED, \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+ .active_discharge_reg = BST_SW_CR, \ -+ .active_discharge_mask = SW_OUT_DISCHARGE, \ -+ .active_discharge_on = SW_OUT_DISCHARGE, \ -+} -+ -+static const struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { -+ [STPMIC1_BUCK1] = { -+ .desc = REG_BUCK(BUCK1, buck1), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(0), -+ .mask_reset_reg = BUCKS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(0), -+ }, -+ [STPMIC1_BUCK2] = { -+ .desc = REG_BUCK(BUCK2, buck2), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(1), -+ .mask_reset_reg = BUCKS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(1), -+ }, -+ [STPMIC1_BUCK3] = { -+ .desc = REG_BUCK(BUCK3, buck3), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(2), -+ .mask_reset_reg = BUCKS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(2), -+ }, -+ [STPMIC1_BUCK4] = { -+ .desc = REG_BUCK(BUCK4, buck4), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(3), -+ .mask_reset_reg = BUCKS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(3), -+ }, -+ [STPMIC1_LDO1] = { -+ .desc = REG_LDO(LDO1, ldo1), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(0), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(0), -+ }, -+ [STPMIC1_LDO2] = { -+ .desc = REG_LDO(LDO2, ldo2), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(1), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(1), -+ }, -+ [STPMIC1_LDO3] = { -+ .desc = REG_LDO3(LDO3, ldo3), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(2), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(2), -+ }, -+ [STPMIC1_LDO4] = { -+ .desc = REG_LDO4(LDO4, ldo4), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(3), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(3), -+ }, -+ [STPMIC1_LDO5] = { -+ .desc = REG_LDO(LDO5, ldo5), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(4), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(4), -+ }, -+ [STPMIC1_LDO6] = { -+ .desc = REG_LDO(LDO6, ldo6), -+ .icc_reg = LDOS_ICCTO_CR, -+ .icc_mask = BIT(5), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(5), -+ }, -+ [STPMIC1_VREF_DDR] = { -+ .desc = REG_VREF_DDR(VREF_DDR, vref_ddr), -+ .mask_reset_reg = LDOS_MASK_RESET_CR, -+ .mask_reset_mask = BIT(6), -+ }, -+ [STPMIC1_BOOST] = { -+ .desc = REG_BOOST(BOOST, boost), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(6), -+ }, -+ [STPMIC1_VBUS_OTG] = { -+ .desc = REG_VBUS_OTG(VBUS_OTG, pwr_sw1), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(4), -+ }, -+ [STPMIC1_SW_OUT] = { -+ .desc = REG_SW_OUT(SW_OUT, pwr_sw2), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(5), -+ }, -+}; -+ -+static unsigned int stpmic1_map_mode(unsigned int mode) -+{ -+ switch (mode) { -+ case STPMIC1_BUCK_MODE_NORMAL: -+ return REGULATOR_MODE_NORMAL; -+ case STPMIC1_BUCK_MODE_LP: -+ return REGULATOR_MODE_STANDBY; -+ default: -+ return REGULATOR_MODE_INVALID; -+ } -+} -+ -+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) -+{ -+ int value; -+ struct regmap *regmap = rdev_get_regmap(rdev); -+ -+ regmap_read(regmap, rdev->desc->enable_reg, &value); -+ -+ if (value & STPMIC1_BUCK_MODE_LP) -+ return REGULATOR_MODE_STANDBY; -+ -+ return REGULATOR_MODE_NORMAL; -+} -+ -+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) -+{ -+ int value; -+ struct regmap *regmap = rdev_get_regmap(rdev); -+ -+ switch (mode) { -+ case REGULATOR_MODE_NORMAL: -+ value = STPMIC1_BUCK_MODE_NORMAL; -+ break; -+ case REGULATOR_MODE_STANDBY: -+ value = STPMIC1_BUCK_MODE_LP; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return regmap_update_bits(regmap, rdev->desc->enable_reg, -+ STPMIC1_BUCK_MODE_LP, value); -+} -+ -+static int stpmic1_set_icc(struct regulator_dev *rdev) -+{ -+ struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev); -+ struct regmap *regmap = rdev_get_regmap(rdev); -+ -+ /* enable switch off in case of over current */ -+ return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask, -+ cfg->icc_mask); -+} -+ -+static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) -+{ -+ struct regulator_dev *rdev = (struct regulator_dev *)data; -+ -+ mutex_lock(&rdev->mutex); -+ -+ /* Send an overcurrent notification */ -+ regulator_notifier_call_chain(rdev, -+ REGULATOR_EVENT_OVER_CURRENT, -+ NULL); -+ -+ mutex_unlock(&rdev->mutex); -+ -+ return IRQ_HANDLED; -+} -+ -+#define MATCH(_name, _id) \ -+ [STPMIC1_##_id] = { \ -+ .name = #_name, \ -+ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \ -+ } -+ -+static struct of_regulator_match stpmic1_matches[] = { -+ MATCH(buck1, BUCK1), -+ MATCH(buck2, BUCK2), -+ MATCH(buck3, BUCK3), -+ MATCH(buck4, BUCK4), -+ MATCH(ldo1, LDO1), -+ MATCH(ldo2, LDO2), -+ MATCH(ldo3, LDO3), -+ MATCH(ldo4, LDO4), -+ MATCH(ldo5, LDO5), -+ MATCH(ldo6, LDO6), -+ MATCH(vref_ddr, VREF_DDR), -+ MATCH(boost, BOOST), -+ MATCH(pwr_sw1, VBUS_OTG), -+ MATCH(pwr_sw2, SW_OUT), -+}; -+ -+static int stpmic1_regulator_register(struct platform_device *pdev, int id, -+ struct of_regulator_match *match, -+ const struct stpmic1_regulator_cfg *cfg) -+{ -+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); -+ struct regulator_dev *rdev; -+ struct regulator_config config = {}; -+ int ret = 0; -+ int irq; -+ -+ config.dev = &pdev->dev; -+ config.init_data = match->init_data; -+ config.of_node = match->of_node; -+ config.regmap = pmic_dev->regmap; -+ config.driver_data = (void *)cfg; -+ -+ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); -+ if (IS_ERR(rdev)) { -+ dev_err(&pdev->dev, "failed to register %s regulator\n", -+ cfg->desc.name); -+ return PTR_ERR(rdev); -+ } -+ -+ /* set mask reset */ -+ if (of_get_property(config.of_node, "st,mask-reset", NULL) && -+ cfg->mask_reset_reg != 0) { -+ ret = regmap_update_bits(pmic_dev->regmap, -+ cfg->mask_reset_reg, -+ cfg->mask_reset_mask, -+ cfg->mask_reset_mask); -+ if (ret) { -+ dev_err(&pdev->dev, "set mask reset failed\n"); -+ return ret; -+ } -+ } -+ -+ /* setup an irq handler for over-current detection */ -+ irq = of_irq_get(config.of_node, 0); -+ if (irq > 0) { -+ ret = devm_request_threaded_irq(&pdev->dev, -+ irq, NULL, -+ stpmic1_curlim_irq_handler, -+ IRQF_ONESHOT | IRQF_SHARED, -+ pdev->name, rdev); -+ if (ret) { -+ dev_err(&pdev->dev, "Request IRQ failed\n"); -+ return ret; -+ } -+ } -+ return 0; -+} -+ -+static int stpmic1_regulator_probe(struct platform_device *pdev) -+{ -+ int i, ret; -+ -+ ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, -+ ARRAY_SIZE(stpmic1_matches)); -+ if (ret < 0) { -+ dev_err(&pdev->dev, -+ "Error in PMIC regulator device tree node"); -+ return ret; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { -+ ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], -+ &stpmic1_regulator_cfgs[i]); -+ if (ret < 0) -+ return ret; -+ } -+ -+ dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); -+ -+ return 0; -+} -+ -+static const struct of_device_id of_pmic_regulator_match[] = { -+ { .compatible = "st,stpmic1-regulators" }, -+ { }, -+}; -+ -+MODULE_DEVICE_TABLE(of, of_pmic_regulator_match); -+ -+static struct platform_driver stpmic1_regulator_driver = { -+ .driver = { -+ .name = "stpmic1-regulator", -+ .of_match_table = of_match_ptr(of_pmic_regulator_match), -+ }, -+ .probe = stpmic1_regulator_probe, -+}; -+ -+module_platform_driver(stpmic1_regulator_driver); -+ -+MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver"); -+MODULE_AUTHOR("Pascal Paillet "); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h -index 0fd8fbb..85c5427 100644 ---- a/include/linux/regulator/driver.h -+++ b/include/linux/regulator/driver.h -@@ -492,6 +492,7 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev, - - void *rdev_get_drvdata(struct regulator_dev *rdev); - struct device *rdev_get_dev(struct regulator_dev *rdev); -+struct regmap *rdev_get_regmap(struct regulator_dev *rdev); - int rdev_get_id(struct regulator_dev *rdev); - - int regulator_mode_to_status(unsigned int); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch deleted file mode 100644 index 0294aab..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch +++ /dev/null @@ -1,4019 +0,0 @@ -From b1e1c0d118b5f460f13d08f7a4f25210aaa88641 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:45 +0100 -Subject: [PATCH 21/31] ARM stm32mp1 r3 REMOTEPROC RPMSG RESET - ---- - drivers/remoteproc/Kconfig | 36 ++ - drivers/remoteproc/Makefile | 3 + - drivers/remoteproc/remoteproc_core.c | 689 ++++++++++++++++++++----- - drivers/remoteproc/remoteproc_debugfs.c | 22 +- - drivers/remoteproc/remoteproc_internal.h | 12 +- - drivers/remoteproc/remoteproc_virtio.c | 58 ++- - drivers/remoteproc/rproc_srm_core.c | 303 +++++++++++ - drivers/remoteproc/rproc_srm_core.h | 98 ++++ - drivers/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++++ - drivers/remoteproc/stm32_rproc.c | 858 +++++++++++++++++++++++++++++++ - drivers/reset/reset-stm32mp1.c | 48 ++ - drivers/rpmsg/Kconfig | 9 + - drivers/rpmsg/Makefile | 1 + - drivers/rpmsg/rpmsg_core.c | 19 + - drivers/rpmsg/rpmsg_internal.h | 2 + - drivers/rpmsg/rpmsg_tty.c | 310 +++++++++++ - drivers/rpmsg/virtio_rpmsg_bus.c | 17 +- - include/linux/remoteproc.h | 38 +- - include/linux/rpmsg.h | 9 + - 19 files changed, 3127 insertions(+), 149 deletions(-) - create mode 100644 drivers/remoteproc/rproc_srm_core.c - create mode 100644 drivers/remoteproc/rproc_srm_core.h - create mode 100644 drivers/remoteproc/rproc_srm_dev.c - create mode 100644 drivers/remoteproc/stm32_rproc.c - create mode 100644 drivers/rpmsg/rpmsg_tty.c - -diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig -index 052d4dd..c1f3f00 100644 ---- a/drivers/remoteproc/Kconfig -+++ b/drivers/remoteproc/Kconfig -@@ -13,6 +13,25 @@ config REMOTEPROC - - if REMOTEPROC - -+config REMOTEPROC_SRM_CORE -+ tristate "Remoteproc System Resource Manager core" -+ depends on RPMSG -+ help -+ Say y here to enable the core driver of the remoteproc System Resource -+ Manager (SRM). -+ The SRM handles resources allocated to remote processors. -+ The core part is in charge of controlling the device children. -+ -+config REMOTEPROC_SRM_DEV -+ tristate "Remoteproc System Resource Manager device" -+ depends on REMOTEPROC_SRM_CORE -+ help -+ Say y here to enable the device driver of the remoteproc System -+ Resource Manager (SRM). -+ The SRM handles resources allocated to remote processors. -+ The device part is in charge of reserving and initializing resources -+ for a peripheral assigned to a coprocessor. -+ - config IMX_REMOTEPROC - tristate "IMX6/7 remoteproc support" - depends on SOC_IMX6SX || SOC_IMX7D -@@ -181,6 +200,23 @@ config ST_REMOTEPROC - config ST_SLIM_REMOTEPROC - tristate - -+config STM32_RPROC -+ tristate "STM32 remoteproc support" -+ depends on ARCH_STM32 -+ depends on REMOTEPROC -+ select MAILBOX -+ select REMOTEPROC_SRM_CORE -+ select REMOTEPROC_SRM_DEV -+ help -+ Say y here to support STM32 MCU processors via the -+ remote processor framework. -+ -+ You want to say y here in order to enable AMP -+ use-cases to run on your platform (dedicated firmware could be -+ offloaded to remote MCU processors using this framework). -+ -+ This can be either built-in or a loadable module. -+ - endif # REMOTEPROC - - endmenu -diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile -index 03332fa..1e43aa6 100644 ---- a/drivers/remoteproc/Makefile -+++ b/drivers/remoteproc/Makefile -@@ -9,6 +9,8 @@ remoteproc-y += remoteproc_debugfs.o - remoteproc-y += remoteproc_sysfs.o - remoteproc-y += remoteproc_virtio.o - remoteproc-y += remoteproc_elf_loader.o -+obj-$(CONFIG_REMOTEPROC_SRM_CORE) += rproc_srm_core.o -+obj-$(CONFIG_REMOTEPROC_SRM_DEV) += rproc_srm_dev.o - obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o - obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o - obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o -@@ -25,3 +27,4 @@ qcom_wcnss_pil-y += qcom_wcnss.o - qcom_wcnss_pil-y += qcom_wcnss_iris.o - obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o - obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o -+obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o -diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index aa62067..6430747 100644 ---- a/drivers/remoteproc/remoteproc_core.c -+++ b/drivers/remoteproc/remoteproc_core.c -@@ -39,8 +39,11 @@ - #include - #include - #include -+#include -+#include - #include - #include -+#include - #include - - #include "remoteproc_internal.h" -@@ -53,6 +56,11 @@ typedef int (*rproc_handle_resources_t)(struct rproc *rproc, - typedef int (*rproc_handle_resource_t)(struct rproc *rproc, - void *, int offset, int avail); - -+static int rproc_alloc_carveout(struct rproc *rproc, -+ struct rproc_mem_entry *mem); -+static int rproc_release_carveout(struct rproc *rproc, -+ struct rproc_mem_entry *mem); -+ - /* Unique indices for remoteproc devices */ - static DEFINE_IDA(rproc_dev_index); - -@@ -140,6 +148,23 @@ static void rproc_disable_iommu(struct rproc *rproc) - iommu_domain_free(domain); - } - -+phys_addr_t rproc_va_to_pa(void *cpu_addr) -+{ -+ /* -+ * Return physical address according to virtual address location -+ * - in vmalloc: if region ioremapped or defined as dma_alloc_coherent -+ * - in kernel: if region allocated in generic dma memory pool -+ */ -+ if (is_vmalloc_addr(cpu_addr)) { -+ return page_to_phys(vmalloc_to_page(cpu_addr)) + -+ offset_in_page(cpu_addr); -+ } -+ -+ WARN_ON(!virt_addr_valid(cpu_addr)); -+ return virt_to_phys(cpu_addr); -+} -+EXPORT_SYMBOL(rproc_va_to_pa); -+ - /** - * rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address - * @rproc: handle of a remote processor -@@ -183,6 +208,10 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) - list_for_each_entry(carveout, &rproc->carveouts, node) { - int offset = da - carveout->da; - -+ /* Verify that carveout is allocated */ -+ if (!carveout->va) -+ continue; -+ - /* try next carveout if da is too small */ - if (offset < 0) - continue; -@@ -201,27 +230,128 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) - } - EXPORT_SYMBOL(rproc_da_to_va); - -+/** -+ * rproc_find_carveout_by_name() - lookup the carveout region by a name -+ * @rproc: handle of a remote processor -+ * @name,..: carveout name to find (standard printf format) -+ * -+ * Platform driver has the capability to register some pre-allacoted carveout -+ * (physically contiguous memory regions) before rproc firmware loading and -+ * associated resource table analysis. These regions may be dedicated memory -+ * regions internal to the coprocessor or specified DDR region with specific -+ * attributes -+ * -+ * This function is a helper function with which we can go over the -+ * allocated carveouts and return associated region characteristics like -+ * coprocessor address, length or processor virtual address. -+ * -+ * Return: a valid pointer on carveout entry on success or NULL on failure. -+ */ -+struct rproc_mem_entry * -+rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...) -+{ -+ va_list args; -+ char _name[32]; -+ struct rproc_mem_entry *carveout, *mem = NULL; -+ -+ if (!name) -+ return NULL; -+ -+ va_start(args, name); -+ vsnprintf(_name, sizeof(_name), name, args); -+ va_end(args); -+ -+ list_for_each_entry(carveout, &rproc->carveouts, node) { -+ /* Compare carveout and requested names */ -+ if (!strcmp(carveout->name, _name)) { -+ mem = carveout; -+ break; -+ } -+ } -+ -+ return mem; -+} -+ -+/** -+ * rproc_check_carveout_da() - Check specified carveout da configuration -+ * @rproc: handle of a remote processor -+ * @mem: pointer on carveout to check -+ * @da: area device address -+ * @len: associated area size -+ * -+ * This function is a helper function to verify requested device area (couple -+ * da, len) is part of specified carevout. -+ * -+ * Return: 0 if carveout matchs request else -ENOMEM -+ */ -+static int rproc_check_carveout_da(struct rproc *rproc, -+ struct rproc_mem_entry *mem, u32 da, u32 len) -+{ -+ struct device *dev = &rproc->dev; -+ int delta; -+ -+ /* Check requested resource length */ -+ if (len > mem->len) { -+ dev_err(dev, "Registered carveout doesn't fit len request\n"); -+ return -EINVAL; -+ } -+ -+ if (da != FW_RSC_ADDR_ANY && mem->da == FW_RSC_ADDR_ANY) { -+ /* Address doesn't match registered carveout configuration */ -+ return -EINVAL; -+ } else if (da != FW_RSC_ADDR_ANY && mem->da != FW_RSC_ADDR_ANY) { -+ delta = da - mem->da; -+ -+ /* Check requested resource belongs to registered carveout */ -+ if (delta < 0) { -+ dev_err(dev, -+ "Registered carveout doesn't fit da request\n"); -+ return -EINVAL; -+ } -+ -+ if (delta + len > mem->len) { -+ dev_err(dev, -+ "Registered carveout doesn't fit len request\n"); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ - int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) - { - struct rproc *rproc = rvdev->rproc; - struct device *dev = &rproc->dev; - struct rproc_vring *rvring = &rvdev->vring[i]; - struct fw_rsc_vdev *rsc; -- dma_addr_t dma; -- void *va; - int ret, size, notifyid; -+ struct rproc_mem_entry *mem; - - /* actual size of vring (in bytes) */ - size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); - -- /* -- * Allocate non-cacheable memory for the vring. In the future -- * this call will also configure the IOMMU for us -- */ -- va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL); -- if (!va) { -- dev_err(dev->parent, "dma_alloc_coherent failed\n"); -- return -EINVAL; -+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; -+ -+ /* Search for pre-registered carveout */ -+ mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index, -+ i); -+ if (mem) { -+ if (rproc_check_carveout_da(rproc, mem, rsc->vring[i].da, size)) -+ return -ENOMEM; -+ } else { -+ /* Register carveout in in list */ -+ mem = rproc_mem_entry_init(dev, 0, 0, size, rsc->vring[i].da, -+ rproc_alloc_carveout, -+ rproc_release_carveout, -+ "vdev%dvring%d", -+ rvdev->index, i); -+ if (!mem) { -+ dev_err(dev, "Can't allocate memory entry structure\n"); -+ return -ENOMEM; -+ } -+ -+ rproc_add_carveout(rproc, mem); - } - - /* -@@ -232,7 +362,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) - ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); - if (ret < 0) { - dev_err(dev, "idr_alloc failed: %d\n", ret); -- dma_free_coherent(dev->parent, size, va, dma); - return ret; - } - notifyid = ret; -@@ -241,21 +370,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) - if (notifyid > rproc->max_notifyid) - rproc->max_notifyid = notifyid; - -- dev_dbg(dev, "vring%d: va %pK dma %pad size 0x%x idr %d\n", -- i, va, &dma, size, notifyid); -- -- rvring->va = va; -- rvring->dma = dma; - rvring->notifyid = notifyid; - -- /* -- * Let the rproc know the notifyid and da of this vring. -- * Not all platforms use dma_alloc_coherent to automatically -- * set up the iommu. In this case the device address (da) will -- * hold the physical address and not the device address. -- */ -- rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; -- rsc->vring[i].da = dma; -+ /* Let the rproc know the notifyid of this vring.*/ - rsc->vring[i].notifyid = notifyid; - return 0; - } -@@ -287,12 +404,10 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) - - void rproc_free_vring(struct rproc_vring *rvring) - { -- int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); - struct rproc *rproc = rvring->rvdev->rproc; - int idx = rvring->rvdev->vring - rvring; - struct fw_rsc_vdev *rsc; - -- dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); - idr_remove(&rproc->notifyids, rvring->notifyid); - - /* reset resource entry info */ -@@ -316,6 +431,20 @@ static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed) - } - - /** -+ * rproc_rvdev_release() - release the existence of a rvdev -+ * -+ * @dev: the subdevice's dev -+ */ -+static void rproc_rvdev_release(struct device *dev) -+{ -+ struct rproc_vdev *rvdev = container_of(dev, struct rproc_vdev, dev); -+ -+ of_reserved_mem_device_release(dev); -+ -+ kfree(rvdev); -+} -+ -+/** - * rproc_handle_vdev() - handle a vdev fw resource - * @rproc: the remote processor - * @rsc: the vring resource descriptor -@@ -348,6 +477,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, - struct device *dev = &rproc->dev; - struct rproc_vdev *rvdev; - int i, ret; -+ char name[16]; - - /* make sure resource isn't truncated */ - if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring) -@@ -379,6 +509,30 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, - - rvdev->id = rsc->id; - rvdev->rproc = rproc; -+ rvdev->index = rproc->nb_vdev++; -+ -+ /* Initialise vdev subdevice */ -+ snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index); -+ rvdev->dev.parent = rproc->dev.parent; -+ rvdev->dev.release = rproc_rvdev_release; -+ dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name); -+ dev_set_drvdata(&rvdev->dev, rvdev); -+ -+ ret = device_register(&rvdev->dev); -+ if (ret) { -+ put_device(&rvdev->dev); -+ return ret; -+ } -+ /* Make device dma capable by inheriting from parent's capabilities */ -+ set_dma_ops(&rvdev->dev, get_dma_ops(rproc->dev.parent)); -+ -+ ret = dma_coerce_mask_and_coherent(&rvdev->dev, -+ dma_get_mask(rproc->dev.parent)); -+ if (ret) { -+ dev_warn(dev, -+ "Failed to set DMA mask %llx. Trying to continue... %x\n", -+ dma_get_mask(rproc->dev.parent), ret); -+ } - - /* parse the vrings */ - for (i = 0; i < rsc->num_of_vrings; i++) { -@@ -410,7 +564,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, - for (i--; i >= 0; i--) - rproc_free_vring(&rvdev->vring[i]); - free_rvdev: -- kfree(rvdev); -+ device_unregister(&rvdev->dev); - return ret; - } - -@@ -423,15 +577,12 @@ void rproc_vdev_release(struct kref *ref) - - for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) { - rvring = &rvdev->vring[id]; -- if (!rvring->va) -- continue; -- - rproc_free_vring(rvring); - } - - rproc_remove_subdev(rproc, &rvdev->subdev); - list_del(&rvdev->node); -- kfree(rvdev); -+ device_unregister(&rvdev->dev); - } - - /** -@@ -453,9 +604,8 @@ void rproc_vdev_release(struct kref *ref) - static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, - int offset, int avail) - { -- struct rproc_mem_entry *trace; -+ struct rproc_debug_trace *trace; - struct device *dev = &rproc->dev; -- void *ptr; - char name[15]; - - if (sizeof(*rsc) > avail) { -@@ -469,28 +619,23 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, - return -EINVAL; - } - -- /* what's the kernel address of this resource ? */ -- ptr = rproc_da_to_va(rproc, rsc->da, rsc->len); -- if (!ptr) { -- dev_err(dev, "erroneous trace resource entry\n"); -- return -EINVAL; -- } -- - trace = kzalloc(sizeof(*trace), GFP_KERNEL); - if (!trace) - return -ENOMEM; - - /* set the trace buffer dma properties */ -- trace->len = rsc->len; -- trace->va = ptr; -+ trace->trace_mem.len = rsc->len; -+ trace->trace_mem.da = rsc->da; -+ -+ /* set pointer on rproc device */ -+ trace->rproc = rproc; - - /* make sure snprintf always null terminates, even if truncating */ - snprintf(name, sizeof(name), "trace%d", rproc->num_traces); - - /* create the debugfs entry */ -- trace->priv = rproc_create_trace_file(name, rproc, trace); -- if (!trace->priv) { -- trace->va = NULL; -+ trace->tfile = rproc_create_trace_file(name, rproc, trace); -+ if (!trace->tfile) { - kfree(trace); - return -EINVAL; - } -@@ -499,8 +644,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, - - rproc->num_traces++; - -- dev_dbg(dev, "%s added: va %pK, da 0x%x, len 0x%x\n", -- name, ptr, rsc->da, rsc->len); -+ dev_dbg(dev, "%s added: da 0x%x, len 0x%x\n", -+ name, rsc->da, rsc->len); - - return 0; - } -@@ -584,61 +729,43 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, - } - - /** -- * rproc_handle_carveout() - handle phys contig memory allocation requests -+ * rproc_alloc_carveout() - allocated specified carveout - * @rproc: rproc handle -- * @rsc: the resource entry -- * @avail: size of available data (for image validation) -+ * @mem: the memory entry to allocate - * -- * This function will handle firmware requests for allocation of physically -- * contiguous memory regions. -- * -- * These request entries should come first in the firmware's resource table, -- * as other firmware entries might request placing other data objects inside -- * these memory regions (e.g. data/code segments, trace resource entries, ...). -- * -- * Allocating memory this way helps utilizing the reserved physical memory -- * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries -- * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB -- * pressure is important; it may have a substantial impact on performance. -+ * This function allocate specified memory entry @mem using -+ * dma_alloc_coherent() as default allocator - */ --static int rproc_handle_carveout(struct rproc *rproc, -- struct fw_rsc_carveout *rsc, -- int offset, int avail) -+static int rproc_alloc_carveout(struct rproc *rproc, -+ struct rproc_mem_entry *mem) - { -- struct rproc_mem_entry *carveout, *mapping; -+ struct rproc_mem_entry *mapping = NULL; - struct device *dev = &rproc->dev; - dma_addr_t dma; - void *va; - int ret; - -- if (sizeof(*rsc) > avail) { -- dev_err(dev, "carveout rsc is truncated\n"); -- return -EINVAL; -- } -- -- /* make sure reserved bytes are zeroes */ -- if (rsc->reserved) { -- dev_err(dev, "carveout rsc has non zero reserved bytes\n"); -- return -EINVAL; -- } -- -- dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n", -- rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags); -- -- carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); -- if (!carveout) -- return -ENOMEM; -- -- va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); -+ va = dma_alloc_coherent(dev->parent, mem->len, &dma, GFP_KERNEL); - if (!va) { - dev_err(dev->parent, -- "failed to allocate dma memory: len 0x%x\n", rsc->len); -- ret = -ENOMEM; -- goto free_carv; -+ "failed to allocate dma memory: len 0x%x\n", mem->len); -+ return -ENOMEM; - } - - dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n", -- va, &dma, rsc->len); -+ va, &dma, mem->len); -+ -+ if (mem->da != FW_RSC_ADDR_ANY && !rproc->domain) { -+ /* -+ * Check requested da is equal to dma address -+ * and print a warn message in case of missalignment. -+ * Don't stop rproc_start sequence as coprocessor may -+ * build pa to da translation on its side. -+ */ -+ if (mem->da != (u32)dma) -+ dev_warn(dev->parent, -+ "Allocated carveout doesn't fit device address request\n"); -+ } - - /* - * Ok, this is non-standard. -@@ -657,15 +784,15 @@ static int rproc_handle_carveout(struct rproc *rproc, - * to use the iommu-based DMA API: we expect 'dma' to contain the - * physical address in this case. - */ -- if (rproc->domain) { -+ if (mem->da != FW_RSC_ADDR_ANY && rproc->domain) { - mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); - if (!mapping) { - ret = -ENOMEM; - goto dma_free; - } - -- ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, -- rsc->flags); -+ ret = iommu_map(rproc->domain, mem->da, dma, mem->len, -+ mem->flags); - if (ret) { - dev_err(dev, "iommu_map failed: %d\n", ret); - goto free_mapping; -@@ -678,52 +805,226 @@ static int rproc_handle_carveout(struct rproc *rproc, - * We can't trust the remote processor not to change the - * resource table, so we must maintain this info independently. - */ -- mapping->da = rsc->da; -- mapping->len = rsc->len; -+ mapping->da = mem->da; -+ mapping->len = mem->len; - list_add_tail(&mapping->node, &rproc->mappings); - - dev_dbg(dev, "carveout mapped 0x%x to %pad\n", -- rsc->da, &dma); -+ mem->da, &dma); - } - -- /* -- * Some remote processors might need to know the pa -- * even though they are behind an IOMMU. E.g., OMAP4's -- * remote M3 processor needs this so it can control -- * on-chip hardware accelerators that are not behind -- * the IOMMU, and therefor must know the pa. -- * -- * Generally we don't want to expose physical addresses -- * if we don't have to (remote processors are generally -- * _not_ trusted), so we might want to do this only for -- * remote processor that _must_ have this (e.g. OMAP4's -- * dual M3 subsystem). -- * -- * Non-IOMMU processors might also want to have this info. -- * In this case, the device address and the physical address -- * are the same. -- */ -- rsc->pa = dma; -+ if (mem->da == FW_RSC_ADDR_ANY) { -+ /* Update device address as undefined by requester */ -+ if (sizeof(dma_addr_t) > sizeof(u32)) -+ dev_warn(dev, "DMA address cast in 32bit to fit resource table format\n"); - -- carveout->va = va; -- carveout->len = rsc->len; -- carveout->dma = dma; -- carveout->da = rsc->da; -+ mem->da = (u32)dma; -+ } - -- list_add_tail(&carveout->node, &rproc->carveouts); -+ mem->dma = dma; -+ mem->va = va; - - return 0; - - free_mapping: - kfree(mapping); - dma_free: -- dma_free_coherent(dev->parent, rsc->len, va, dma); --free_carv: -- kfree(carveout); -+ dma_free_coherent(dev->parent, mem->len, va, dma); - return ret; - } - --/* -+/** -+ * rproc_release_carveout() - release acquired carveout -+ * @rproc: rproc handle -+ * @mem: the memory entry to release -+ * -+ * This function releases specified memory entry @mem allocated via -+ * rproc_alloc_carveout() function by @rproc. -+ */ -+static int rproc_release_carveout(struct rproc *rproc, -+ struct rproc_mem_entry *mem) -+{ -+ struct device *dev = &rproc->dev; -+ -+ /* clean up carveout allocations */ -+ dma_free_coherent(dev->parent, mem->len, mem->va, mem->dma); -+ return 0; -+} -+ -+/** -+ * rproc_handle_carveout() - handle phys contig memory allocation requests -+ * @rproc: rproc handle -+ * @rsc: the resource entry -+ * @avail: size of available data (for image validation) -+ * -+ * This function will handle firmware requests for allocation of physically -+ * contiguous memory regions. -+ * -+ * These request entries should come first in the firmware's resource table, -+ * as other firmware entries might request placing other data objects inside -+ * these memory regions (e.g. data/code segments, trace resource entries, ...). -+ * -+ * Allocating memory this way helps utilizing the reserved physical memory -+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries -+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB -+ * pressure is important; it may have a substantial impact on performance. -+ */ -+static int rproc_handle_carveout(struct rproc *rproc, -+ struct fw_rsc_carveout *rsc, -+ int offset, int avail) -+{ -+ struct rproc_mem_entry *carveout; -+ struct device *dev = &rproc->dev; -+ -+ if (sizeof(*rsc) > avail) { -+ dev_err(dev, "carveout rsc is truncated\n"); -+ return -EINVAL; -+ } -+ -+ /* make sure reserved bytes are zeroes */ -+ if (rsc->reserved) { -+ dev_err(dev, "carveout rsc has non zero reserved bytes\n"); -+ return -EINVAL; -+ } -+ -+ dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n", -+ rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags); -+ -+ /* -+ * Check carveout rsc already part of a registered carveout, -+ * Search by name, then check the da and length -+ */ -+ carveout = rproc_find_carveout_by_name(rproc, rsc->name); -+ -+ if (carveout) { -+ if (carveout->rsc_offset != FW_RSC_ADDR_ANY) { -+ dev_err(dev, -+ "Carveout already associated to resource table\n"); -+ return -ENOMEM; -+ } -+ -+ if (rproc_check_carveout_da(rproc, carveout, rsc->da, rsc->len)) -+ return -ENOMEM; -+ -+ /* Update memory carveout with resource table info */ -+ carveout->rsc_offset = offset; -+ carveout->flags = rsc->flags; -+ -+ return 0; -+ } -+ -+ /* Register carveout in in list */ -+ carveout = rproc_mem_entry_init(dev, 0, 0, rsc->len, rsc->da, -+ rproc_alloc_carveout, -+ rproc_release_carveout, rsc->name); -+ if (!carveout) { -+ dev_err(dev, "Can't allocate memory entry structure\n"); -+ return -ENOMEM; -+ } -+ -+ carveout->flags = rsc->flags; -+ carveout->rsc_offset = offset; -+ rproc_add_carveout(rproc, carveout); -+ -+ return 0; -+} -+ -+/** -+ * rproc_add_carveout() - register an allocated carveout region -+ * @rproc: rproc handle -+ * @mem: memory entry to register -+ * -+ * This function registers specified memory entry in @rproc carveouts list. -+ * Specified carveout should have been allocated before registering. -+ */ -+void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) -+{ -+ list_add_tail(&mem->node, &rproc->carveouts); -+} -+EXPORT_SYMBOL(rproc_add_carveout); -+ -+/** -+ * rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct -+ * @dev: pointer on device struct -+ * @va: virtual address -+ * @dma: dma address -+ * @len: memory carveout length -+ * @da: device address -+ * @alloc: memory carveout allocation function -+ * @release: memory carveout release function -+ * @name: carveout name -+ * -+ * This function allocates a rproc_mem_entry struct and fill it with parameters -+ * provided by client. -+ */ -+struct rproc_mem_entry * -+rproc_mem_entry_init(struct device *dev, -+ void *va, dma_addr_t dma, int len, u32 da, -+ int (*alloc)(struct rproc *, struct rproc_mem_entry *), -+ int (*release)(struct rproc *, struct rproc_mem_entry *), -+ const char *name, ...) -+{ -+ struct rproc_mem_entry *mem; -+ va_list args; -+ -+ mem = kzalloc(sizeof(*mem), GFP_KERNEL); -+ if (!mem) -+ return mem; -+ -+ mem->va = va; -+ mem->dma = dma; -+ mem->da = da; -+ mem->len = len; -+ mem->alloc = alloc; -+ mem->release = release; -+ mem->rsc_offset = FW_RSC_ADDR_ANY; -+ mem->of_resm_idx = -1; -+ -+ va_start(args, name); -+ vsnprintf(mem->name, sizeof(mem->name), name, args); -+ va_end(args); -+ -+ return mem; -+} -+EXPORT_SYMBOL(rproc_mem_entry_init); -+ -+/** -+ * rproc_of_resm_mem_entry_init() - allocate and initialize rproc_mem_entry struct -+ * from a reserved memory phandle -+ * @dev: pointer on device struct -+ * @of_resm_idx: reserved memory phandle index in "memory-region" -+ * @len: memory carveout length -+ * @da: device address -+ * @name: carveout name -+ * -+ * This function allocates a rproc_mem_entry struct and fill it with parameters -+ * provided by client. -+ */ -+struct rproc_mem_entry * -+rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len, -+ u32 da, const char *name, ...) -+{ -+ struct rproc_mem_entry *mem; -+ va_list args; -+ -+ mem = kzalloc(sizeof(*mem), GFP_KERNEL); -+ if (!mem) -+ return mem; -+ -+ mem->da = da; -+ mem->len = len; -+ mem->rsc_offset = FW_RSC_ADDR_ANY; -+ mem->of_resm_idx = of_resm_idx; -+ -+ va_start(args, name); -+ vsnprintf(mem->name, sizeof(mem->name), name, args); -+ va_end(args); -+ -+ return mem; -+} -+EXPORT_SYMBOL(rproc_of_resm_mem_entry_init); -+ -+/** - * A lookup table for resource handlers. The indices are defined in - * enum fw_resource_type. - */ -@@ -845,6 +1146,74 @@ static void rproc_unprepare_subdevices(struct rproc *rproc) - } - - /** -+ * rproc_alloc_registered_carveouts() - allocate all carveouts registered -+ * in the list -+ * @rproc: the remote processor handle -+ * -+ * This function parses registered carveout list, performs allocation -+ * if alloc() ops registered and updates resource table information -+ * if rsc_offset set. -+ * -+ * Return: 0 on success -+ */ -+static int rproc_alloc_registered_carveouts(struct rproc *rproc) -+{ -+ struct rproc_mem_entry *entry, *tmp; -+ struct fw_rsc_carveout *rsc; -+ struct device *dev = &rproc->dev; -+ int ret; -+ -+ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { -+ if (entry->alloc) { -+ ret = entry->alloc(rproc, entry); -+ if (ret) { -+ dev_err(dev, "Unable to allocate carveout %s: %d\n", -+ entry->name, ret); -+ return -ENOMEM; -+ } -+ } -+ -+ if (entry->rsc_offset != FW_RSC_ADDR_ANY) { -+ /* update resource table */ -+ rsc = (void *)rproc->table_ptr + entry->rsc_offset; -+ -+ /* -+ * Some remote processors might need to know the pa -+ * even though they are behind an IOMMU. E.g., OMAP4's -+ * remote M3 processor needs this so it can control -+ * on-chip hardware accelerators that are not behind -+ * the IOMMU, and therefor must know the pa. -+ * -+ * Generally we don't want to expose physical addresses -+ * if we don't have to (remote processors are generally -+ * _not_ trusted), so we might want to do this only for -+ * remote processor that _must_ have this (e.g. OMAP4's -+ * dual M3 subsystem). -+ * -+ * Non-IOMMU processors might also want to have this info. -+ * In this case, the device address and the physical address -+ * are the same. -+ */ -+ -+ /* Use va if defined else dma to generate pa */ -+ if (sizeof(dma_addr_t) > sizeof(u32) || -+ sizeof(phys_addr_t) > sizeof(u32)) -+ dev_warn(dev, "Physical address cast in 32bit to fit resource table format\n"); -+ -+ if (entry->va) -+ rsc->pa = (u32)rproc_va_to_pa(entry->va); -+ else -+ rsc->pa = (u32)entry->dma; -+ -+ rsc->da = entry->da; -+ rsc->len = entry->len; -+ } -+ } -+ -+ return 0; -+} -+ -+/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -@@ -867,16 +1236,17 @@ static void rproc_coredump_cleanup(struct rproc *rproc) - */ - static void rproc_resource_cleanup(struct rproc *rproc) - { -+ struct rproc_debug_trace *trace, *trace_tmp; - struct rproc_mem_entry *entry, *tmp; - struct rproc_vdev *rvdev, *rvtmp; - struct device *dev = &rproc->dev; - - /* clean up debugfs trace entries */ -- list_for_each_entry_safe(entry, tmp, &rproc->traces, node) { -- rproc_remove_trace_file(entry->priv); -+ list_for_each_entry_safe(trace, trace_tmp, &rproc->traces, node) { -+ rproc_remove_trace_file(trace->tfile); - rproc->num_traces--; -- list_del(&entry->node); -- kfree(entry); -+ list_del(&trace->node); -+ kfree(trace); - } - - /* clean up iommu mapping entries */ -@@ -896,8 +1266,8 @@ static void rproc_resource_cleanup(struct rproc *rproc) - - /* clean up carveout allocations */ - list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { -- dma_free_coherent(dev->parent, entry->len, entry->va, -- entry->dma); -+ if (entry->release) -+ entry->release(rproc, entry); - list_del(&entry->node); - kfree(entry); - } -@@ -987,7 +1357,11 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) - if (ret) - return ret; - -- dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); -+ if (fw) -+ dev_info(dev, "Booting fw image %s, size %zd\n", name, -+ fw->size); -+ else -+ dev_info(dev, "Synchronizing with early booted co-processor\n"); - - /* - * if enabling an IOMMU isn't relevant for this rproc, this is -@@ -1009,6 +1383,9 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) - /* reset max_notifyid */ - rproc->max_notifyid = -1; - -+ /* reset handled vdev */ -+ rproc->nb_vdev = 0; -+ - /* handle fw resources which are required to boot rproc */ - ret = rproc_handle_resources(rproc, rproc_loading_handlers); - if (ret) { -@@ -1016,6 +1393,14 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) - goto clean_up_resources; - } - -+ /* Allocate carveout resources associated to rproc */ -+ ret = rproc_alloc_registered_carveouts(rproc); -+ if (ret) { -+ dev_err(dev, "Failed to allocate associated carveouts: %d\n", -+ ret); -+ goto clean_up_resources; -+ } -+ - ret = rproc_start(rproc, fw); - if (ret) - goto clean_up_resources; -@@ -1071,6 +1456,9 @@ static int rproc_stop(struct rproc *rproc, bool crashed) - struct device *dev = &rproc->dev; - int ret; - -+ if (rproc->state == RPROC_OFFLINE) -+ return 0; -+ - /* Stop any subdevices for the remote processor */ - rproc_stop_subdevices(rproc, crashed); - -@@ -1229,6 +1617,13 @@ int rproc_trigger_recovery(struct rproc *rproc) - /* generate coredump */ - rproc_coredump(rproc); - -+ if (!rproc->firmware) { -+ /* we don't know how to recover it, so try to shutdown it*/ -+ mutex_unlock(&rproc->lock); -+ rproc_shutdown(rproc); -+ return 0; -+ } -+ - /* load firmware */ - ret = request_firmware(&firmware_p, rproc->firmware, dev); - if (ret < 0) { -@@ -1290,7 +1685,7 @@ static void rproc_crash_handler_work(struct work_struct *work) - */ - int rproc_boot(struct rproc *rproc) - { -- const struct firmware *firmware_p; -+ const struct firmware *firmware_p = NULL; - struct device *dev; - int ret; - -@@ -1321,11 +1716,17 @@ int rproc_boot(struct rproc *rproc) - - dev_info(dev, "powering up %s\n", rproc->name); - -- /* load firmware */ -- ret = request_firmware(&firmware_p, rproc->firmware, dev); -- if (ret < 0) { -- dev_err(dev, "request_firmware failed: %d\n", ret); -- goto downref_rproc; -+ if (!rproc->early_boot) { -+ /* load firmware */ -+ ret = request_firmware(&firmware_p, rproc->firmware, dev); -+ if (ret < 0) { -+ dev_err(dev, "request_firmware failed: %d\n", ret); -+ goto downref_rproc; -+ } -+ } else { -+ /* set firmware name to null as unknown */ -+ kfree(rproc->firmware); -+ rproc->firmware = NULL; - } - - ret = rproc_fw_boot(rproc, firmware_p); -@@ -1479,8 +1880,22 @@ int rproc_add(struct rproc *rproc) - /* create debugfs entries */ - rproc_create_debug_dir(rproc); - -- /* if rproc is marked always-on, request it to boot */ -- if (rproc->auto_boot) { -+ /* add resource manager device */ -+ ret = devm_of_platform_populate(dev->parent); -+ if (ret < 0) -+ return ret; -+ -+ if (rproc->early_boot) { -+ /* -+ * If rproc is marked already booted, no need to wait -+ * for firmware. -+ * Just handle associated resources and start sub devices -+ */ -+ ret = rproc_boot(rproc); -+ if (ret < 0) -+ return ret; -+ } else if (rproc->auto_boot) { -+ /* if rproc is marked always-on, request it to boot */ - ret = rproc_trigger_auto_boot(rproc); - if (ret < 0) - return ret; -@@ -1706,6 +2121,8 @@ int rproc_del(struct rproc *rproc) - list_del(&rproc->node); - mutex_unlock(&rproc_list_mutex); - -+ of_platform_depopulate(rproc->dev.parent); -+ - device_del(&rproc->dev); - - return 0; -diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c -index a5c29f2..11240b4 100644 ---- a/drivers/remoteproc/remoteproc_debugfs.c -+++ b/drivers/remoteproc/remoteproc_debugfs.c -@@ -47,10 +47,23 @@ static struct dentry *rproc_dbg; - static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) - { -- struct rproc_mem_entry *trace = filp->private_data; -- int len = strnlen(trace->va, trace->len); -+ struct rproc_debug_trace *data = filp->private_data; -+ struct rproc_mem_entry *trace = &data->trace_mem; -+ void *va; -+ char buf[100]; -+ int len; -+ -+ va = rproc_da_to_va(data->rproc, trace->da, trace->len); -+ -+ if (!va) { -+ len = scnprintf(buf, sizeof(buf), "Trace %s not available\n", -+ trace->name); -+ va = buf; -+ } else { -+ len = strnlen(va, trace->len); -+ } - -- return simple_read_from_buffer(userbuf, count, ppos, trace->va, len); -+ return simple_read_from_buffer(userbuf, count, ppos, va, len); - } - - static const struct file_operations trace_rproc_ops = { -@@ -260,6 +273,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p) - - list_for_each_entry(carveout, &rproc->carveouts, node) { - seq_puts(seq, "Carveout memory entry:\n"); -+ seq_printf(seq, "\tName: %s\n", carveout->name); - seq_printf(seq, "\tVirtual address: %pK\n", carveout->va); - seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma); - seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da); -@@ -287,7 +301,7 @@ void rproc_remove_trace_file(struct dentry *tfile) - } - - struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, -- struct rproc_mem_entry *trace) -+ struct rproc_debug_trace *trace) - { - struct dentry *tfile; - -diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h -index 7570beb..b130a3d 100644 ---- a/drivers/remoteproc/remoteproc_internal.h -+++ b/drivers/remoteproc/remoteproc_internal.h -@@ -25,6 +25,13 @@ - - struct rproc; - -+struct rproc_debug_trace { -+ struct rproc *rproc; -+ struct dentry *tfile; -+ struct list_head node; -+ struct rproc_mem_entry trace_mem; -+}; -+ - /* from remoteproc_core.c */ - void rproc_release(struct kref *kref); - irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id); -@@ -37,7 +44,7 @@ void rproc_remove_virtio_dev(struct rproc_vdev *rvdev); - /* from remoteproc_debugfs.c */ - void rproc_remove_trace_file(struct dentry *tfile); - struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, -- struct rproc_mem_entry *trace); -+ struct rproc_debug_trace *trace); - void rproc_delete_debug_dir(struct rproc *rproc); - void rproc_create_debug_dir(struct rproc *rproc); - void rproc_init_debugfs(void); -@@ -52,6 +59,7 @@ void rproc_free_vring(struct rproc_vring *rvring); - int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); - - void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); -+phys_addr_t rproc_va_to_pa(void *cpu_addr); - int rproc_trigger_recovery(struct rproc *rproc); - - int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw); -@@ -60,6 +68,8 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw); - int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw); - struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, - const struct firmware *fw); -+struct rproc_mem_entry * -+rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...); - - static inline - int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) -diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c -index bbecd44..78462f5 100644 ---- a/drivers/remoteproc/remoteproc_virtio.c -+++ b/drivers/remoteproc/remoteproc_virtio.c -@@ -17,7 +17,9 @@ - * GNU General Public License for more details. - */ - -+#include - #include -+#include - #include - #include - #include -@@ -76,7 +78,9 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, - struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); - struct rproc *rproc = vdev_to_rproc(vdev); - struct device *dev = &rproc->dev; -+ struct rproc_mem_entry *mem; - struct rproc_vring *rvring; -+ struct fw_rsc_vdev *rsc; - struct virtqueue *vq; - void *addr; - int len, size; -@@ -88,8 +92,14 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, - if (!name) - return NULL; - -+ /* Search allocated memory region by name */ -+ mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index, -+ id); -+ if (!mem || !mem->va) -+ return ERR_PTR(-ENOMEM); -+ - rvring = &rvdev->vring[id]; -- addr = rvring->va; -+ addr = mem->va; - len = rvring->len; - - /* zero vring */ -@@ -114,6 +124,10 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, - rvring->vq = vq; - vq->priv = rvring; - -+ /* Update vring in resource table */ -+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; -+ rsc->vring[id].da = mem->da; -+ - return vq; - } - -@@ -303,10 +317,50 @@ static void rproc_virtio_dev_release(struct device *dev) - int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) - { - struct rproc *rproc = rvdev->rproc; -- struct device *dev = &rproc->dev; -+ struct device *dev = &rvdev->dev; - struct virtio_device *vdev = &rvdev->vdev; -+ struct rproc_mem_entry *mem; - int ret; - -+ /* Try to find dedicated vdev buffer carveout */ -+ mem = rproc_find_carveout_by_name(rproc, "vdev%dbuffer", rvdev->index); -+ if (mem) { -+ phys_addr_t pa; -+ -+ if (mem->of_resm_idx != -1) { -+ struct device_node *np = rproc->dev.parent->of_node; -+ -+ /* Associate reserved memory to vdev device */ -+ ret = of_reserved_mem_device_init_by_idx(dev, np, -+ mem->of_resm_idx); -+ if (ret) { -+ dev_err(dev, "Can't associate reserved memory\n"); -+ goto out; -+ } -+ } else { -+ if (mem->va) { -+ dev_warn(dev, "vdev %d buffer already mapped\n", -+ rvdev->index); -+ pa = rproc_va_to_pa(mem->va); -+ } else { -+ /* Use dma address as carveout no memmapped yet */ -+ pa = (phys_addr_t)mem->dma; -+ } -+ -+ /* Associate vdev buffer memory pool to vdev subdev */ -+ ret = dmam_declare_coherent_memory(dev, pa, -+ mem->da, -+ mem->len, -+ DMA_MEMORY_EXCLUSIVE); -+ if (ret < 0) { -+ dev_err(dev, "Failed to associate buffer\n"); -+ goto out; -+ } -+ } -+ } -+ -+ /* Reset vdev struct as you don't know how it has been previously allocated */ -+ memset(vdev, 0, sizeof(struct virtio_device)); - vdev->id.device = id, - vdev->config = &rproc_virtio_config_ops, - vdev->dev.parent = dev; -diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c -new file mode 100644 -index 0000000..fc61e8b ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_core.c -@@ -0,0 +1,303 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "rproc_srm_core.h" -+ -+#define BIND_TIMEOUT 10000 -+ -+struct rproc_srm_core { -+ struct device *dev; -+ struct completion all_bound; -+ int bind_status; -+ atomic_t prepared; -+ struct rproc_subdev subdev; -+ struct rpmsg_driver rpdrv; -+ struct blocking_notifier_head notifier; -+}; -+ -+#define to_rproc_srm_core(s) container_of(s, struct rproc_srm_core, subdev) -+ -+static struct rproc_srm_core *rpmsg_srm_to_core(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_driver *rpdrv; -+ struct rproc_srm_core *core; -+ -+ rpdrv = container_of(rpdev->dev.driver, struct rpmsg_driver, drv); -+ core = container_of(rpdrv, struct rproc_srm_core, rpdrv); -+ -+ return core; -+} -+ -+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg) -+{ -+ int ret; -+ -+ ret = rpmsg_send(ept, (void *)msg, sizeof(*msg)); -+ if (ret) -+ dev_err(&ept->rpdev->dev, "rpmsg_send failed: %d\n", ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(rpmsg_srm_send); -+ -+static int rpmsg_srm_cb(struct rpmsg_device *rpdev, void *data, int len, -+ void *priv, u32 src) -+{ -+ struct rproc_srm_core *core = rpmsg_srm_to_core(rpdev); -+ struct rpmsg_srm_msg_desc desc; -+ int ret; -+ -+ desc.ept = rpdev->ept; -+ desc.msg = data; -+ -+ ret = blocking_notifier_call_chain(&core->notifier, 0, &desc); -+ -+ if (!(ret & NOTIFY_STOP_MASK)) { -+ dev_warn(&rpdev->dev, "unknown device\n"); -+ desc.msg->message_type = RPROC_SRM_MSG_ERROR; -+ rpmsg_srm_send(desc.ept, desc.msg); -+ } -+ -+ return 0; -+} -+ -+static int rpmsg_srm_probe(struct rpmsg_device *rpdev) -+{ -+ int ret; -+ -+ dev_dbg(&rpdev->dev, "%s\n", __func__); -+ -+ /* Send an empty message to complete the initialization */ -+ ret = rpmsg_send(rpdev->ept, NULL, 0); -+ if (ret) -+ dev_err(&rpdev->dev, "failed to send init message\n"); -+ -+ return ret; -+} -+ -+static void rpmsg_srm_remove(struct rpmsg_device *rpdev) -+{ -+ /* Note : the remove ops is mandatory */ -+ dev_dbg(&rpdev->dev, "%s\n", __func__); -+} -+ -+static struct rpmsg_device_id rpmsg_srm_id_table[] = { -+ { .name = "rproc-srm" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(rpmsg, rpmsg_srm_id_table); -+ -+static struct rpmsg_driver rpmsg_srm_drv = { -+ .drv.name = "rpmsg_srm", -+ .id_table = rpmsg_srm_id_table, -+ .probe = rpmsg_srm_probe, -+ .callback = rpmsg_srm_cb, -+ .remove = rpmsg_srm_remove, -+}; -+ -+int rproc_srm_core_register_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&core->notifier, nb); -+} -+EXPORT_SYMBOL(rproc_srm_core_register_notifier); -+ -+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&core->notifier, nb); -+} -+EXPORT_SYMBOL(rproc_srm_core_unregister_notifier); -+ -+static int compare_of(struct device *dev, void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static void release_of(struct device *dev, void *data) -+{ -+ of_node_put(data); -+} -+ -+static void rproc_srm_core_unbind(struct device *dev) -+{ -+ component_unbind_all(dev, NULL); -+} -+ -+static int rproc_srm_core_bind(struct device *dev) -+{ -+ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); -+ -+ rproc_srm_core->bind_status = component_bind_all(dev, NULL); -+ complete(&rproc_srm_core->all_bound); -+ -+ return rproc_srm_core->bind_status; -+} -+ -+static const struct component_master_ops srm_comp_ops = { -+ .bind = rproc_srm_core_bind, -+ .unbind = rproc_srm_core_unbind, -+}; -+ -+static int rproc_srm_core_prepare(struct rproc_subdev *subdev) -+{ -+ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); -+ struct device *dev = rproc_srm_core->dev; -+ struct device_node *node = dev->of_node; -+ struct device_node *child_np; -+ struct component_match *match = NULL; -+ int ret; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ init_completion(&rproc_srm_core->all_bound); -+ -+ ret = devm_of_platform_populate(dev); -+ if (ret) { -+ dev_err(dev, "cannot populate node (%d)\n", ret); -+ return ret; -+ } -+ -+ child_np = of_get_next_available_child(node, NULL); -+ -+ while (child_np) { -+ of_node_get(child_np); -+ component_match_add_release(dev, &match, release_of, compare_of, -+ child_np); -+ child_np = of_get_next_available_child(node, child_np); -+ } -+ -+ if (!match) { -+ dev_dbg(dev, "No available child\n"); -+ goto done; -+ } -+ -+ ret = component_master_add_with_match(dev, &srm_comp_ops, match); -+ if (ret) -+ goto depopulate; -+ -+ /* Wait for every child to be bound */ -+ if (!wait_for_completion_timeout(&rproc_srm_core->all_bound, -+ msecs_to_jiffies(BIND_TIMEOUT))) { -+ dev_err(dev, "failed to bind one or more system resource device(s)\n"); -+ ret = -ETIMEDOUT; -+ goto master; -+ } -+ -+ ret = rproc_srm_core->bind_status; -+ if (ret) { -+ dev_err(dev, "failed to bind\n"); -+ goto master; -+ } -+ -+ /* Register rpmsg driver for dynamic management */ -+ rproc_srm_core->rpdrv = rpmsg_srm_drv; -+ ret = register_rpmsg_driver(&rproc_srm_core->rpdrv); -+ if (ret) { -+ dev_err(dev, "failed to register rpmsg drv\n"); -+ goto master; -+ } -+ -+done: -+ atomic_inc(&rproc_srm_core->prepared); -+ -+ return 0; -+ -+master: -+ component_master_del(dev, &srm_comp_ops); -+depopulate: -+ devm_of_platform_depopulate(dev); -+ return ret; -+} -+ -+static void rproc_srm_core_unprepare(struct rproc_subdev *subdev) -+{ -+ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); -+ struct device *dev = rproc_srm_core->dev; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ if (!atomic_read(&rproc_srm_core->prepared)) -+ return; -+ -+ atomic_dec(&rproc_srm_core->prepared); -+ -+ unregister_rpmsg_driver(&rproc_srm_core->rpdrv); -+ -+ component_master_del(dev, &srm_comp_ops); -+ devm_of_platform_depopulate(dev); -+} -+ -+static int rproc_srm_core_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc *rproc = dev_get_drvdata(dev->parent); -+ struct rproc_srm_core *rproc_srm_core; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ rproc_srm_core = devm_kzalloc(dev, sizeof(struct rproc_srm_core), -+ GFP_KERNEL); -+ if (!rproc_srm_core) -+ return -ENOMEM; -+ -+ rproc_srm_core->dev = dev; -+ BLOCKING_INIT_NOTIFIER_HEAD(&rproc_srm_core->notifier); -+ -+ /* Register rproc subdevice with (un)prepare ops */ -+ rproc_srm_core->subdev.prepare = rproc_srm_core_prepare; -+ rproc_srm_core->subdev.unprepare = rproc_srm_core_unprepare; -+ rproc_add_subdev(rproc, &rproc_srm_core->subdev); -+ -+ dev_set_drvdata(dev, rproc_srm_core); -+ -+ return 0; -+} -+ -+static int rproc_srm_core_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); -+ struct rproc *rproc = dev_get_drvdata(dev->parent); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ if (atomic_read(&rproc->power) > 0) -+ dev_warn(dev, "Releasing resources while firmware running!\n"); -+ -+ rproc_srm_core_unprepare(&rproc_srm_core->subdev); -+ -+ return 0; -+} -+ -+static const struct of_device_id rproc_srm_core_match[] = { -+ { .compatible = "rproc-srm-core", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, rproc_srm_core_match); -+ -+static struct platform_driver rproc_srm_core_driver = { -+ .probe = rproc_srm_core_probe, -+ .remove = rproc_srm_core_remove, -+ .driver = { -+ .name = "rproc-srm-core", -+ .of_match_table = of_match_ptr(rproc_srm_core_match), -+ }, -+}; -+ -+module_platform_driver(rproc_srm_core_driver); -+ -+MODULE_AUTHOR("Fabien Dessenne "); -+MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - core"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h -new file mode 100644 -index 0000000..7dffdb38 ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_core.h -@@ -0,0 +1,98 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#ifndef _RPROC_SRM_CORE_H_ -+#define _RPROC_SRM_CORE_H_ -+ -+/** -+ * Message type used in resource manager rpmsg: -+ * RPROC_SRM_MSG_GETCONFIG: Request to get the configuration of a resource -+ * RPROC_SRM_MSG_SETCONFIG: Request to set the configuration of a resource -+ * RPROC_SRM_MSG_ERROR: Error when processing a request -+ */ -+#define RPROC_SRM_MSG_GETCONFIG 0x00 -+#define RPROC_SRM_MSG_SETCONFIG 0x01 -+#define RPROC_SRM_MSG_ERROR 0xFF -+ -+/** -+ * Resource type used in resource manager rpmsg: -+ * RPROC_SRM_RSC_CLOCK: clock resource -+ * RPROC_SRM_RSC_REGU: regulator resource -+ */ -+#define RPROC_SRM_RSC_CLOCK 0x00 -+#define RPROC_SRM_RSC_REGU 0x01 -+ -+/** -+ * struct clock_cfg - clock configuration used in resource manager rpmsg -+ * @index: clock index -+ * @name: clock name -+ * @rate: clock rate request (in SetConfig message) or current status (in -+ * GetConfig message) -+ */ -+struct clock_cfg { -+ u32 index; -+ u8 name[16]; -+ u32 rate; -+}; -+ -+/** -+ * struct regu_cfg - regu configuration used in resource manager rpmsg -+ * @index: regulator index -+ * @name: regulator name -+ * @enable: regulator enable/disable request (in SetConfig message) or -+ * current status (in GetConfig message) -+ * @curr_voltage_mv: current regulator voltage in mV (meaningful in -+ * SetConfig message) -+ * @min_voltage_mv: regulator min voltage request in mV (meaningful in -+ * SetConfig message) -+ * @max_voltage_mv: regulator max voltage request in mV (meaningful in -+ * SetConfig message) -+ */ -+struct regu_cfg { -+ u32 index; -+ u8 name[16]; -+ u32 enable; -+ u32 curr_voltage_mv; -+ u32 min_voltage_mv; -+ u32 max_voltage_mv; -+}; -+ -+/** -+ * struct rpmsg_srm_msg - message structure used between processors to -+ * dynamically update resources configuration -+ * @message_type: type of the message: see RPROC_SRM_MSG* -+ * @device_id: an identifier specifying the device owning the resources. -+ * This is implementation dependent. As example it may be the -+ * device name or the device address. -+ * @rsc_type: the type of the resource for which the configuration applies: -+ * see RPROC_SRM_RSC* -+ * @clock_cfg: clock config - relevant if &rsc_type is RPROC_SRM_RSC_CLOCK -+ * @regu_cfg: regulator config - relevant if &rsc_type is RPROC_SRM_RSC_REGU -+ */ -+struct rpmsg_srm_msg { -+ u32 message_type; -+ u8 device_id[32]; -+ u32 rsc_type; -+ union { -+ struct clock_cfg clock_cfg; -+ struct regu_cfg regu_cfg; -+ }; -+}; -+ -+struct rpmsg_srm_msg_desc { -+ struct rpmsg_endpoint *ept; -+ struct rpmsg_srm_msg *msg; -+}; -+ -+struct rproc_srm_core; -+ -+int rproc_srm_core_register_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb); -+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, -+ struct notifier_block *nb); -+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg); -+ -+#endif -diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c -new file mode 100644 -index 0000000..6b164da ---- /dev/null -+++ b/drivers/remoteproc/rproc_srm_dev.c -@@ -0,0 +1,744 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "rproc_srm_core.h" -+ -+struct rproc_srm_clk_info { -+ struct list_head list; -+ unsigned int index; -+ struct clk *clk; -+ const char *name; -+ bool parent_enabled; -+}; -+ -+struct rproc_srm_regu_info { -+ struct list_head list; -+ unsigned int index; -+ struct regulator *regu; -+ const char *name; -+ bool enabled; -+}; -+ -+struct rproc_srm_irq_info { -+ struct list_head list; -+ unsigned int index; -+ char *name; -+ int irq; -+ bool enabled; -+}; -+ -+struct rproc_srm_dev { -+ struct device *dev; -+ struct rproc_srm_core *core; -+ struct notifier_block nb; -+ bool early_boot; -+ -+ struct list_head clk_list_head; -+ struct list_head regu_list_head; -+ struct list_head irq_list_head; -+}; -+ -+/* Irqs */ -+static void rproc_srm_dev_irqs_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_irq_info *i, *tmp; -+ -+ list_for_each_entry_safe(i, tmp, &rproc_srm_dev->irq_list_head, list) { -+ devm_free_irq(dev, i->irq, NULL); -+ dev_dbg(dev, "Put irq %d (%s)\n", i->irq, i->name); -+ list_del(&i->list); -+ } -+} -+ -+static irqreturn_t rproc_srm_dev_irq_handler(int irq, void *dev) -+{ -+ dev_warn(dev, "Spurious interrupt\n"); -+ return IRQ_HANDLED; -+} -+ -+static int rproc_srm_dev_irqs_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct platform_device *pdev = to_platform_device(dev); -+ struct device_node *np = dev->of_node; -+ struct rproc_srm_irq_info *info; -+ const char *name; -+ int nr, ret, irq; -+ unsigned int i; -+ -+ if (!np) -+ return 0; -+ -+ nr = platform_irq_count(pdev); -+ if (!nr) -+ return 0; -+ -+ if (rproc_srm_dev->early_boot) -+ /* -+ * Do not overwrite the irq configuration. -+ * No need to parse irq from DT since the resource manager does -+ * not offer any service to update the irq config. -+ */ -+ return 0; -+ -+ for (i = 0; i < nr; i++) { -+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); -+ if (!info) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ irq = platform_get_irq(pdev, i); -+ if (irq <= 0) { -+ ret = irq; -+ dev_err(dev, "Failed to get irq (%d)\n", ret); -+ goto err; -+ } -+ -+ info->irq = irq; -+ -+ /* Register a dummy irq handleras not used by Linux */ -+ ret = devm_request_irq(dev, info->irq, -+ rproc_srm_dev_irq_handler, 0, -+ dev_name(dev), NULL); -+ if (ret) { -+ dev_err(dev, "Failed to request irq (%d)\n", ret); -+ goto err; -+ } -+ -+ /* -+ * Disable IRQ. Since it is used by the remote processor we -+ * must not use the 'irq lazy disable' optimization -+ */ -+ irq_set_status_flags(info->irq, IRQ_DISABLE_UNLAZY); -+ disable_irq(info->irq); -+ -+ /* Note: "interrupt-names" is optional */ -+ if (!of_property_read_string_index(np, "interrupt-names", i, -+ &name)) -+ info->name = devm_kstrdup(dev, name, GFP_KERNEL); -+ else -+ info->name = devm_kstrdup(dev, "", GFP_KERNEL); -+ -+ info->index = i; -+ -+ list_add_tail(&info->list, &rproc_srm_dev->irq_list_head); -+ dev_dbg(dev, "Got irq %d (%s)\n", info->irq, info->name); -+ } -+ -+ return 0; -+ -+err: -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ -+ return ret; -+} -+ -+/* Clocks */ -+static void rproc_srm_dev_clocks_unsetup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_clk_info *c; -+ -+ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { -+ if (!c->parent_enabled) -+ continue; -+ -+ clk_disable_unprepare(clk_get_parent(c->clk)); -+ c->parent_enabled = false; -+ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) unsetup\n", -+ c->index, c->name); -+ } -+} -+ -+static int rproc_srm_dev_clocks_setup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_clk_info *c; -+ int ret; -+ -+ /* -+ * Prepare and enable the parent clocks. -+ * Since the clock tree is under the exclusive control of the master -+ * processor, we need to configure the clock tree of the targeted clock. -+ * We do not want to enable the clock itself, which is under the -+ * responsibility of the remote processor. -+ * Hence we prepare and enable the parent clock. -+ */ -+ -+ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { -+ if (c->parent_enabled) -+ continue; -+ -+ ret = clk_prepare_enable(clk_get_parent(c->clk)); -+ if (ret) { -+ dev_err(rproc_srm_dev->dev, -+ "clk %d (%s) parent enable failed\n", -+ c->index, c->name); -+ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); -+ return ret; -+ } -+ c->parent_enabled = true; -+ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) parent enabled\n", -+ c->index, c->name); -+ } -+ -+ return 0; -+} -+ -+static struct rproc_srm_clk_info -+ *rproc_srm_dev_clock_find(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *ci; -+ -+ /* Search by index (if valid value) otherwise search by name */ -+ list_for_each_entry(ci, &rproc_srm_dev->clk_list_head, list) { -+ if (cfg->index != U32_MAX) { -+ if (ci->index == cfg->index) -+ return ci; -+ } else { -+ if (!strcmp(ci->name, cfg->name)) -+ return ci; -+ } -+ } -+ -+ return NULL; -+} -+ -+static int rproc_srm_dev_clock_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *c; -+ struct device *dev = rproc_srm_dev->dev; -+ int ret; -+ -+ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); -+ -+ if (!c) { -+ dev_err(dev, "unknown clock (id %d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ if (cfg->rate && clk_get_rate(c->clk) != cfg->rate) { -+ ret = clk_set_rate(c->clk, cfg->rate); -+ if (ret) { -+ dev_err(dev, "clk set rate failed\n"); -+ return ret; -+ } -+ -+ dev_dbg(dev, "clk %d (%s) rate = %d\n", c->index, c->name, -+ cfg->rate); -+ } -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_clock_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct clock_cfg *cfg) -+{ -+ struct rproc_srm_clk_info *c; -+ -+ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); -+ if (!c) { -+ dev_err(rproc_srm_dev->dev, "unknown clock (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ strlcpy(cfg->name, c->name, sizeof(cfg->name)); -+ cfg->index = c->index; -+ cfg->rate = (u32)clk_get_rate(c->clk); -+ -+ return 0; -+} -+ -+static void rproc_srm_dev_clocks_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_clk_info *c, *tmp; -+ -+ list_for_each_entry_safe(c, tmp, &rproc_srm_dev->clk_list_head, list) { -+ clk_put(c->clk); -+ dev_dbg(dev, "put clock %d (%s)\n", c->index, c->name); -+ list_del(&c->list); -+ } -+} -+ -+static int rproc_srm_dev_clocks_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct device_node *np = dev->of_node; -+ struct rproc_srm_clk_info *c; -+ const char *name; -+ int nb_c, ret; -+ unsigned int i; -+ -+ if (!np) -+ return 0; -+ -+ nb_c = of_clk_get_parent_count(np); -+ if (!nb_c) -+ return 0; -+ -+ for (i = 0; i < nb_c; i++) { -+ c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); -+ if (!c) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ c->clk = of_clk_get(np, i); -+ if (IS_ERR(c->clk)) { -+ dev_err(dev, "clock %d KO (%ld)\n", i, -+ PTR_ERR(c->clk)); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ /* Note: "clock-names" is optional */ -+ if (!of_property_read_string_index(np, "clock-names", i, -+ &name)) -+ c->name = devm_kstrdup(dev, name, GFP_KERNEL); -+ else -+ c->name = devm_kstrdup(dev, "", GFP_KERNEL); -+ -+ c->index = i; -+ -+ list_add_tail(&c->list, &rproc_srm_dev->clk_list_head); -+ dev_dbg(dev, "got clock %d (%s)\n", c->index, c->name); -+ } -+ -+ return 0; -+ -+err: -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ return ret; -+} -+ -+/* Regulators */ -+static void rproc_srm_dev_regus_unsetup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ -+ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { -+ if (!r->enabled) -+ continue; -+ -+ if (regulator_disable(r->regu)) { -+ dev_warn(dev, "regu %d disabled failed\n", r->index); -+ continue; -+ } -+ -+ r->enabled = false; -+ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); -+ } -+} -+ -+static int rproc_srm_dev_regus_setup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_regu_info *r; -+ int ret; -+ -+ /* Enable all the regulators */ -+ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { -+ if (r->enabled) -+ continue; -+ -+ /* in early_boot mode sync on hw */ -+ if (rproc_srm_dev->early_boot && !regulator_is_enabled(r->regu)) -+ continue; -+ -+ ret = regulator_enable(r->regu); -+ if (ret) { -+ dev_err(rproc_srm_dev->dev, "regu %d (%s) failed\n", -+ r->index, r->name); -+ rproc_srm_dev_regus_unsetup(rproc_srm_dev); -+ return ret; -+ } -+ r->enabled = true; -+ dev_dbg(rproc_srm_dev->dev, "regu %d (%s) enabled\n", -+ r->index, r->name); -+ } -+ -+ return 0; -+} -+ -+static struct rproc_srm_regu_info -+ *rproc_srm_dev_regu_find(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *ri; -+ -+ list_for_each_entry(ri, &rproc_srm_dev->regu_list_head, list) { -+ if (cfg->index != U32_MAX) { -+ if (ri->index == cfg->index) -+ return ri; -+ } else { -+ if (!strcmp(ri->name, cfg->name)) -+ return ri; -+ } -+ } -+ -+ return NULL; -+} -+ -+static int rproc_srm_dev_regu_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ int ret; -+ -+ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); -+ if (!r) { -+ dev_err(dev, "unknown regu (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ if (!r->enabled && cfg->enable) { -+ ret = regulator_enable(r->regu); -+ if (ret) { -+ dev_err(dev, "regu %d enable failed\n", r->index); -+ return ret; -+ } -+ r->enabled = true; -+ dev_dbg(dev, "regu %d (%s) enabled\n", r->index, r->name); -+ } else if (r->enabled && !cfg->enable) { -+ ret = regulator_disable(r->regu); -+ if (ret) { -+ dev_err(dev, "regu %d disable failed\n", r->index); -+ return ret; -+ } -+ r->enabled = false; -+ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); -+ } -+ -+ if (cfg->min_voltage_mv || cfg->max_voltage_mv) { -+ ret = regulator_set_voltage(r->regu, cfg->min_voltage_mv * 1000, -+ cfg->max_voltage_mv * 1000); -+ if (ret) { -+ dev_err(dev, "regu %d set voltage failed\n", r->index); -+ return ret; -+ } -+ -+ dev_dbg(dev, "regu %d (%s) voltage = [%d - %d] mv\n", r->index, -+ r->name, cfg->min_voltage_mv, cfg->max_voltage_mv); -+ } -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_regu_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct regu_cfg *cfg) -+{ -+ struct rproc_srm_regu_info *r; -+ struct device *dev = rproc_srm_dev->dev; -+ int v; -+ -+ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); -+ if (!r) { -+ dev_err(dev, "unknown regu (%d)\n", cfg->index); -+ return -EINVAL; -+ } -+ -+ strlcpy(cfg->name, r->name, sizeof(cfg->name)); -+ cfg->index = r->index; -+ cfg->enable = r->enabled; -+ cfg->min_voltage_mv = 0; -+ cfg->max_voltage_mv = 0; -+ -+ v = regulator_get_voltage(r->regu); -+ if (v < 0) { -+ dev_warn(dev, "cannot get %s voltage\n", r->name); -+ cfg->curr_voltage_mv = 0; -+ } else { -+ cfg->curr_voltage_mv = v / 1000; -+ } -+ -+ return 0; -+} -+ -+static void rproc_srm_dev_regus_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_regu_info *r, *tmp; -+ -+ list_for_each_entry_safe(r, tmp, &rproc_srm_dev->regu_list_head, list) { -+ devm_regulator_put(r->regu); -+ dev_dbg(dev, "put regu %d (%s)\n", r->index, r->name); -+ list_del(&r->list); -+ } -+} -+ -+static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct device_node *np = dev->of_node; -+ struct property *p; -+ const char *n; -+ char *name; -+ struct rproc_srm_regu_info *r; -+ int ret, nb_s = 0; -+ -+ if (!np) -+ return 0; -+ -+ for_each_property_of_node(np, p) { -+ n = strstr(p->name, "-supply"); -+ if (!n || n == p->name) -+ continue; -+ -+ r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); -+ if (!r) { -+ ret = -ENOMEM; -+ goto err_list; -+ } -+ -+ name = devm_kstrdup(dev, p->name, GFP_KERNEL); -+ name[strlen(p->name) - strlen("-supply")] = '\0'; -+ r->name = name; -+ -+ r->regu = devm_regulator_get(dev, r->name); -+ if (IS_ERR(r->regu)) { -+ dev_err(dev, "cannot get regu %s\n", r->name); -+ ret = -EINVAL; -+ goto err_list; -+ } -+ -+ r->index = nb_s++; -+ -+ list_add_tail(&r->list, &rproc_srm_dev->regu_list_head); -+ dev_dbg(dev, "got regu %d (%s)\n", r->index, r->name); -+ } -+ -+ return 0; -+ -+err_list: -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ return ret; -+} -+ -+/* Core */ -+static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, -+ void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = -+ container_of(nb, struct rproc_srm_dev, nb); -+ struct device *dev = rproc_srm_dev->dev; -+ struct rpmsg_srm_msg_desc *desc; -+ struct rpmsg_srm_msg *i, o; -+ int ret = 0; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ desc = (struct rpmsg_srm_msg_desc *)data; -+ i = desc->msg; -+ o = *i; -+ -+ /* Check if 'device_id' (name / addr ) matches this device */ -+ if (!strstr(dev_name(dev), i->device_id)) -+ return NOTIFY_DONE; -+ -+ switch (i->message_type) { -+ case RPROC_SRM_MSG_SETCONFIG: -+ switch (i->rsc_type) { -+ case RPROC_SRM_RSC_CLOCK: -+ ret = rproc_srm_dev_clock_set_cfg(rproc_srm_dev, -+ &i->clock_cfg); -+ if (!ret) -+ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, -+ &o.clock_cfg); -+ break; -+ case RPROC_SRM_RSC_REGU: -+ ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev, -+ &i->regu_cfg); -+ if (!ret) -+ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, -+ &o.regu_cfg); -+ break; -+ default: -+ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); -+ ret = -EINVAL; -+ break; -+ } -+ break; -+ case RPROC_SRM_MSG_GETCONFIG: -+ switch (i->rsc_type) { -+ case RPROC_SRM_RSC_CLOCK: -+ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, -+ &o.clock_cfg); -+ break; -+ case RPROC_SRM_RSC_REGU: -+ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, -+ &o.regu_cfg); -+ break; -+ default: -+ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); -+ ret = -EINVAL; -+ break; -+ } -+ break; -+ default: -+ dev_warn(dev, "bad msg type (%d)\n", i->message_type); -+ ret = -EINVAL; -+ break; -+ } -+ -+ /* Send return msg */ -+ if (ret) -+ o.message_type = RPROC_SRM_MSG_ERROR; -+ -+ ret = rpmsg_srm_send(desc->ept, &o); -+ -+ return ret ? NOTIFY_BAD : NOTIFY_STOP; -+} -+ -+static void -+rproc_srm_dev_unbind(struct device *dev, struct device *master, void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ rproc_srm_dev_regus_unsetup(rproc_srm_dev); -+ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); -+ -+ /* For IRQs: nothing to unsetup */ -+} -+ -+static int -+rproc_srm_dev_bind(struct device *dev, struct device *master, void *data) -+{ -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ int ret; -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ ret = rproc_srm_dev_clocks_setup(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ ret = rproc_srm_dev_regus_setup(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ /* For IRQs: nothing to setup */ -+ return 0; -+} -+ -+static const struct component_ops rproc_srm_dev_ops = { -+ .bind = rproc_srm_dev_bind, -+ .unbind = rproc_srm_dev_unbind, -+}; -+ -+static int rproc_srm_dev_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_dev *rproc_srm_dev; -+ struct rproc *rproc; -+ int ret; -+ -+ dev_dbg(dev, "%s for node %s\n", __func__, dev->of_node->name); -+ -+ rproc_srm_dev = devm_kzalloc(dev, sizeof(struct rproc_srm_dev), -+ GFP_KERNEL); -+ if (!rproc_srm_dev) -+ return -ENOMEM; -+ -+ rproc_srm_dev->dev = dev; -+ rproc = (struct rproc *)dev_get_drvdata(dev->parent->parent); -+ rproc_srm_dev->early_boot = rproc->early_boot; -+ rproc_srm_dev->core = dev_get_drvdata(dev->parent); -+ -+ INIT_LIST_HEAD(&rproc_srm_dev->clk_list_head); -+ INIT_LIST_HEAD(&rproc_srm_dev->regu_list_head); -+ INIT_LIST_HEAD(&rproc_srm_dev->irq_list_head); -+ -+ /* Get clocks, regu and irqs */ -+ ret = rproc_srm_dev_clocks_get(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ ret = rproc_srm_dev_regus_get(rproc_srm_dev); -+ if (ret) -+ goto err_get; -+ -+ ret = rproc_srm_dev_irqs_get(rproc_srm_dev); -+ if (ret) -+ goto err_get; -+ -+ rproc_srm_dev->nb.notifier_call = rproc_srm_dev_notify_cb; -+ ret = rproc_srm_core_register_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+ if (ret) -+ goto err_register; -+ -+ dev_set_drvdata(dev, rproc_srm_dev); -+ -+ return component_add(dev, &rproc_srm_dev_ops); -+ -+err_register: -+ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+err_get: -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ return ret; -+} -+ -+static int rproc_srm_dev_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); -+ -+ dev_dbg(dev, "%s\n", __func__); -+ -+ component_del(dev, &rproc_srm_dev_ops); -+ -+ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, -+ &rproc_srm_dev->nb); -+ -+ rproc_srm_dev_irqs_put(rproc_srm_dev); -+ rproc_srm_dev_regus_put(rproc_srm_dev); -+ rproc_srm_dev_clocks_put(rproc_srm_dev); -+ -+ return 0; -+} -+ -+static const struct of_device_id rproc_srm_dev_match[] = { -+ { .compatible = "rproc-srm-dev", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, rproc_srm_dev_match); -+ -+static struct platform_driver rproc_srm_dev_driver = { -+ .probe = rproc_srm_dev_probe, -+ .remove = rproc_srm_dev_remove, -+ .driver = { -+ .name = "rproc-srm-dev", -+ .of_match_table = of_match_ptr(rproc_srm_dev_match), -+ }, -+}; -+ -+module_platform_driver(rproc_srm_dev_driver); -+ -+MODULE_AUTHOR("Fabien Dessenne "); -+MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - dev"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -new file mode 100644 -index 0000000..21a569a ---- /dev/null -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -0,0 +1,858 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Authors: Ludovic Barre for STMicroelectronics. -+ * Fabien Dessenne for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "remoteproc_internal.h" -+ -+#define HOLD_BOOT 0 -+#define RELEASE_BOOT 1 -+ -+#define MBOX_NB_VQ 2 -+#define MBOX_NB_MBX 3 -+ -+#define STM32_SMC_RCC 0x82001000 -+#define STM32_SMC_REG_WRITE 0x1 -+ -+#define STM32_MBX_VQ0 "vq0" -+#define STM32_MBX_VQ0_ID 0 -+#define STM32_MBX_VQ1 "vq1" -+#define STM32_MBX_VQ1_ID 1 -+#define STM32_MBX_SHUTDOWN "shutdown" -+ -+#define RSC_TBL_SIZE (1024) -+ -+struct stm32_syscon { -+ struct regmap *map; -+ u32 reg; -+ u32 mask; -+}; -+ -+struct stm32_rproc_mem { -+ char name[20]; -+ void __iomem *cpu_addr; -+ phys_addr_t bus_addr; -+ u32 dev_addr; -+ size_t size; -+}; -+ -+struct stm32_rproc_mem_ranges { -+ u32 dev_addr; -+ u32 bus_addr; -+ u32 size; -+}; -+ -+struct stm32_mbox { -+ const unsigned char name[10]; -+ struct mbox_chan *chan; -+ struct mbox_client client; -+ struct work_struct vq_work; -+ int vq_id; -+}; -+ -+struct stm32_rproc { -+ struct reset_control *rst; -+ struct stm32_syscon hold_boot; -+ struct stm32_syscon pdds; -+ int wdg_irq; -+ u32 nb_rmems; -+ struct stm32_rproc_mem *rmems; -+ struct stm32_mbox mb[MBOX_NB_MBX]; -+ struct workqueue_struct *workqueue; -+ bool secured_soc; -+ void __iomem *rsc_va; -+}; -+ -+static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) -+{ -+ unsigned int i; -+ struct stm32_rproc *ddata = rproc->priv; -+ struct stm32_rproc_mem *p_mem; -+ -+ for (i = 0; i < ddata->nb_rmems; i++) { -+ p_mem = &ddata->rmems[i]; -+ -+ if (pa < p_mem->bus_addr || -+ pa >= p_mem->bus_addr + p_mem->size) -+ continue; -+ *da = pa - p_mem->bus_addr + p_mem->dev_addr; -+ dev_dbg(rproc->dev.parent, "pa %#x to da %llx\n", pa, *da); -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static int stm32_rproc_da_to_pa(struct rproc *rproc, u64 da, phys_addr_t *pa) -+{ -+ unsigned int i; -+ struct stm32_rproc *ddata = rproc->priv; -+ struct stm32_rproc_mem *p_mem; -+ -+ for (i = 0; i < ddata->nb_rmems; i++) { -+ p_mem = &ddata->rmems[i]; -+ -+ if (da < p_mem->dev_addr || -+ da >= p_mem->dev_addr + p_mem->size) -+ continue; -+ *pa = da - p_mem->dev_addr + p_mem->bus_addr; -+ dev_dbg(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa); -+ return 0; -+ } -+ -+ dev_err(rproc->dev.parent, "can't translate da %llx\n", da); -+ -+ return -EINVAL; -+} -+ -+static int stm32_rproc_mem_alloc(struct rproc *rproc, -+ struct rproc_mem_entry *mem) -+{ -+ struct device *dev = rproc->dev.parent; -+ void *va; -+ -+ dev_dbg(dev, "map memory: %pa+%zx\n", &mem->dma, mem->len); -+ va = ioremap_wc(mem->dma, mem->len); -+ if (IS_ERR_OR_NULL(va)) { -+ dev_err(dev, "Unable to map memory region: %pa+%zx\n", -+ &mem->dma, mem->len); -+ return -ENOMEM; -+ } -+ -+ /* Update memory entry va */ -+ mem->va = va; -+ -+ return 0; -+} -+ -+static int stm32_rproc_mem_release(struct rproc *rproc, -+ struct rproc_mem_entry *mem) -+{ -+ dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma); -+ iounmap(mem->va); -+ -+ return 0; -+} -+ -+static int stm32_rproc_elf_load_segments(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ if (!rproc->early_boot) -+ return rproc_elf_load_segments(rproc, fw); -+ -+ return 0; -+} -+ -+static int stm32_rproc_of_memory_translations(struct rproc *rproc) -+{ -+ struct device *dev = rproc->dev.parent; -+ struct stm32_rproc *ddata = rproc->priv; -+ struct device_node *np = dev->of_node; -+ struct stm32_rproc_mem *p_mems; -+ struct stm32_rproc_mem_ranges *mem_range; -+ int cnt, array_size, i, ret = 0; -+ -+ cnt = of_property_count_elems_of_size(np, "ranges", -+ sizeof(*mem_range)); -+ if (cnt <= 0) { -+ dev_err(dev, "%s: ranges property not defined\n", __func__); -+ return -EINVAL; -+ } -+ -+ p_mems = devm_kcalloc(dev, cnt, sizeof(*p_mems), GFP_KERNEL); -+ if (!p_mems) -+ return -ENOMEM; -+ mem_range = kcalloc(cnt, sizeof(*mem_range), GFP_KERNEL); -+ if (!mem_range) -+ return -ENOMEM; -+ -+ array_size = cnt * sizeof(struct stm32_rproc_mem_ranges) / sizeof(u32); -+ -+ ret = of_property_read_u32_array(np, "ranges", -+ (u32 *)mem_range, array_size); -+ if (ret) { -+ dev_err(dev, "error while get ranges property: %x\n", ret); -+ goto free_mem; -+ } -+ -+ for (i = 0; i < cnt; i++) { -+ p_mems[i].bus_addr = mem_range[i].bus_addr; -+ p_mems[i].dev_addr = mem_range[i].dev_addr; -+ p_mems[i].size = mem_range[i].size; -+ -+ dev_dbg(dev, "memory range[%i]: da %#x, pa %#x, size %#x:\n", -+ i, p_mems[i].dev_addr, p_mems[i].bus_addr, -+ p_mems[i].size); -+ } -+ -+ ddata->rmems = p_mems; -+ ddata->nb_rmems = cnt; -+ -+free_mem: -+ kfree(mem_range); -+ return ret; -+} -+ -+static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) { -+ if (!strncmp(ddata->mb[i].name, name, strlen(name))) -+ return i; -+ } -+ dev_err(&rproc->dev, "mailbox %s not found\n", name); -+ -+ return -EINVAL; -+} -+ -+static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ int status; -+ struct resource_table *table = NULL; -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ if (!rproc->early_boot) { -+ status = rproc_elf_load_rsc_table(rproc, fw); -+ if (status) -+ goto no_rsc_table; -+ -+ return 0; -+ } -+ -+ if (ddata->rsc_va) { -+ table = (struct resource_table *)ddata->rsc_va; -+ /* Assuming that the resource table fits in 1kB is fair */ -+ rproc->cached_table = kmemdup(table, RSC_TBL_SIZE, GFP_KERNEL); -+ if (!rproc->cached_table) -+ return -ENOMEM; -+ -+ rproc->table_ptr = rproc->cached_table; -+ rproc->table_sz = RSC_TBL_SIZE; -+ return 0; -+ } -+ -+ rproc->cached_table = NULL; -+ rproc->table_ptr = NULL; -+ rproc->table_sz = 0; -+ -+no_rsc_table: -+ dev_warn(&rproc->dev, "no resource table found for this firmware\n"); -+ return 0; -+} -+ -+static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) -+{ -+ struct device *dev = rproc->dev.parent; -+ struct device_node *np = dev->of_node; -+ struct of_phandle_iterator it; -+ struct rproc_mem_entry *mem; -+ struct reserved_mem *rmem; -+ u64 da; -+ int index = 0; -+ -+ /* Register associated reserved memory regions */ -+ of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); -+ while (of_phandle_iterator_next(&it) == 0) { -+ rmem = of_reserved_mem_lookup(it.node); -+ if (!rmem) { -+ dev_err(dev, "unable to acquire memory-region\n"); -+ return -EINVAL; -+ } -+ -+ if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) { -+ dev_err(dev, "memory region not valid %pa\n", -+ &rmem->base); -+ return -EINVAL; -+ } -+ -+ /* No need to map vdev buffer */ -+ if (strcmp(it.node->name, "vdev0buffer")) { -+ /* Register memory region */ -+ mem = rproc_mem_entry_init(dev, NULL, -+ (dma_addr_t)rmem->base, -+ rmem->size, da, -+ stm32_rproc_mem_alloc, -+ stm32_rproc_mem_release, -+ it.node->name); -+ -+ if (mem) -+ rproc_coredump_add_segment(rproc, da, -+ rmem->size); -+ } else { -+ /* Register reserved memory for vdev buffer alloc */ -+ mem = rproc_of_resm_mem_entry_init(dev, index, -+ rmem->size, -+ rmem->base, -+ it.node->name); -+ } -+ -+ if (!mem) -+ return -ENOMEM; -+ -+ rproc_add_carveout(rproc, mem); -+ index++; -+ } -+ -+ return stm32_rproc_elf_load_rsc_table(rproc, fw); -+} -+ -+static struct resource_table * -+stm32_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ if (!rproc->early_boot) -+ return rproc_elf_find_loaded_rsc_table(rproc, fw); -+ -+ return (struct resource_table *)ddata->rsc_va; -+} -+ -+static int stm32_rproc_elf_sanity_check(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ if (!rproc->early_boot) -+ return rproc_elf_sanity_check(rproc, fw); -+ -+ return 0; -+} -+ -+static u32 stm32_rproc_elf_get_boot_addr(struct rproc *rproc, -+ const struct firmware *fw) -+{ -+ if (!rproc->early_boot) -+ return rproc_elf_get_boot_addr(rproc, fw); -+ -+ return 0; -+} -+ -+static irqreturn_t stm32_rproc_wdg(int irq, void *data) -+{ -+ struct rproc *rproc = data; -+ -+ rproc_report_crash(rproc, RPROC_WATCHDOG); -+ -+ return IRQ_HANDLED; -+} -+ -+static void stm32_rproc_mb_vq_work(struct work_struct *work) -+{ -+ struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work); -+ struct rproc *rproc = dev_get_drvdata(mb->client.dev); -+ -+ if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) -+ dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); -+} -+ -+static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data) -+{ -+ struct rproc *rproc = dev_get_drvdata(cl->dev); -+ struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client); -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ queue_work(ddata->workqueue, &mb->vq_work); -+} -+ -+static void stm32_rproc_free_mbox(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) { -+ if (ddata->mb[i].chan) -+ mbox_free_channel(ddata->mb[i].chan); -+ ddata->mb[i].chan = NULL; -+ } -+} -+ -+static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { -+ { -+ .name = STM32_MBX_VQ0, -+ .vq_id = STM32_MBX_VQ0_ID, -+ .client = { -+ .rx_callback = stm32_rproc_mb_callback, -+ .tx_block = false, -+ }, -+ }, -+ { -+ .name = STM32_MBX_VQ1, -+ .vq_id = STM32_MBX_VQ1_ID, -+ .client = { -+ .rx_callback = stm32_rproc_mb_callback, -+ .tx_block = false, -+ }, -+ }, -+ { -+ .name = STM32_MBX_SHUTDOWN, -+ .vq_id = -1, -+ .client = { -+ .tx_block = true, -+ .tx_done = NULL, -+ .tx_tout = 500, /* 500 ms time out */ -+ }, -+ } -+}; -+ -+static int stm32_rproc_request_mbox(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ struct device *dev = &rproc->dev; -+ unsigned int i; -+ const unsigned char *name; -+ struct mbox_client *cl; -+ -+ /* Initialise mailbox structure table */ -+ memcpy(ddata->mb, stm32_rproc_mbox, sizeof(stm32_rproc_mbox)); -+ -+ for (i = 0; i < MBOX_NB_MBX; i++) { -+ name = ddata->mb[i].name; -+ -+ cl = &ddata->mb[i].client; -+ cl->dev = dev->parent; -+ -+ ddata->mb[i].chan = mbox_request_channel_byname(cl, name); -+ if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) { -+ return -EPROBE_DEFER; -+ } else if (IS_ERR(ddata->mb[i].chan)) { -+ dev_warn(dev, "cannot get %s mbox\n", name); -+ ddata->mb[i].chan = NULL; -+ } -+ if (ddata->mb[i].vq_id >= 0) { -+ INIT_WORK(&ddata->mb[i].vq_work, -+ stm32_rproc_mb_vq_work); -+ } -+ } -+ -+ return 0; -+} -+ -+static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ struct stm32_syscon hold_boot = ddata->hold_boot; -+ struct arm_smccc_res smc_res; -+ int val, err; -+ -+ val = hold ? HOLD_BOOT : RELEASE_BOOT; -+ -+ if (ddata->secured_soc) { -+ arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE, -+ hold_boot.reg, val, 0, 0, 0, 0, &smc_res); -+ err = smc_res.a0; -+ } else { -+ err = regmap_update_bits(hold_boot.map, hold_boot.reg, -+ hold_boot.mask, val); -+ } -+ -+ if (err) -+ dev_err(&rproc->dev, "failed to set hold boot\n"); -+ -+ return err; -+} -+ -+static void stm32_rproc_add_coredump_trace(struct rproc *rproc) -+{ -+ struct rproc_debug_trace *trace; -+ struct rproc_dump_segment *segment; -+ bool already_added; -+ -+ list_for_each_entry(trace, &rproc->traces, node) { -+ already_added = false; -+ -+ list_for_each_entry(segment, &rproc->dump_segments, node) { -+ if (segment->da == trace->trace_mem.da) { -+ already_added = true; -+ break; -+ } -+ } -+ -+ if (!already_added) -+ rproc_coredump_add_segment(rproc, trace->trace_mem.da, -+ trace->trace_mem.len); -+ } -+} -+ -+static int stm32_rproc_start(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ int err; -+ -+ stm32_rproc_add_coredump_trace(rproc); -+ -+ /* clear remote proc Deep Sleep */ -+ if (ddata->pdds.map && !rproc->early_boot) { -+ err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, -+ ddata->pdds.mask, 0); -+ if (err) { -+ dev_err(&rproc->dev, "failed to clear pdds\n"); -+ return err; -+ } -+ } -+ -+ /* -+ * If M4 previously started by bootloader, just guarantee holdboot -+ * is set to catch any crash. -+ */ -+ if (!rproc->early_boot) { -+ err = stm32_rproc_set_hold_boot(rproc, false); -+ if (err) -+ return err; -+ } -+ -+ return stm32_rproc_set_hold_boot(rproc, true); -+} -+ -+static int stm32_rproc_stop(struct rproc *rproc) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ int err, dummy_data, idx; -+ -+ /* request shutdown of the remote processor */ -+ if (rproc->state != RPROC_OFFLINE) { -+ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); -+ if (idx >= 0 && ddata->mb[idx].chan) { -+ /* a dummy data is sent to allow to block on transmit */ -+ err = mbox_send_message(ddata->mb[idx].chan, -+ &dummy_data); -+ if (err < 0) -+ dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); -+ } -+ } -+ -+ err = stm32_rproc_set_hold_boot(rproc, true); -+ if (err) -+ return err; -+ -+ err = reset_control_assert(ddata->rst); -+ if (err) { -+ dev_err(&rproc->dev, "failed to assert the reset\n"); -+ return err; -+ } -+ -+ /* to allow platform Standby power mode, set remote proc Deep Sleep */ -+ if (ddata->pdds.map) { -+ err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, -+ ddata->pdds.mask, 1); -+ if (err) { -+ dev_err(&rproc->dev, "failed to set pdds\n"); -+ return err; -+ } -+ } -+ -+ /* Reset early_boot state as we stop the co-processor */ -+ rproc->early_boot = false; -+ -+ return 0; -+} -+ -+static void stm32_rproc_kick(struct rproc *rproc, int vqid) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ unsigned int i; -+ int err; -+ -+ if (WARN_ON(vqid >= MBOX_NB_VQ)) -+ return; -+ -+ for (i = 0; i < MBOX_NB_MBX; i++) { -+ if (vqid != ddata->mb[i].vq_id) -+ continue; -+ if (!ddata->mb[i].chan) -+ return; -+ err = mbox_send_message(ddata->mb[i].chan, (void *)vqid); -+ if (err < 0) -+ dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n", -+ __func__, ddata->mb[i].name, err); -+ return; -+ } -+} -+ -+static struct rproc_ops st_rproc_ops = { -+ .start = stm32_rproc_start, -+ .stop = stm32_rproc_stop, -+ .kick = stm32_rproc_kick, -+ .load = stm32_rproc_elf_load_segments, -+ .parse_fw = stm32_rproc_parse_fw, -+ .find_loaded_rsc_table = stm32_rproc_elf_find_loaded_rsc_table, -+ .sanity_check = stm32_rproc_elf_sanity_check, -+ .get_boot_addr = stm32_rproc_elf_get_boot_addr, -+}; -+ -+static const struct of_device_id stm32_rproc_match[] = { -+ { .compatible = "st,stm32mp1-rproc" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, stm32_rproc_match); -+ -+static int stm32_rproc_get_syscon(struct device_node *np, const char *prop, -+ struct stm32_syscon *syscon) -+{ -+ int err = 0; -+ -+ syscon->map = syscon_regmap_lookup_by_phandle(np, prop); -+ if (IS_ERR(syscon->map)) { -+ err = PTR_ERR(syscon->map); -+ syscon->map = NULL; -+ goto out; -+ } -+ -+ err = of_property_read_u32_index(np, prop, 1, &syscon->reg); -+ if (err) -+ goto out; -+ -+ err = of_property_read_u32_index(np, prop, 2, &syscon->mask); -+ -+out: -+ return err; -+} -+ -+static int stm32_rproc_parse_dt(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct rproc *rproc = platform_get_drvdata(pdev); -+ struct stm32_rproc *ddata = rproc->priv; -+ struct stm32_syscon tz, rsctbl; -+ phys_addr_t rsc_pa; -+ u32 rsc_da; -+ unsigned int tzen; -+ int err, irq; -+ -+ irq = platform_get_irq_byname(pdev, "wdg"); -+ if (irq == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ if (irq > 0) { -+ err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0, -+ dev_name(dev), rproc); -+ if (err) { -+ dev_err(dev, "failed to request wdg irq\n"); -+ return err; -+ } -+ -+ ddata->wdg_irq = irq; -+ -+ if (of_property_read_bool(np, "wakeup-source")) { -+ device_init_wakeup(dev, true); -+ dev_pm_set_wake_irq(dev, irq); -+ } -+ -+ dev_info(dev, "wdg irq registered\n"); -+ } -+ -+ ddata->rst = devm_reset_control_get(dev, "mcu_rst"); -+ if (IS_ERR(ddata->rst)) { -+ dev_err(dev, "failed to get mcu reset\n"); -+ return PTR_ERR(ddata->rst); -+ } -+ -+ /* -+ * if platform is secured the hold boot bit must be written by -+ * smc call and read normally. -+ * if not secure the hold boot bit could be read/write normally -+ */ -+ err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); -+ if (err) { -+ dev_err(dev, "failed to get tz syscfg\n"); -+ return err; -+ } -+ -+ err = regmap_read(tz.map, tz.reg, &tzen); -+ if (err) { -+ dev_err(&rproc->dev, "failed to read tzen\n"); -+ return err; -+ } -+ ddata->secured_soc = tzen & tz.mask; -+ -+ err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", -+ &ddata->hold_boot); -+ if (err) { -+ dev_err(dev, "failed to get hold boot\n"); -+ return err; -+ } -+ -+ err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); -+ if (err) -+ dev_warn(dev, "pdds not supported\n"); -+ -+ -+ rproc->auto_boot = of_property_read_bool(np, "auto_boot"); -+ rproc->recovery_disabled = !of_property_read_bool(np, "recovery"); -+ -+ err = stm32_rproc_of_memory_translations(rproc); -+ if (err) -+ return err; -+ -+ if (of_property_read_bool(np, "early-booted")) { -+ rproc->early_boot = true; -+ -+ if (stm32_rproc_get_syscon(np, "st,syscfg-rsc-tbl", &rsctbl)) { -+ /* no rsc table syscon (optional) */ -+ dev_warn(dev, "rsc tbl syscon not supported\n"); -+ goto bail; -+ } -+ -+ err = regmap_read(rsctbl.map, rsctbl.reg, &rsc_da); -+ if (err) { -+ dev_err(&rproc->dev, "failed to read rsc tbl addr\n"); -+ return err; -+ } -+ if (!rsc_da) -+ /* no rsc table */ -+ goto bail; -+ -+ err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); -+ if (err) -+ return err; -+ -+ ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); -+ if (IS_ERR_OR_NULL(ddata->rsc_va)) { -+ dev_err(dev, "Unable to map memory region: %pa+%zx\n", -+ &rsc_pa, RSC_TBL_SIZE); -+ ddata->rsc_va = NULL; -+ return -ENOMEM; -+ } -+ } -+bail: -+ return 0; -+} -+ -+static int stm32_rproc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct stm32_rproc *ddata; -+ struct device_node *np = dev->of_node; -+ struct rproc *rproc; -+ int ret; -+ -+ rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); -+ if (!rproc) -+ return -ENOMEM; -+ -+ rproc->has_iommu = false; -+ ddata = rproc->priv; -+ ddata->workqueue = create_workqueue(dev_name(dev)); -+ if (!ddata->workqueue) { -+ dev_err(dev, "cannot create workqueue\n"); -+ ret = -ENOMEM; -+ goto free_rproc; -+ } -+ -+ platform_set_drvdata(pdev, rproc); -+ -+ ret = stm32_rproc_parse_dt(pdev); -+ if (ret) -+ goto free_wkq; -+ -+ if (!rproc->early_boot) { -+ ret = stm32_rproc_stop(rproc); -+ if (ret) -+ goto free_wkq; -+ } -+ -+ ret = stm32_rproc_request_mbox(rproc); -+ if (ret) -+ goto free_wkq; -+ -+ ret = rproc_add(rproc); -+ if (ret) -+ goto free_mb; -+ -+ return 0; -+ -+free_mb: -+ stm32_rproc_free_mbox(rproc); -+free_wkq: -+ destroy_workqueue(ddata->workqueue); -+free_rproc: -+ if (device_may_wakeup(dev)) { -+ dev_pm_clear_wake_irq(dev); -+ device_init_wakeup(dev, false); -+ } -+ rproc_free(rproc); -+ return ret; -+} -+ -+static int stm32_rproc_remove(struct platform_device *pdev) -+{ -+ struct rproc *rproc = platform_get_drvdata(pdev); -+ struct stm32_rproc *ddata = rproc->priv; -+ struct device *dev = &pdev->dev; -+ -+ if (atomic_read(&rproc->power) > 0) -+ rproc_shutdown(rproc); -+ -+ rproc_del(rproc); -+ stm32_rproc_free_mbox(rproc); -+ destroy_workqueue(ddata->workqueue); -+ -+ if (device_may_wakeup(dev)) { -+ dev_pm_clear_wake_irq(dev); -+ device_init_wakeup(dev, false); -+ } -+ rproc_free(rproc); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_rproc_suspend(struct device *dev) -+{ -+ struct rproc *rproc = dev_get_drvdata(dev); -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ if (device_may_wakeup(dev)) -+ return enable_irq_wake(ddata->wdg_irq); -+ -+ return 0; -+} -+ -+static int stm32_rproc_resume(struct device *dev) -+{ -+ struct rproc *rproc = dev_get_drvdata(dev); -+ struct stm32_rproc *ddata = rproc->priv; -+ -+ if (device_may_wakeup(dev)) -+ return disable_irq_wake(ddata->wdg_irq); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, -+ stm32_rproc_suspend, stm32_rproc_resume); -+ -+static struct platform_driver stm32_rproc_driver = { -+ .probe = stm32_rproc_probe, -+ .remove = stm32_rproc_remove, -+ .driver = { -+ .name = "stm32-rproc", -+ .pm = &stm32_rproc_pm_ops, -+ .of_match_table = of_match_ptr(stm32_rproc_match), -+ }, -+}; -+module_platform_driver(stm32_rproc_driver); -+ -+MODULE_DESCRIPTION("STM32 Remote Processor Control Driver"); -+MODULE_AUTHOR("Ludovic Barre "); -+MODULE_LICENSE("GPL v2"); -+ -diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c -index b221a28..d46c47b 100644 ---- a/drivers/reset/reset-stm32mp1.c -+++ b/drivers/reset/reset-stm32mp1.c -@@ -4,6 +4,7 @@ - * Author: Gabriel Fernandez for STMicroelectronics. - */ - -+#include - #include - #include - #include -@@ -13,11 +14,50 @@ - - #define CLR_OFFSET 0x4 - -+#define STM32_RCC_TZCR 0x0 -+#define CLR_OFFSET 0x4 -+ -+#define STM32MP1_SVC_RCC 0x82001000 -+ -+#define SMT32_SPI6_R 3136 -+#define STM32_AXIM_R 3216 -+#define STM32_MCU_R 8225 -+ - struct stm32_reset_data { - struct reset_controller_dev rcdev; - void __iomem *membase; - }; - -+static int soc_secured; -+ -+static int is_stm32_id_secured(unsigned long id) -+{ -+ if (id >= SMT32_SPI6_R && id <= STM32_AXIM_R) -+ return 1; -+ -+ if (id == STM32_MCU_R) -+ return 1; -+ -+ return 0; -+} -+ -+static int reset_stm32_secure_update(struct reset_controller_dev *rcdev, -+ unsigned long id, bool assert) -+{ -+ struct arm_smccc_res res; -+ int bank = id / BITS_PER_LONG; -+ int offset = id % BITS_PER_LONG; -+ -+ if (assert) -+ arm_smccc_smc(STM32MP1_SVC_RCC, 0x1, (bank * 4), -+ BIT(offset), 0, 0, 0, 0, &res); -+ else -+ arm_smccc_smc(STM32MP1_SVC_RCC, 0x1, (bank * 4) + CLR_OFFSET, -+ BIT(offset), 0, 0, 0, 0, &res); -+ -+ return 0; -+} -+ - static inline struct stm32_reset_data * - to_stm32_reset_data(struct reset_controller_dev *rcdev) - { -@@ -45,12 +85,18 @@ static int stm32_reset_update(struct reset_controller_dev *rcdev, - static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) - { -+ if (soc_secured && is_stm32_id_secured(id)) -+ return reset_stm32_secure_update(rcdev, id, true); -+ - return stm32_reset_update(rcdev, id, true); - } - - static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) - { -+ if (soc_secured && is_stm32_id_secured(id)) -+ return reset_stm32_secure_update(rcdev, id, false); -+ - return stm32_reset_update(rcdev, id, false); - } - -@@ -101,6 +147,8 @@ static int stm32_reset_probe(struct platform_device *pdev) - data->rcdev.ops = &stm32_reset_ops; - data->rcdev.of_node = dev->of_node; - -+ soc_secured = readl(membase + STM32_RCC_TZCR) & 0x1; -+ - return devm_reset_controller_register(dev, &data->rcdev); - } - -diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig -index d0322b4..88759a4 100644 ---- a/drivers/rpmsg/Kconfig -+++ b/drivers/rpmsg/Kconfig -@@ -55,4 +55,13 @@ config RPMSG_VIRTIO - select RPMSG - select VIRTIO - -+config RPMSG_TTY -+ tristate "RPMSG tty driver" -+ depends on RPMSG -+ help -+ Say y here to export rpmsg endpoints as tty console, usually found -+ in /dev/ttyRPMSG. -+ This makes it possible for user-space programs to send and receive -+ rpmsg messages as a standard tty protocol. -+ - endmenu -diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile -index 9aa8595..107145c 100644 ---- a/drivers/rpmsg/Makefile -+++ b/drivers/rpmsg/Makefile -@@ -5,4 +5,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o - obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o - obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o - obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o -+obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o - obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o -diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c -index 8122807..edb8549 100644 ---- a/drivers/rpmsg/rpmsg_core.c -+++ b/drivers/rpmsg/rpmsg_core.c -@@ -283,6 +283,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - } - EXPORT_SYMBOL(rpmsg_trysend_offchannel); - -+/** -+ * rpmsg_get_buffer_size() -+ * This function returns buffer size available for sending messages. -+ * -+ * @ept: the rpmsg endpoint -+ * -+ * Returns buffer size on success and an appropriate error value on failure. -+ */ -+int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ if (WARN_ON(!ept)) -+ return -EINVAL; -+ if (!ept->ops->get_buffer_size) -+ return -ENXIO; -+ -+ return ept->ops->get_buffer_size(ept); -+} -+EXPORT_SYMBOL(rpmsg_get_buffer_size); -+ - /* - * match an rpmsg channel with a channel info struct. - * this is used to make sure we're not creating rpmsg devices for channels -diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h -index 0d791c3..65bcb52 100644 ---- a/drivers/rpmsg/rpmsg_internal.h -+++ b/drivers/rpmsg/rpmsg_internal.h -@@ -46,6 +46,7 @@ struct rpmsg_device_ops { - * @trysend: see @rpmsg_trysend(), required - * @trysendto: see @rpmsg_trysendto(), optional - * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional -+ * @get_buffer_size: see @rpmsg_get_buffer_size(), optional - * - * Indirection table for the operations that a rpmsg backend should implement. - * In addition to @destroy_ept, the backend must at least implement @send and -@@ -65,6 +66,7 @@ struct rpmsg_endpoint_ops { - void *data, int len); - __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, - poll_table *wait); -+ int (*get_buffer_size)(struct rpmsg_endpoint *ept); - }; - - int rpmsg_register_device(struct rpmsg_device *rpdev); -diff --git a/drivers/rpmsg/rpmsg_tty.c b/drivers/rpmsg/rpmsg_tty.c -new file mode 100644 -index 0000000..5776389 ---- /dev/null -+++ b/drivers/rpmsg/rpmsg_tty.c -@@ -0,0 +1,310 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Arnaud Pouliquen for STMicroelectronics. -+ * Derived from the imx-rmpsg and omap-rpmsg implementations. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_TTY_RPMSG_INDEX 32 /* Should be enough for a while */ -+ -+static LIST_HEAD(rpmsg_tty_list); /* tty instances list */ -+static DEFINE_MUTEX(rpmsg_tty_lock); /* protect tty list */ -+ -+static struct tty_driver *rpmsg_tty_driver; -+static struct tty_port_operations rpmsg_tty_port_ops = { }; -+ -+struct rpmsg_tty_port { -+ struct tty_port port; /* TTY port data */ -+ struct list_head list; /* TTY device list */ -+ u32 id; /* tty rpmsg index */ -+ spinlock_t rx_lock; /* message reception lock */ -+ struct rpmsg_device *rpdev; /* handle rpmsg device */ -+}; -+ -+static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, -+ void *priv, u32 src) -+{ -+ int space; -+ unsigned char *cbuf; -+ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); -+ -+ /* Flush the recv-ed none-zero data to tty node */ -+ if (len == 0) -+ return -EINVAL; -+ -+ dev_dbg(&rpdev->dev, "msg(<- src 0x%x) len %d\n", src, len); -+ -+ print_hex_dump_debug(__func__, DUMP_PREFIX_NONE, 16, 1, data, len, -+ true); -+ -+ spin_lock(&cport->rx_lock); -+ space = tty_prepare_flip_string(&cport->port, &cbuf, len); -+ if (space <= 0) { -+ dev_err(&rpdev->dev, "No memory for tty_prepare_flip_string\n"); -+ spin_unlock(&cport->rx_lock); -+ return -ENOMEM; -+ } -+ -+ if (space != len) -+ dev_warn(&rpdev->dev, "Trunc buffer from %d to %d\n", -+ len, space); -+ -+ memcpy(cbuf, data, space); -+ tty_flip_buffer_push(&cport->port); -+ spin_unlock(&cport->rx_lock); -+ -+ return 0; -+} -+ -+static struct rpmsg_tty_port *rpmsg_tty_get(unsigned int index) -+{ -+ struct rpmsg_tty_port *cport; -+ -+ mutex_lock(&rpmsg_tty_lock); -+ list_for_each_entry(cport, &rpmsg_tty_list, list) { -+ if (index == cport->id) { -+ mutex_unlock(&rpmsg_tty_lock); -+ return cport; -+ } -+ } -+ mutex_unlock(&rpmsg_tty_lock); -+ -+ return NULL; -+} -+ -+static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return -ENODEV; -+ -+ return tty_port_install(&cport->port, driver, tty); -+} -+ -+static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return -ENODEV; -+ -+ return tty_port_open(tty->port, tty, filp); -+} -+ -+static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp) -+{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return; -+ return tty_port_close(tty->port, tty, filp); -+} -+ -+static int rpmsg_tty_write(struct tty_struct *tty, const unsigned char *buf, -+ int total) -+{ -+ int count, ret = 0; -+ const unsigned char *tbuf; -+ struct rpmsg_tty_port *cport = container_of(tty->port, -+ struct rpmsg_tty_port, port); -+ struct rpmsg_device *rpdev = cport->rpdev; -+ int msg_size; -+ -+ dev_dbg(&rpdev->dev, "%s: send message from tty->index = %d\n", -+ __func__, tty->index); -+ -+ if (!buf) { -+ dev_err(&rpdev->dev, "buf shouldn't be null.\n"); -+ return -ENOMEM; -+ } -+ -+ msg_size = rpmsg_get_buffer_size(rpdev->ept); -+ if (msg_size < 0) -+ return msg_size; -+ -+ count = total; -+ tbuf = buf; -+ do { -+ /* send a message to our remote processor */ -+ ret = rpmsg_trysend(rpdev->ept, (void *)tbuf, -+ count > msg_size ? msg_size : count); -+ if (ret) { -+ dev_dbg(&rpdev->dev, "rpmsg_send failed: %d\n", ret); -+ return 0; -+ } -+ -+ if (count > msg_size) { -+ count -= msg_size; -+ tbuf += msg_size; -+ } else { -+ count = 0; -+ } -+ } while (count > 0); -+ -+ return total; -+} -+ -+static int rpmsg_tty_write_room(struct tty_struct *tty) -+{ -+ struct rpmsg_tty_port *cport = container_of(tty->port, -+ struct rpmsg_tty_port, port); -+ struct rpmsg_device *rpdev = cport->rpdev; -+ -+ /* report the space in the rpmsg buffer */ -+ return rpmsg_get_buffer_size(rpdev->ept); -+} -+ -+static const struct tty_operations rpmsg_tty_ops = { -+ .install = rpmsg_tty_install, -+ .open = rpmsg_tty_open, -+ .close = rpmsg_tty_close, -+ .write = rpmsg_tty_write, -+ .write_room = rpmsg_tty_write_room, -+}; -+ -+static int rpmsg_tty_probe(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_tty_port *cport, *tmp; -+ unsigned int index; -+ struct device *tty_dev; -+ -+ cport = devm_kzalloc(&rpdev->dev, sizeof(*cport), GFP_KERNEL); -+ if (!cport) -+ return -ENOMEM; -+ -+ tty_port_init(&cport->port); -+ cport->port.ops = &rpmsg_tty_port_ops; -+ spin_lock_init(&cport->rx_lock); -+ -+ cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY; -+ -+ cport->rpdev = rpdev; -+ -+ /* get free index */ -+ mutex_lock(&rpmsg_tty_lock); -+ for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) { -+ bool id_found = false; -+ -+ list_for_each_entry(tmp, &rpmsg_tty_list, list) { -+ if (index == tmp->id) { -+ id_found = true; -+ break; -+ } -+ } -+ if (!id_found) -+ break; -+ } -+ -+ tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, -+ index, &rpdev->dev); -+ if (IS_ERR(tty_dev)) { -+ dev_err(&rpdev->dev, "failed to register tty port\n"); -+ tty_port_destroy(&cport->port); -+ mutex_unlock(&rpmsg_tty_lock); -+ return PTR_ERR(tty_dev); -+ } -+ -+ cport->id = index; -+ list_add_tail(&cport->list, &rpmsg_tty_list); -+ mutex_unlock(&rpmsg_tty_lock); -+ dev_set_drvdata(&rpdev->dev, cport); -+ -+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x : ttyRPMSG%d\n", -+ rpdev->src, rpdev->dst, index); -+ -+ return 0; -+} -+ -+static void rpmsg_tty_remove(struct rpmsg_device *rpdev) -+{ -+ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); -+ -+ /* User hang up to release the tty */ -+ if (tty_port_initialized(&cport->port)) -+ tty_port_tty_hangup(&cport->port, false); -+ tty_port_destroy(&cport->port); -+ tty_unregister_device(rpmsg_tty_driver, cport->id); -+ list_del(&cport->list); -+ -+ dev_info(&rpdev->dev, "rpmsg tty device %d is removed\n", cport->id); -+} -+ -+static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = { -+ { .name = "rpmsg-tty-channel" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table); -+ -+static struct rpmsg_driver rpmsg_tty_rmpsg_drv = { -+ .drv.name = KBUILD_MODNAME, -+ .drv.owner = THIS_MODULE, -+ .id_table = rpmsg_driver_tty_id_table, -+ .probe = rpmsg_tty_probe, -+ .callback = rpmsg_tty_cb, -+ .remove = rpmsg_tty_remove, -+}; -+ -+static int __init rpmsg_tty_init(void) -+{ -+ int err; -+ -+ rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG_INDEX, 0); -+ if (IS_ERR(rpmsg_tty_driver)) -+ return PTR_ERR(rpmsg_tty_driver); -+ -+ rpmsg_tty_driver->driver_name = "rpmsg_tty"; -+ rpmsg_tty_driver->name = "ttyRPMSG"; -+ rpmsg_tty_driver->major = TTYAUX_MAJOR; -+ rpmsg_tty_driver->minor_start = 3; -+ rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE; -+ rpmsg_tty_driver->init_termios = tty_std_termios; -+ rpmsg_tty_driver->flags = TTY_DRIVER_REAL_RAW | -+ TTY_DRIVER_DYNAMIC_DEV; -+ -+ tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); -+ -+ /* Disable unused mode by default */ -+ rpmsg_tty_driver->init_termios = tty_std_termios; -+ rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON); -+ rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR); -+ -+ err = tty_register_driver(rpmsg_tty_driver); -+ if (err < 0) { -+ pr_err("Couldn't install rpmsg tty driver: err %d\n", err); -+ goto tty_error; -+ } -+ err = register_rpmsg_driver(&rpmsg_tty_rmpsg_drv); -+ -+ if (!err) -+ return 0; -+ -+ tty_unregister_driver(rpmsg_tty_driver); -+ -+tty_error: -+ put_tty_driver(rpmsg_tty_driver); -+ -+ return err; -+} -+ -+static void __exit rpmsg_tty_exit(void) -+{ -+ unregister_rpmsg_driver(&rpmsg_tty_rmpsg_drv); -+ tty_unregister_driver(rpmsg_tty_driver); -+ put_tty_driver(rpmsg_tty_driver); -+} -+ -+module_init(rpmsg_tty_init); -+module_exit(rpmsg_tty_exit); -+ -+MODULE_AUTHOR("Arnaud Pouliquen "); -+MODULE_DESCRIPTION("virtio remote processor messaging tty driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c -index 664f957..f1f3032 100644 ---- a/drivers/rpmsg/virtio_rpmsg_bus.c -+++ b/drivers/rpmsg/virtio_rpmsg_bus.c -@@ -175,6 +175,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, - int len, u32 dst); - static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, - u32 dst, void *data, int len); -+static int virtio_get_buffer_size(struct rpmsg_endpoint *ept); - - static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { - .destroy_ept = virtio_rpmsg_destroy_ept, -@@ -184,6 +185,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { - .trysend = virtio_rpmsg_trysend, - .trysendto = virtio_rpmsg_trysendto, - .trysend_offchannel = virtio_rpmsg_trysend_offchannel, -+ .get_buffer_size = virtio_get_buffer_size, - }; - - /** -@@ -699,6 +701,15 @@ static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); - } - -+static int virtio_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ struct rpmsg_device *rpdev = ept->rpdev; -+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); -+ struct virtproc_info *vrp = vch->vrp; -+ -+ return vrp->buf_size - sizeof(struct rpmsg_hdr); -+} -+ - static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, - struct rpmsg_hdr *msg, unsigned int len) - { -@@ -912,7 +923,7 @@ static int rpmsg_probe(struct virtio_device *vdev) - total_buf_space = vrp->num_bufs * vrp->buf_size; - - /* allocate coherent memory for the buffers */ -- bufs_va = dma_alloc_coherent(vdev->dev.parent->parent, -+ bufs_va = dma_alloc_coherent(vdev->dev.parent, - total_buf_space, &vrp->bufs_dma, - GFP_KERNEL); - if (!bufs_va) { -@@ -980,7 +991,7 @@ static int rpmsg_probe(struct virtio_device *vdev) - return 0; - - free_coherent: -- dma_free_coherent(vdev->dev.parent->parent, total_buf_space, -+ dma_free_coherent(vdev->dev.parent, total_buf_space, - bufs_va, vrp->bufs_dma); - vqs_del: - vdev->config->del_vqs(vrp->vdev); -@@ -1015,7 +1026,7 @@ static void rpmsg_remove(struct virtio_device *vdev) - - vdev->config->del_vqs(vrp->vdev); - -- dma_free_coherent(vdev->dev.parent->parent, total_buf_space, -+ dma_free_coherent(vdev->dev.parent, total_buf_space, - vrp->rbufs, vrp->bufs_dma); - - kfree(vrp); -diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h -index e3c5d85..cd540c0 100644 ---- a/include/linux/remoteproc.h -+++ b/include/linux/remoteproc.h -@@ -305,14 +305,22 @@ struct fw_rsc_vdev { - struct fw_rsc_vdev_vring vring[0]; - } __packed; - -+struct rproc; -+ - /** - * struct rproc_mem_entry - memory entry descriptor - * @va: virtual address - * @dma: dma address - * @len: length, in bytes - * @da: device address -+ * @release: release associated memory - * @priv: associated data -+ * @name: associated memory region name (optional) - * @node: list node -+ * @rsc_offset: offset in resource table -+ * @flags: iommu protection flags -+ * @of_resm_idx: reserved memory phandle index -+ * @alloc: specific memory allocator function - */ - struct rproc_mem_entry { - void *va; -@@ -320,10 +328,15 @@ struct rproc_mem_entry { - int len; - u32 da; - void *priv; -+ char name[32]; - struct list_head node; -+ u32 rsc_offset; -+ u32 flags; -+ u32 of_resm_idx; -+ int (*alloc)(struct rproc *rproc, struct rproc_mem_entry *mem); -+ int (*release)(struct rproc *rproc, struct rproc_mem_entry *mem); - }; - --struct rproc; - struct firmware; - - /** -@@ -440,6 +453,8 @@ struct rproc_dump_segment { - * @table_sz: size of @cached_table - * @has_iommu: flag to indicate if remote processor is behind an MMU - * @dump_segments: list of segments in the firmware -+ * @early_boot: remote processor has been booted before kernel boot -+ * @nb_vdev: number of vdev currently handled by rproc - */ - struct rproc { - struct list_head node; -@@ -472,6 +487,8 @@ struct rproc { - bool has_iommu; - bool auto_boot; - struct list_head dump_segments; -+ bool early_boot; -+ int nb_vdev; - }; - - /** -@@ -499,7 +516,6 @@ struct rproc_subdev { - /** - * struct rproc_vring - remoteproc vring state - * @va: virtual address -- * @dma: dma address - * @len: length, in bytes - * @da: device address - * @align: vring alignment -@@ -509,7 +525,6 @@ struct rproc_subdev { - */ - struct rproc_vring { - void *va; -- dma_addr_t dma; - int len; - u32 da; - u32 align; -@@ -521,6 +536,7 @@ struct rproc_vring { - /** - * struct rproc_vdev - remoteproc state for a supported virtio device - * @refcount: reference counter for the vdev and vring allocations -+ * @dev: sub device associated to the virtio device - * @subdev: handle for registering the vdev as a rproc subdevice - * @id: virtio device id (as in virtio_ids.h) - * @node: list node -@@ -528,11 +544,13 @@ struct rproc_vring { - * @vdev: the virio device - * @vring: the vrings for this vdev - * @rsc_offset: offset of the vdev's resource entry -+ * @index: vdev position versus other vdev declared in resource table - */ - struct rproc_vdev { - struct kref refcount; - - struct rproc_subdev subdev; -+ struct device dev; - - unsigned int id; - struct list_head node; -@@ -540,6 +558,7 @@ struct rproc_vdev { - struct virtio_device vdev; - struct rproc_vring vring[RVDEV_NUM_VRINGS]; - u32 rsc_offset; -+ u32 index; - }; - - struct rproc *rproc_get_by_phandle(phandle phandle); -@@ -553,6 +572,19 @@ int rproc_add(struct rproc *rproc); - int rproc_del(struct rproc *rproc); - void rproc_free(struct rproc *rproc); - -+void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem); -+ -+struct rproc_mem_entry * -+rproc_mem_entry_init(struct device *dev, -+ void *va, dma_addr_t dma, int len, u32 da, -+ int (*alloc)(struct rproc *, struct rproc_mem_entry *), -+ int (*release)(struct rproc *, struct rproc_mem_entry *), -+ const char *name, ...); -+ -+struct rproc_mem_entry * -+rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len, -+ u32 da, const char *name, ...); -+ - int rproc_boot(struct rproc *rproc); - void rproc_shutdown(struct rproc *rproc); - void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); -diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h -index 9fe156d..2af7674 100644 ---- a/include/linux/rpmsg.h -+++ b/include/linux/rpmsg.h -@@ -135,6 +135,7 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, - poll_table *wait); - -+int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept); - #else - - static inline int register_rpmsg_device(struct rpmsg_device *dev) -@@ -242,6 +243,14 @@ static inline __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, - return 0; - } - -+static int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) -+{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return -ENXIO; -+} -+ - #endif /* IS_ENABLED(CONFIG_RPMSG) */ - - /* use a macro to avoid include chaining to get THIS_MODULE */ --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch deleted file mode 100644 index c50aaaf..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch +++ /dev/null @@ -1,276 +0,0 @@ -From eb8e18ef550744ca51256b8cd1dc3cf09b7596e4 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:45 +0100 -Subject: [PATCH 22/31] ARM stm32mp1 r3 RTC - ---- - drivers/rtc/Kconfig | 1 + - drivers/rtc/rtc-stm32.c | 119 ++++++++++++++++++++++++++++++++++++ - include/dt-bindings/rtc/rtc-stm32.h | 13 ++++ - 3 files changed, 133 insertions(+) - create mode 100644 include/dt-bindings/rtc/rtc-stm32.h - -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 7d7be60..6e201ff 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1770,6 +1770,7 @@ config RTC_DRV_R7301 - config RTC_DRV_STM32 - tristate "STM32 RTC" - select REGMAP_MMIO -+ depends on COMMON_CLK - depends on ARCH_STM32 || COMPILE_TEST - help - If you say yes here you get support for the STM32 On-Chip -diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c -index 8e6c9b3..8ab3586 100644 ---- a/drivers/rtc/rtc-stm32.c -+++ b/drivers/rtc/rtc-stm32.c -@@ -6,6 +6,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -15,6 +16,8 @@ - #include - #include - -+#include -+ - #define DRIVER_NAME "stm32_rtc" - - /* STM32_RTC_TR bit fields */ -@@ -39,6 +42,12 @@ - #define STM32_RTC_CR_FMT BIT(6) - #define STM32_RTC_CR_ALRAE BIT(8) - #define STM32_RTC_CR_ALRAIE BIT(12) -+#define STM32_RTC_CR_COSEL BIT(19) -+#define STM32_RTC_CR_OSEL_SHIFT 21 -+#define STM32_RTC_CR_OSEL GENMASK(22, 21) -+#define STM32_RTC_CR_COE BIT(23) -+#define STM32_RTC_CR_TAMPOE BIT(26) -+#define STM32_RTC_CR_OUT2EN BIT(31) - - /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ - #define STM32_RTC_ISR_ALRAWF BIT(0) -@@ -75,6 +84,11 @@ - /* STM32_RTC_SR/_SCR bit fields */ - #define STM32_RTC_SR_ALRA BIT(0) - -+/* STM32_RTC_CFGR bit fields */ -+#define STM32_RTC_CFGR_OUT2_RMP BIT(0) -+#define STM32_RTC_CFGR_LSCOEN_OUT1 1 -+#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2 -+ - /* STM32_RTC_VERR bit fields */ - #define STM32_RTC_VERR_MINREV_SHIFT 0 - #define STM32_RTC_VERR_MINREV GENMASK(3, 0) -@@ -101,6 +115,7 @@ struct stm32_rtc_registers { - u16 wpr; - u16 sr; - u16 scr; -+ u16 cfgr; - u16 verr; - }; - -@@ -115,6 +130,7 @@ struct stm32_rtc_data { - bool has_pclk; - bool need_dbp; - bool has_wakeirq; -+ bool has_lsco; - }; - - struct stm32_rtc { -@@ -128,8 +144,87 @@ struct stm32_rtc { - const struct stm32_rtc_data *data; - int irq_alarm; - int wakeirq_alarm; -+ int lsco; -+ struct clk *clk_lsco; - }; - -+/* -+ * ------------------------------------------------------------------------- -+ * | TAMPOE | OSEL[1:0] | COE | OUT2EN | RTC_OUT1 | RTC_OUT2 | -+ * | | | | | | or RTC_OUT2_RMP | -+ * |-------------------------------------------------------------------------| -+ * | 0 | 00 | 0 | 0 or 1 | - | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 | 00 | 1 | 0 | CALIB | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 0 | 0 | TAMPALRM | - | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 | 00 | 1 | 1 | - | CALIB | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 0 | 1 | - | TAMPALRM | -+ * |--------|-----------|-----|--------|------------------|------------------| -+ * | 0 or 1 | !=00 | 1 | 1 | TAMPALRM | CALIB | -+ * ------------------------------------------------------------------------- -+ */ -+static int stm32_rtc_clk_lsco_check_availability(struct stm32_rtc *rtc) -+{ -+ struct stm32_rtc_registers regs = rtc->data->regs; -+ unsigned int cr = readl_relaxed(rtc->base + regs.cr); -+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr); -+ unsigned int calib = STM32_RTC_CR_COE; -+ unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL; -+ -+ switch (rtc->lsco) { -+ case RTC_OUT1: -+ if ((!(cr & STM32_RTC_CR_OUT2EN) && -+ ((cr & calib) || cr & tampalrm)) || -+ ((cr & calib) && (cr & tampalrm))) -+ return -EBUSY; -+ break; -+ case RTC_OUT2_RMP: -+ if ((cr & STM32_RTC_CR_OUT2EN) && -+ (cfgr & STM32_RTC_CFGR_OUT2_RMP) && -+ ((cr & calib) || (cr & tampalrm))) -+ return -EBUSY; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (clk_get_rate(rtc->rtc_ck) != 32768) -+ return -ERANGE; -+ -+ return 0; -+} -+ -+static int stm32_rtc_clk_lsco_register(struct platform_device *pdev) -+{ -+ struct stm32_rtc *rtc = platform_get_drvdata(pdev); -+ struct stm32_rtc_registers regs = rtc->data->regs; -+ u8 lscoen; -+ int ret; -+ -+ ret = stm32_rtc_clk_lsco_check_availability(rtc); -+ if (ret) -+ return ret; -+ -+ lscoen = (rtc->lsco == RTC_OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : -+ STM32_RTC_CFGR_LSCOEN_OUT2_RMP; -+ -+ rtc->clk_lsco = clk_register_gate(&pdev->dev, "rtc_lsco", -+ __clk_get_name(rtc->rtc_ck), -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, -+ rtc->base + regs.cfgr, lscoen, -+ 0, NULL); -+ if (IS_ERR(rtc->clk_lsco)) -+ return PTR_ERR(rtc->clk_lsco); -+ -+ of_clk_add_provider(pdev->dev.of_node, -+ of_clk_src_simple_get, rtc->clk_lsco); -+ -+ return 0; -+} -+ - static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) - { - const struct stm32_rtc_registers *regs = &rtc->data->regs; -@@ -552,6 +647,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { - .has_pclk = false, - .need_dbp = true, - .has_wakeirq = false, -+ .has_lsco = false, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -562,6 +658,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { - .wpr = 0x24, - .sr = 0x0C, /* set to ISR offset to ease alarm management */ - .scr = UNDEF_REG, -+ .cfgr = UNDEF_REG, - .verr = UNDEF_REG, - }, - .events = { -@@ -574,6 +671,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { - .has_pclk = true, - .need_dbp = true, - .has_wakeirq = false, -+ .has_lsco = false, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -584,6 +682,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { - .wpr = 0x24, - .sr = 0x0C, /* set to ISR offset to ease alarm management */ - .scr = UNDEF_REG, -+ .cfgr = UNDEF_REG, - .verr = UNDEF_REG, - }, - .events = { -@@ -605,6 +704,7 @@ static const struct stm32_rtc_data stm32mp1_data = { - .has_pclk = true, - .need_dbp = false, - .has_wakeirq = true, -+ .has_lsco = true, - .regs = { - .tr = 0x00, - .dr = 0x04, -@@ -615,6 +715,7 @@ static const struct stm32_rtc_data stm32mp1_data = { - .wpr = 0x24, - .sr = 0x50, - .scr = 0x5C, -+ .cfgr = 0x60, - .verr = 0x3F4, - }, - .events = { -@@ -821,6 +922,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) - goto err; - } - -+ if (rtc->data->has_lsco) { -+ ret = of_property_read_s32(pdev->dev.of_node, -+ "st,lsco", &rtc->lsco); -+ if (!ret) { -+ ret = stm32_rtc_clk_lsco_register(pdev); -+ if (ret) -+ dev_warn(&pdev->dev, -+ "LSCO clock registration failed: %d\n", -+ ret); -+ } else { -+ rtc->lsco = ret; -+ dev_dbg(&pdev->dev, "No LSCO clock: %d\n", ret); -+ } -+ } -+ - /* - * If INITS flag is reset (calendar year field set to 0x00), calendar - * must be initialized -@@ -857,6 +973,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) - const struct stm32_rtc_registers *regs = &rtc->data->regs; - unsigned int cr; - -+ if (!IS_ERR_OR_NULL(rtc->clk_lsco)) -+ clk_unregister_gate(rtc->clk_lsco); -+ - /* Disable interrupts */ - stm32_rtc_wpr_unlock(rtc); - cr = readl_relaxed(rtc->base + regs->cr); -diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h -new file mode 100644 -index 0000000..4373c4d ---- /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 --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch deleted file mode 100644 index 3498c9f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch +++ /dev/null @@ -1,658 +0,0 @@ -From 62a47162dba55286160a68ac2b46d405142b2830 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 9 Dec 2019 12:26:14 +0100 -Subject: [PATCH 23/31] ARM stm32mp1 r3 SOC - ---- - drivers/soc/Kconfig | 1 + - drivers/soc/Makefile | 1 + - drivers/soc/st/Kconfig | 17 +++ - drivers/soc/st/Makefile | 2 + - drivers/soc/st/stm32_hdp.c | 242 ++++++++++++++++++++++++++++++++++++ - drivers/soc/st/stm32_pm_domain.c | 212 +++++++++++++++++++++++++++++++ - include/dt-bindings/soc/stm32-hdp.h | 108 ++++++++++++++++ - 7 files changed, 583 insertions(+) - create mode 100644 drivers/soc/st/Kconfig - create mode 100644 drivers/soc/st/Makefile - create mode 100644 drivers/soc/st/stm32_hdp.c - create mode 100644 drivers/soc/st/stm32_pm_domain.c - create mode 100644 include/dt-bindings/soc/stm32-hdp.h - -diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig -index c07b4a8..f2bd1ce 100644 ---- a/drivers/soc/Kconfig -+++ b/drivers/soc/Kconfig -@@ -11,6 +11,7 @@ source "drivers/soc/qcom/Kconfig" - source "drivers/soc/renesas/Kconfig" - source "drivers/soc/rockchip/Kconfig" - source "drivers/soc/samsung/Kconfig" -+source "drivers/soc/st/Kconfig" - source "drivers/soc/sunxi/Kconfig" - source "drivers/soc/tegra/Kconfig" - source "drivers/soc/ti/Kconfig" -diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index f0d46b1..d2c3147 100644 ---- a/drivers/soc/Makefile -+++ b/drivers/soc/Makefile -@@ -18,6 +18,7 @@ obj-y += qcom/ - obj-y += renesas/ - obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ - obj-$(CONFIG_SOC_SAMSUNG) += samsung/ -+obj-$(CONFIG_ARCH_STM32) += st/ - obj-$(CONFIG_ARCH_SUNXI) += sunxi/ - obj-$(CONFIG_ARCH_TEGRA) += tegra/ - obj-$(CONFIG_SOC_TI) += ti/ -diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig -new file mode 100644 -index 0000000..8ab6049 ---- /dev/null -+++ b/drivers/soc/st/Kconfig -@@ -0,0 +1,17 @@ -+if ARCH_STM32 -+ -+config STM32_PM_DOMAINS -+ bool "STM32 PM domains" -+ depends on MACH_STM32MP157 -+ select PM_GENERIC_DOMAINS -+ default y if MACH_STM32MP157 -+ -+config STM32_HDP -+ bool "STMicroelectronics STM32MP157 Hardware Debug Port (HDP) pin control" -+ depends on MACH_STM32MP157 -+ default n if MACH_STM32MP157 -+ help -+ The Hardware Debug Port allows the observation of internal signals. By using multiplexers, -+ up to 16 signals for each of 8-bit output can be observed. -+ -+endif # ARCH_STM32 -diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile -new file mode 100644 -index 0000000..85905b7 ---- /dev/null -+++ b/drivers/soc/st/Makefile -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o -+obj-$(CONFIG_STM32_HDP) += stm32_hdp.o -diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c -new file mode 100644 -index 0000000..6408ac6 ---- /dev/null -+++ b/drivers/soc/st/stm32_hdp.c -@@ -0,0 +1,242 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Christophe Roullier -+ * for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define HDP_CTRL_ENABLE 1 -+#define HDP_CTRL_DISABLE 0 -+ -+enum { -+ HDP_CTRL = 0, -+ HDP_MUX = 0x4, -+ HDP_VAL = 0x10, -+ HDP_GPOSET = 0x14, -+ HDP_GPOCLR = 0x18, -+ HDP_GPOVAL = 0x1c, -+ HDP_VERR = 0x3f4, -+ HDP_IPIDR = 0x3f8, -+ HDP_SIDR = 0x3fc -+} HDP_register_offsets; -+ -+struct data_priv { -+ struct clk *clk; -+ int clk_is_enabled; -+ struct dentry *pwr_dentry; -+ unsigned char __iomem *hdp_membase; -+ unsigned int hdp_ctrl; -+ unsigned int hdp_mux; -+}; -+ -+/* enable/disable */ -+static int stm32_hdp_enable_set(void *data, int val) -+{ -+ struct data_priv *e = (struct data_priv *)data; -+ -+ if (!e->clk) -+ return -EPERM; -+ -+ if (val == 1) { -+ if (clk_prepare_enable(e->clk) < 0) { -+ pr_err("Failed to enable HDP clock\n"); -+ return -EPERM; -+ } -+ e->clk_is_enabled = 1; -+ } else { -+ clk_disable_unprepare(e->clk); -+ e->clk_is_enabled = 0; -+ } -+ return 0; -+} -+ -+static int stm32_hdp_fops_set(void *data, u64 val) -+{ -+ unsigned char __iomem *addr = (unsigned char __iomem *)data; -+ -+ writel_relaxed(val, addr); -+ -+ return 0; -+} -+ -+static int stm32_hdp_fops_get(void *data, u64 *val) -+{ -+ unsigned char __iomem *addr = (unsigned char __iomem *)data; -+ -+ *val = readl_relaxed(addr); -+ -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(stm32_hdp_fops, stm32_hdp_fops_get, -+ stm32_hdp_fops_set, "0x%llx\n"); -+ -+int stm32_hdp_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ -+ struct data_priv *data; -+ struct dentry *r; -+ -+ int ret; -+ const __be32 *getmuxing; -+ u32 muxing, version; -+ -+ if (!np) -+ return -ENODEV; -+ -+ data = devm_kzalloc(&pdev->dev, sizeof(struct data_priv), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ data->hdp_membase = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->hdp_membase)) -+ return PTR_ERR(data->hdp_membase); -+ -+ /* Get HDP clocks */ -+ data->clk = devm_clk_get(dev, "hdp"); -+ if (IS_ERR(data->clk)) { -+ dev_err(dev, "No HDP CK clock provided...\n"); -+ return PTR_ERR(data->clk); -+ } -+ -+ /* Enable clock */ -+ ret = stm32_hdp_enable_set(data, 1); -+ if (ret != 0) -+ return ret; -+ -+ getmuxing = of_get_property(np, "muxing-hdp", NULL); -+ if (!getmuxing) { -+ dev_err(dev, -+ "no muxing-hdp property in node\n"); -+ /* Disable clock */ -+ ret = stm32_hdp_enable_set(data, 0); -+ if (ret != 0) -+ return ret; -+ -+ return -EINVAL; -+ } -+ -+ /* add hdp directory */ -+ r = debugfs_create_dir("hdp", NULL); -+ if (!r) { -+ dev_err(dev, "Unable to create HDP debugFS\n"); -+ /* Disable clock */ -+ ret = stm32_hdp_enable_set(data, 0); -+ if (ret != 0) -+ return ret; -+ -+ return -ENODEV; -+ } -+ -+ debugfs_create_file("ctrl", 0644, r, -+ data->hdp_membase + HDP_CTRL, &stm32_hdp_fops); -+ debugfs_create_file("mux", 0644, r, -+ data->hdp_membase + HDP_MUX, &stm32_hdp_fops); -+ debugfs_create_file("val", 0644, r, -+ data->hdp_membase + HDP_VAL, &stm32_hdp_fops); -+ debugfs_create_file("gposet", 0644, r, -+ data->hdp_membase + HDP_GPOSET, &stm32_hdp_fops); -+ debugfs_create_file("gpoclr", 0644, r, -+ data->hdp_membase + HDP_GPOCLR, &stm32_hdp_fops); -+ debugfs_create_file("gpoval", 0644, r, -+ data->hdp_membase + HDP_GPOVAL, &stm32_hdp_fops); -+ -+ /* Enable HDP */ -+ writel(HDP_CTRL_ENABLE, data->hdp_membase + HDP_CTRL); -+ -+ /* HDP Multiplexing */ -+ muxing = of_read_number(getmuxing, -+ of_n_addr_cells(np)); -+ -+ writel(muxing, data->hdp_membase + HDP_MUX); -+ -+ platform_set_drvdata(pdev, data); -+ -+ /* Get Majeur, Minor version */ -+ version = readl(data->hdp_membase + HDP_VERR); -+ -+ dev_info(dev, "STM32 HDP version %d.%d initialized\n", -+ version >> 4, version & 0x0F); -+ -+ return 0; -+} -+ -+static int stm32_hdp_remove(struct platform_device *pdev) -+{ -+ struct data_priv *data = platform_get_drvdata(pdev); -+ -+ /* Disable HDP */ -+ writel(HDP_CTRL_DISABLE, data->hdp_membase + HDP_CTRL); -+ -+ if (data->clk) { -+ if (data->clk_is_enabled) -+ clk_disable_unprepare(data->clk); -+ } -+ -+ pr_info("driver STM32 HDP removed\n"); -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_hdp_suspend(struct device *dev) -+{ -+ struct data_priv *data = dev_get_drvdata(dev); -+ -+ data->hdp_ctrl = readl_relaxed(data->hdp_membase + HDP_CTRL); -+ data->hdp_mux = readl_relaxed(data->hdp_membase + HDP_MUX); -+ -+ pinctrl_pm_select_sleep_state(dev); -+ -+ return 0; -+} -+ -+static int stm32_hdp_resume(struct device *dev) -+{ -+ struct data_priv *data = dev_get_drvdata(dev); -+ -+ writel_relaxed(data->hdp_ctrl, data->hdp_membase + HDP_CTRL); -+ writel_relaxed(data->hdp_mux, data->hdp_membase + HDP_MUX); -+ -+ pinctrl_pm_select_default_state(dev); -+ -+ return 0; -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, -+ stm32_hdp_suspend, -+ stm32_hdp_resume); -+ -+static const struct of_device_id hdp_match[] = { -+ { .compatible = "st,stm32mp1-hdp",}, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, hdp_match); -+ -+static struct platform_driver hdp_driver = { -+ .probe = stm32_hdp_probe, -+ .remove = stm32_hdp_remove, -+ .driver = { -+ .name = "hdp", -+ .of_match_table = hdp_match, -+ .pm = &stm32_hdp_pm_ops, -+ }, -+}; -+ -+module_platform_driver(hdp_driver); -diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c -new file mode 100644 -index 0000000..0386624 ---- /dev/null -+++ b/drivers/soc/st/stm32_pm_domain.c -@@ -0,0 +1,212 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ * Author: Olivier Bideau for STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SMC(domain, state) \ -+{ \ -+ struct arm_smccc_res res; \ -+ arm_smccc_smc(0x82001008, domain, state, 0, \ -+ 0, 0, 0, 0, &res); \ -+} -+ -+#define STM32_SMC_PD_DOMAIN_ON 0 -+#define STM32_SMC_PD_DOMAIN_OFF 1 -+ -+struct stm32_pm_domain { -+ struct device *dev; -+ struct generic_pm_domain genpd; -+ int id; -+}; -+ -+static int stm32_pd_power_off(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ -+ SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF); -+ -+ dev_dbg(priv->dev, "%s OFF\n", domain->name); -+ -+ return 0; -+} -+ -+static int stm32_pd_power_on(struct generic_pm_domain *domain) -+{ -+ struct stm32_pm_domain *priv = container_of(domain, -+ struct stm32_pm_domain, -+ genpd); -+ -+ SMC(priv->id, STM32_SMC_PD_DOMAIN_ON); -+ -+ dev_dbg(priv->dev, "%s ON\n", domain->name); -+ -+ return 0; -+} -+ -+static void stm32_pm_domain_remove(struct stm32_pm_domain *domain) -+{ -+ int ret; -+ -+ ret = pm_genpd_remove(&domain->genpd); -+ if (ret) -+ dev_err(domain->dev, "failed to remove PM domain %s: %d\n", -+ domain->genpd.name, ret); -+} -+ -+static int stm32_pm_domain_add(struct stm32_pm_domain *domain, -+ struct device *dev, -+ struct device_node *np) -+{ -+ int ret; -+ -+ domain->dev = dev; -+ domain->genpd.name = np->name; -+ domain->genpd.power_off = stm32_pd_power_off; -+ domain->genpd.power_on = stm32_pd_power_on; -+ domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; -+ -+ ret = of_property_read_u32(np, "reg", &domain->id); -+ if (ret) { -+ dev_err(domain->dev, "no domain ID\n"); -+ return ret; -+ } -+ -+ ret = pm_genpd_init(&domain->genpd, NULL, 0); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", -+ np->name, ret); -+ return ret; -+ } -+ -+ ret = of_genpd_add_provider_simple(np, &domain->genpd); -+ if (ret < 0) { -+ dev_err(domain->dev, "failed to register PM domain %s: %d\n", -+ np->name, ret); -+ stm32_pm_domain_remove(domain); -+ return ret; -+ } -+ -+ dev_info(domain->dev, "domain %s registered\n", np->name); -+ -+ return 0; -+} -+ -+static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain, -+ struct device *dev, -+ struct device_node *np) -+{ -+ struct device_node *np_child; -+ int ret; -+ -+ for_each_child_of_node(np, np_child) { -+ struct stm32_pm_domain *sub_domain; -+ -+ sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL); -+ if (!sub_domain) -+ continue; -+ -+ sub_domain->dev = dev; -+ sub_domain->genpd.name = np_child->name; -+ sub_domain->genpd.power_off = stm32_pd_power_off; -+ sub_domain->genpd.power_on = stm32_pd_power_on; -+ sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; -+ -+ ret = of_property_read_u32(np_child, "reg", &sub_domain->id); -+ if (ret) { -+ dev_err(sub_domain->dev, "no domain ID\n"); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = pm_genpd_init(&sub_domain->genpd, NULL, 0); -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n" -+ , np_child->name, ret); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = of_genpd_add_provider_simple(np_child, -+ &sub_domain->genpd); -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n" -+ , np_child->name, ret); -+ stm32_pm_domain_remove(sub_domain); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ ret = pm_genpd_add_subdomain(&domain->genpd, -+ &sub_domain->genpd); -+ -+ if (ret < 0) { -+ dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n" -+ , np_child->name, ret); -+ stm32_pm_domain_remove(sub_domain); -+ devm_kfree(dev, sub_domain); -+ continue; -+ } -+ -+ dev_info(sub_domain->dev, "subdomain %s registered\n", -+ np_child->name); -+ } -+} -+ -+static int stm32_pm_domain_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node, *child_np; -+ int ret; -+ -+ for_each_child_of_node(np, child_np) { -+ struct stm32_pm_domain *domain; -+ -+ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); -+ if (!domain) -+ continue; -+ -+ ret = stm32_pm_domain_add(domain, dev, child_np); -+ if (ret) { -+ devm_kfree(dev, domain); -+ continue; -+ } -+ -+ stm32_pm_subdomain_add(domain, dev, child_np); -+ } -+ -+ dev_info(dev, "domains probed\n"); -+ -+ return 0; -+} -+ -+static const struct of_device_id stm32_pm_domain_matches[] = { -+ { .compatible = "st,stm32mp157c-pd", }, -+ { }, -+}; -+ -+static struct platform_driver stm32_pm_domains_driver = { -+ .probe = stm32_pm_domain_probe, -+ .driver = { -+ .name = "stm32-pm-domain", -+ .of_match_table = stm32_pm_domain_matches, -+ }, -+}; -+ -+static int __init stm32_pm_domains_init(void) -+{ -+ return platform_driver_register(&stm32_pm_domains_driver); -+} -+core_initcall(stm32_pm_domains_init); -diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h -new file mode 100644 -index 0000000..d986653 ---- /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 */ --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch deleted file mode 100644 index 068759f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch +++ /dev/null @@ -1,1608 +0,0 @@ -From b40db75218cb1808125643c8e76b364d26ae2479 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:46 +0100 -Subject: [PATCH 24/31] ARM stm32mp1 r3 SPI - ---- - drivers/spi/Kconfig | 9 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-stm32-qspi.c | 733 +++++++++++++++++++++++++++++++++++++++++++ - drivers/spi/spi-stm32.c | 388 ++++++++++++++--------- - 4 files changed, 979 insertions(+), 152 deletions(-) - create mode 100644 drivers/spi/spi-stm32-qspi.c - -diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index 671d078..448d441 100644 ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -613,6 +613,15 @@ config SPI_STM32 - is not available, the driver automatically falls back to - PIO mode. - -+config SPI_STM32_QSPI -+ tristate "STMicroelectronics STM32 QUAD SPI controller" -+ depends on ARCH_STM32 || COMPILE_TEST -+ depends on OF -+ help -+ This enables support for the Quad SPI controller in master mode. -+ This driver does not support generic SPI. The implementation only -+ supports spi-mem interface. -+ - config SPI_ST_SSC4 - tristate "STMicroelectronics SPI SSC-based driver" - depends on ARCH_STI || COMPILE_TEST -diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -index a90d559..68a3c4e 100644 ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -90,6 +90,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o - obj-$(CONFIG_SPI_SIRF) += spi-sirf.o - obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o - obj-$(CONFIG_SPI_STM32) += spi-stm32.o -+obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o - obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o - obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o - obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o -diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c -new file mode 100644 -index 0000000..bf48b3f ---- /dev/null -+++ b/drivers/spi/spi-stm32-qspi.c -@@ -0,0 +1,733 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Ludovic Barre for STMicroelectronics. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define QSPI_CR 0x00 -+#define CR_EN BIT(0) -+#define CR_ABORT BIT(1) -+#define CR_DMAEN BIT(2) -+#define CR_TCEN BIT(3) -+#define CR_SSHIFT BIT(4) -+#define CR_DFM BIT(6) -+#define CR_FSEL BIT(7) -+#define CR_FTHRES_SHIFT 8 -+#define CR_TEIE BIT(16) -+#define CR_TCIE BIT(17) -+#define CR_FTIE BIT(18) -+#define CR_SMIE BIT(19) -+#define CR_TOIE BIT(20) -+#define CR_PRESC_MASK GENMASK(31, 24) -+ -+#define QSPI_DCR 0x04 -+#define DCR_FSIZE_MASK GENMASK(20, 16) -+ -+#define QSPI_SR 0x08 -+#define SR_TEF BIT(0) -+#define SR_TCF BIT(1) -+#define SR_FTF BIT(2) -+#define SR_SMF BIT(3) -+#define SR_TOF BIT(4) -+#define SR_BUSY BIT(5) -+#define SR_FLEVEL_MASK GENMASK(13, 8) -+ -+#define QSPI_FCR 0x0c -+#define FCR_CTEF BIT(0) -+#define FCR_CTCF BIT(1) -+ -+#define QSPI_DLR 0x10 -+ -+#define QSPI_CCR 0x14 -+#define CCR_INST_MASK GENMASK(7, 0) -+#define CCR_IMODE_MASK GENMASK(9, 8) -+#define CCR_ADMODE_MASK GENMASK(11, 10) -+#define CCR_ADSIZE_MASK GENMASK(13, 12) -+#define CCR_DCYC_MASK GENMASK(22, 18) -+#define CCR_DMODE_MASK GENMASK(25, 24) -+#define CCR_FMODE_MASK GENMASK(27, 26) -+#define CCR_FMODE_INDW (0U << 26) -+#define CCR_FMODE_INDR (1U << 26) -+#define CCR_FMODE_APM (2U << 26) -+#define CCR_FMODE_MM (3U << 26) -+#define CCR_BUSWIDTH_0 0x0 -+#define CCR_BUSWIDTH_1 0x1 -+#define CCR_BUSWIDTH_2 0x2 -+#define CCR_BUSWIDTH_4 0x3 -+ -+#define QSPI_AR 0x18 -+#define QSPI_ABR 0x1c -+#define QSPI_DR 0x20 -+#define QSPI_PSMKR 0x24 -+#define QSPI_PSMAR 0x28 -+#define QSPI_PIR 0x2c -+#define QSPI_LPTR 0x30 -+ -+#define STM32_QSPI_MAX_MMAP_SZ SZ_256M -+#define STM32_QSPI_MAX_NORCHIP 2 -+ -+#define STM32_FIFO_TIMEOUT_US 30000 -+#define STM32_BUSY_TIMEOUT_US 100000 -+#define STM32_ABT_TIMEOUT_US 100000 -+#define STM32_COMP_TIMEOUT_MS 1000 -+ -+struct stm32_qspi_flash { -+ struct stm32_qspi *qspi; -+ u32 cs; -+ u32 presc; -+}; -+ -+struct stm32_qspi { -+ struct device *dev; -+ phys_addr_t phys_base; -+ void __iomem *io_base; -+ void __iomem *mm_base; -+ resource_size_t mm_size; -+ struct clk *clk; -+ u32 clk_rate; -+ struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; -+ struct completion data_completion; -+ u32 fmode; -+ -+ struct dma_chan *dma_chtx; -+ struct dma_chan *dma_chrx; -+ struct completion dma_completion; -+ struct sg_table dma_sgt; -+ -+ u32 cr_reg; -+ u32 dcr_reg; -+ -+ /* -+ * to protect device configuration, could be different between -+ * 2 flash access (bk1, bk2) -+ */ -+ struct mutex lock; -+}; -+ -+static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) -+{ -+ struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; -+ u32 cr, sr; -+ -+ sr = readl_relaxed(qspi->io_base + QSPI_SR); -+ -+ if (sr & (SR_TEF | SR_TCF)) { -+ /* disable irq */ -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); -+ cr &= ~CR_TCIE & ~CR_TEIE; -+ writel_relaxed(cr, qspi->io_base + QSPI_CR); -+ complete(&qspi->data_completion); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) -+{ -+ *val = readb_relaxed(addr); -+} -+ -+static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) -+{ -+ writeb_relaxed(*val, addr); -+} -+ -+static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, -+ const struct spi_mem_op *op) -+{ -+ void (*tx_fifo)(u8 *val, void __iomem *addr); -+ u32 len = op->data.nbytes, sr; -+ u8 *buf; -+ int ret; -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ tx_fifo = stm32_qspi_read_fifo; -+ buf = op->data.buf.in; -+ -+ } else { -+ tx_fifo = stm32_qspi_write_fifo; -+ buf = (u8 *)op->data.buf.out; -+ } -+ -+ while (len--) { -+ ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, -+ sr, (sr & SR_FTF), 1, -+ STM32_FIFO_TIMEOUT_US); -+ if (ret) { -+ dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n", -+ len, sr); -+ return ret; -+ } -+ tx_fifo(buf++, qspi->io_base + QSPI_DR); -+ } -+ -+ return 0; -+} -+ -+static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, -+ const struct spi_mem_op *op) -+{ -+ memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val, -+ op->data.nbytes); -+ return 0; -+} -+ -+static void stm32_qspi_dma_callback(void *arg) -+{ -+ struct completion *dma_completion = arg; -+ -+ complete(dma_completion); -+} -+ -+static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, -+ const struct spi_mem_op *op) -+{ -+ struct dma_async_tx_descriptor *desc; -+ enum dma_transfer_direction dma_dir; -+ enum dma_data_direction map_dir; -+ bool addr_valid, vmalloced_buf; -+ unsigned int dma_max_seg_size; -+ struct scatterlist *sg; -+ struct dma_chan *dma_ch; -+ struct page *vm_page; -+ dma_cookie_t cookie; -+ u32 cr, len, t_out; -+ int i, err, nents, desc_len; -+ u8 *buf; -+ -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ map_dir = DMA_FROM_DEVICE; -+ dma_dir = DMA_DEV_TO_MEM; -+ dma_ch = qspi->dma_chrx; -+ buf = op->data.buf.in; -+ } else { -+ map_dir = DMA_TO_DEVICE; -+ dma_dir = DMA_MEM_TO_DEV; -+ dma_ch = qspi->dma_chtx; -+ buf = (u8 *)op->data.buf.out; -+ } -+ -+ /* the stm32 dma could tx MAX_DMA_BLOCK_LEN */ -+ dma_max_seg_size = dma_get_max_seg_size(dma_ch->device->dev); -+ len = op->data.nbytes; -+ -+ vmalloced_buf = is_vmalloc_addr(buf); -+ addr_valid = virt_addr_valid(buf); -+ if (addr_valid) { -+ desc_len = dma_max_seg_size; -+ nents = DIV_ROUND_UP(len, desc_len); -+ } else { -+ desc_len = min_t(int, dma_max_seg_size, PAGE_SIZE); -+ nents = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); -+ } -+ -+ if (nents != qspi->dma_sgt.nents) { -+ sg_free_table(&qspi->dma_sgt); -+ -+ err = sg_alloc_table(&qspi->dma_sgt, nents, GFP_KERNEL); -+ if (err) -+ return err; -+ } -+ -+ for_each_sg(qspi->dma_sgt.sgl, sg, nents, i) { -+ size_t bytes; -+ -+ if (addr_valid) { -+ bytes = min_t(size_t, len, desc_len); -+ sg_set_buf(sg, buf, bytes); -+ } else { -+ bytes = min_t(size_t, len, -+ desc_len - offset_in_page(buf)); -+ if (vmalloced_buf) -+ vm_page = vmalloc_to_page(buf); -+ else -+ vm_page = kmap_to_page(buf); -+ if (!vm_page) { -+ sg_free_table(&qspi->dma_sgt); -+ return -ENOMEM; -+ } -+ sg_set_page(sg, vm_page, bytes, -+ offset_in_page(buf)); -+ } -+ -+ buf += bytes; -+ len -= bytes; -+ } -+ -+ if (dma_map_sg(qspi->dev, qspi->dma_sgt.sgl, nents, map_dir) != nents) -+ return -ENOMEM; -+ -+ desc = dmaengine_prep_slave_sg(dma_ch, qspi->dma_sgt.sgl, nents, -+ dma_dir, DMA_PREP_INTERRUPT); -+ if (!desc) { -+ err = -ENOMEM; -+ goto out_unmap; -+ } -+ -+ reinit_completion(&qspi->dma_completion); -+ desc->callback = stm32_qspi_dma_callback; -+ desc->callback_param = &qspi->dma_completion; -+ cookie = dmaengine_submit(desc); -+ err = dma_submit_error(cookie); -+ if (err) -+ goto out_unmap; -+ -+ dma_async_issue_pending(dma_ch); -+ -+ writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); -+ -+ t_out = nents * STM32_COMP_TIMEOUT_MS; -+ if (!wait_for_completion_timeout(&qspi->dma_completion, -+ msecs_to_jiffies(t_out))) -+ err = -ETIMEDOUT; -+ -+ if (err) -+ dmaengine_terminate_all(dma_ch); -+ -+out_unmap: -+ writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); -+ dma_unmap_sg(qspi->dev, qspi->dma_sgt.sgl, nents, map_dir); -+ -+ return err; -+} -+ -+static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) -+{ -+ if (!op->data.nbytes) -+ return 0; -+ -+ if (qspi->fmode == CCR_FMODE_MM) -+ return stm32_qspi_tx_mm(qspi, op); -+ else if (op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) -+ return stm32_qspi_tx_dma(qspi, op); -+ else if (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx) -+ return stm32_qspi_tx_dma(qspi, op); -+ -+ return stm32_qspi_tx_poll(qspi, op); -+} -+ -+static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) -+{ -+ u32 sr; -+ -+ return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr, -+ !(sr & SR_BUSY), 1, -+ STM32_BUSY_TIMEOUT_US); -+} -+ -+static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, -+ const struct spi_mem_op *op) -+{ -+ u32 cr, sr; -+ int err = 0; -+ -+ if (!op->data.nbytes) -+ return stm32_qspi_wait_nobusy(qspi); -+ -+ if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) -+ goto out; -+ -+ reinit_completion(&qspi->data_completion); -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); -+ writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); -+ -+ if (!wait_for_completion_timeout(&qspi->data_completion, -+ msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { -+ err = -ETIMEDOUT; -+ } else { -+ sr = readl_relaxed(qspi->io_base + QSPI_SR); -+ if (sr & SR_TEF) -+ err = -EIO; -+ } -+ -+out: -+ /* clear flags */ -+ writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR); -+ -+ return err; -+} -+ -+static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) -+{ -+ if (buswidth == 4) -+ return CCR_BUSWIDTH_4; -+ -+ return buswidth; -+} -+ -+static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) -+{ -+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); -+ struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; -+ u32 ccr, cr, addr_max; -+ int timeout, err = 0; -+ -+ dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", -+ op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, -+ op->dummy.buswidth, op->data.buswidth, -+ op->addr.val, op->data.nbytes); -+ -+ err = stm32_qspi_wait_nobusy(qspi); -+ if (err) -+ goto abort; -+ -+ addr_max = op->addr.val + op->data.nbytes + 1; -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ if (addr_max < qspi->mm_size && -+ op->addr.buswidth) -+ qspi->fmode = CCR_FMODE_MM; -+ else -+ qspi->fmode = CCR_FMODE_INDR; -+ } else { -+ qspi->fmode = CCR_FMODE_INDW; -+ } -+ -+ cr = readl_relaxed(qspi->io_base + QSPI_CR); -+ cr &= ~CR_PRESC_MASK & ~CR_FSEL; -+ cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); -+ cr |= FIELD_PREP(CR_FSEL, flash->cs); -+ writel_relaxed(cr, qspi->io_base + QSPI_CR); -+ -+ if (op->data.nbytes) -+ writel_relaxed(op->data.nbytes - 1, -+ qspi->io_base + QSPI_DLR); -+ else -+ qspi->fmode = CCR_FMODE_INDW; -+ -+ ccr = qspi->fmode; -+ ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); -+ ccr |= FIELD_PREP(CCR_IMODE_MASK, -+ stm32_qspi_get_mode(qspi, op->cmd.buswidth)); -+ -+ if (op->addr.nbytes) { -+ ccr |= FIELD_PREP(CCR_ADMODE_MASK, -+ stm32_qspi_get_mode(qspi, op->addr.buswidth)); -+ ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1); -+ } -+ -+ if (op->dummy.buswidth && op->dummy.nbytes) -+ ccr |= FIELD_PREP(CCR_DCYC_MASK, -+ op->dummy.nbytes * 8 / op->dummy.buswidth); -+ -+ if (op->data.nbytes) { -+ ccr |= FIELD_PREP(CCR_DMODE_MASK, -+ stm32_qspi_get_mode(qspi, op->data.buswidth)); -+ } -+ -+ writel_relaxed(ccr, qspi->io_base + QSPI_CCR); -+ -+ if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) -+ writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); -+ -+ err = stm32_qspi_tx(qspi, op); -+ -+ /* -+ * Abort in: -+ * -error case -+ * -read memory map: prefetching must be stopped if we read the last -+ * byte of device (device size - fifo size). like device size is not -+ * knows, the prefetching is always stop. -+ */ -+ if (err || qspi->fmode == CCR_FMODE_MM) -+ goto abort; -+ -+ /* wait end of tx in indirect mode */ -+ err = stm32_qspi_wait_cmd(qspi, op); -+ if (err) -+ goto abort; -+ -+ return 0; -+ -+abort: -+ cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT; -+ writel_relaxed(cr, qspi->io_base + QSPI_CR); -+ -+ /* wait clear of abort bit by hw */ -+ timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR, -+ cr, !(cr & CR_ABORT), 1, -+ STM32_ABT_TIMEOUT_US); -+ -+ writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); -+ -+ if (err || timeout) -+ dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", -+ __func__, err, timeout); -+ -+ return err; -+} -+ -+static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) -+{ -+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); -+ int ret; -+ -+ mutex_lock(&qspi->lock); -+ ret = stm32_qspi_send(mem, op); -+ mutex_unlock(&qspi->lock); -+ -+ return ret; -+} -+ -+static int stm32_qspi_setup(struct spi_device *spi) -+{ -+ struct spi_controller *ctrl = spi->master; -+ struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); -+ struct stm32_qspi_flash *flash; -+ u32 presc; -+ -+ if (ctrl->busy) -+ return -EBUSY; -+ -+ if (!spi->max_speed_hz) -+ return -EINVAL; -+ -+ presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; -+ -+ flash = &qspi->flash[spi->chip_select]; -+ flash->qspi = qspi; -+ flash->cs = spi->chip_select; -+ flash->presc = presc; -+ -+ mutex_lock(&qspi->lock); -+ qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; -+ writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); -+ -+ /* set dcr fsize to max address */ -+ qspi->dcr_reg = DCR_FSIZE_MASK; -+ writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); -+ mutex_unlock(&qspi->lock); -+ -+ return 0; -+} -+ -+static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) -+{ -+ struct dma_slave_config dma_cfg; -+ struct device *dev = qspi->dev; -+ int ret; -+ -+ memset(&dma_cfg, 0, sizeof(dma_cfg)); -+ -+ dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; -+ dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; -+ dma_cfg.src_addr = qspi->phys_base + QSPI_DR; -+ dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; -+ dma_cfg.src_maxburst = 4; -+ dma_cfg.dst_maxburst = 4; -+ -+ qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); -+ if (qspi->dma_chrx) { -+ ret = dmaengine_slave_config(qspi->dma_chrx, &dma_cfg); -+ if (ret) { -+ dev_err(dev, "dma rx config failed\n"); -+ dma_release_channel(qspi->dma_chrx); -+ qspi->dma_chrx = NULL; -+ } -+ } -+ -+ qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); -+ if (qspi->dma_chtx) { -+ ret = dmaengine_slave_config(qspi->dma_chtx, &dma_cfg); -+ if (ret) { -+ dev_err(dev, "dma tx config failed\n"); -+ dma_release_channel(qspi->dma_chtx); -+ qspi->dma_chtx = NULL; -+ } -+ } -+ -+ init_completion(&qspi->dma_completion); -+} -+ -+static void stm32_qspi_dma_free(struct stm32_qspi *qspi) -+{ -+ if (qspi->dma_chtx) -+ dma_release_channel(qspi->dma_chtx); -+ if (qspi->dma_chrx) -+ dma_release_channel(qspi->dma_chrx); -+} -+ -+/* -+ * no special host constraint, so use default spi_mem_default_supports_op -+ * to check supported mode. -+ */ -+static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { -+ .exec_op = stm32_qspi_exec_op, -+}; -+ -+static void stm32_qspi_release(struct stm32_qspi *qspi) -+{ -+ /* disable qspi */ -+ writel_relaxed(0, qspi->io_base + QSPI_CR); -+ stm32_qspi_dma_free(qspi); -+ sg_free_table(&qspi->dma_sgt); -+ mutex_destroy(&qspi->lock); -+ clk_disable_unprepare(qspi->clk); -+} -+ -+static int stm32_qspi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct spi_controller *ctrl; -+ struct reset_control *rstc; -+ struct stm32_qspi *qspi; -+ struct resource *res; -+ int ret, irq; -+ -+ ctrl = spi_alloc_master(dev, sizeof(*qspi)); -+ if (!ctrl) -+ return -ENOMEM; -+ -+ qspi = spi_controller_get_devdata(ctrl); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); -+ qspi->io_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(qspi->io_base)) -+ return PTR_ERR(qspi->io_base); -+ -+ qspi->phys_base = res->start; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); -+ qspi->mm_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(qspi->mm_base)) -+ return PTR_ERR(qspi->mm_base); -+ -+ qspi->mm_size = resource_size(res); -+ if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) -+ return -EINVAL; -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ if (irq != -EPROBE_DEFER) -+ dev_err(dev, "IRQ error missing or invalid\n"); -+ return irq; -+ } -+ -+ ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, -+ dev_name(dev), qspi); -+ if (ret) { -+ dev_err(dev, "failed to request irq\n"); -+ return ret; -+ } -+ -+ init_completion(&qspi->data_completion); -+ -+ qspi->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(qspi->clk)) -+ return PTR_ERR(qspi->clk); -+ -+ qspi->clk_rate = clk_get_rate(qspi->clk); -+ if (!qspi->clk_rate) -+ return -EINVAL; -+ -+ ret = clk_prepare_enable(qspi->clk); -+ if (ret) { -+ dev_err(dev, "can not enable the clock\n"); -+ return ret; -+ } -+ -+ rstc = devm_reset_control_get_exclusive(dev, NULL); -+ if (!IS_ERR(rstc)) { -+ reset_control_assert(rstc); -+ udelay(2); -+ reset_control_deassert(rstc); -+ } -+ -+ qspi->dev = dev; -+ platform_set_drvdata(pdev, qspi); -+ stm32_qspi_dma_setup(qspi); -+ mutex_init(&qspi->lock); -+ -+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -+ | SPI_TX_DUAL | SPI_TX_QUAD; -+ ctrl->setup = stm32_qspi_setup; -+ ctrl->bus_num = -1; -+ ctrl->mem_ops = &stm32_qspi_mem_ops; -+ ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; -+ ctrl->dev.of_node = dev->of_node; -+ -+ ret = devm_spi_register_master(dev, ctrl); -+ if (ret) -+ goto err_spi_register; -+ -+ return 0; -+ -+err_spi_register: -+ stm32_qspi_release(qspi); -+ -+ return ret; -+} -+ -+static int stm32_qspi_remove(struct platform_device *pdev) -+{ -+ struct stm32_qspi *qspi = platform_get_drvdata(pdev); -+ -+ stm32_qspi_release(qspi); -+ return 0; -+} -+ -+static int __maybe_unused stm32_qspi_suspend(struct device *dev) -+{ -+ struct stm32_qspi *qspi = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(qspi->clk); -+ pinctrl_pm_select_sleep_state(dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused stm32_qspi_resume(struct device *dev) -+{ -+ struct stm32_qspi *qspi = dev_get_drvdata(dev); -+ -+ pinctrl_pm_select_default_state(dev); -+ clk_prepare_enable(qspi->clk); -+ -+ writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); -+ writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); -+ -+ return 0; -+} -+ -+SIMPLE_DEV_PM_OPS(stm32_qspi_pm_ops, stm32_qspi_suspend, stm32_qspi_resume); -+ -+static const struct of_device_id stm32_qspi_match[] = { -+ {.compatible = "st,stm32f469-qspi"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, stm32_qspi_match); -+ -+static struct platform_driver stm32_qspi_driver = { -+ .probe = stm32_qspi_probe, -+ .remove = stm32_qspi_remove, -+ .driver = { -+ .name = "stm32-qspi", -+ .of_match_table = stm32_qspi_match, -+ .pm = &stm32_qspi_pm_ops, -+ }, -+}; -+module_platform_driver(stm32_qspi_driver); -+ -+MODULE_AUTHOR("Ludovic Barre "); -+MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c -index ad1e55d..b088764 100644 ---- a/drivers/spi/spi-stm32.c -+++ b/drivers/spi/spi-stm32.c -@@ -18,6 +18,7 @@ - * You should have received a copy of the GNU General Public License along with - * spi_stm32 driver. If not, see . - */ -+#include - #include - #include - #include -@@ -26,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -54,27 +56,23 @@ - #define SPI_CR1_SSI BIT(12) - - /* STM32_SPI_CR2 bit fields */ --#define SPI_CR2_TSIZE_SHIFT 0 - #define SPI_CR2_TSIZE GENMASK(15, 0) -+#define SPI_CR2_TSER GENMASK(31, 16) -+#define SPI_TSIZE_MAX FIELD_GET(SPI_CR2_TSIZE, SPI_CR2_TSIZE) -+#define SPI_TSER_MAX FIELD_GET(SPI_CR2_TSER, SPI_CR2_TSER) - - /* STM32_SPI_CFG1 bit fields */ --#define SPI_CFG1_DSIZE_SHIFT 0 - #define SPI_CFG1_DSIZE GENMASK(4, 0) --#define SPI_CFG1_FTHLV_SHIFT 5 - #define SPI_CFG1_FTHLV GENMASK(8, 5) - #define SPI_CFG1_RXDMAEN BIT(14) - #define SPI_CFG1_TXDMAEN BIT(15) --#define SPI_CFG1_MBR_SHIFT 28 - #define SPI_CFG1_MBR GENMASK(30, 28) - #define SPI_CFG1_MBR_MIN 0 --#define SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) -+#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) - - /* STM32_SPI_CFG2 bit fields */ --#define SPI_CFG2_MIDI_SHIFT 4 - #define SPI_CFG2_MIDI GENMASK(7, 4) --#define SPI_CFG2_COMM_SHIFT 17 - #define SPI_CFG2_COMM GENMASK(18, 17) --#define SPI_CFG2_SP_SHIFT 19 - #define SPI_CFG2_SP GENMASK(21, 19) - #define SPI_CFG2_MASTER BIT(22) - #define SPI_CFG2_LSBFRST BIT(23) -@@ -90,17 +88,17 @@ - #define SPI_IER_EOTIE BIT(3) - #define SPI_IER_TXTFIE BIT(4) - #define SPI_IER_OVRIE BIT(6) --#define SPI_IER_MODFIE BIT(9) -+#define SPI_IER_TSERFIE BIT(10) - #define SPI_IER_ALL GENMASK(10, 0) - - /* 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_MODF BIT(9) -+#define SPI_SR_TSERF BIT(10) - #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) - -@@ -120,8 +118,6 @@ - #define SPI_SIMPLEX_RX 2 - #define SPI_HALF_DUPLEX 3 - --#define SPI_1HZ_NS 1000000000 -- - /** - * struct stm32_spi - private data of the SPI controller - * @dev: driver model representation of the controller -@@ -139,6 +135,7 @@ - * @cur_fthlv: fifo threshold level (data frames in a single data packet) - * @cur_comm: SPI communication mode - * @cur_xferlen: current transfer length in bytes -+ * @cur_reload: current transfer remaining bytes to be loaded - * @cur_usedma: boolean to know if dma is used in current transfer - * @tx_buf: data to be written, or NULL - * @rx_buf: data to be read, or NULL -@@ -165,6 +162,7 @@ struct stm32_spi { - unsigned int cur_fthlv; - unsigned int cur_comm; - unsigned int cur_xferlen; -+ unsigned int cur_reload; - bool cur_usedma; - - const void *tx_buf; -@@ -173,7 +171,10 @@ struct stm32_spi { - int rx_len; - struct dma_chan *dma_tx; - struct dma_chan *dma_rx; -+ struct completion dma_completion; - dma_addr_t phys_addr; -+ struct completion xfer_completion; -+ int xfer_status; - }; - - static inline void stm32_spi_set_bits(struct stm32_spi *spi, -@@ -233,8 +234,7 @@ static int stm32_spi_get_bpw_mask(struct stm32_spi *spi) - stm32_spi_set_bits(spi, STM32_SPI_CFG1, SPI_CFG1_DSIZE); - - cfg1 = readl_relaxed(spi->base + STM32_SPI_CFG1); -- max_bpw = (cfg1 & SPI_CFG1_DSIZE) >> SPI_CFG1_DSIZE_SHIFT; -- max_bpw += 1; -+ max_bpw = FIELD_GET(SPI_CFG1_DSIZE, cfg1) + 1; - - spin_unlock_irqrestore(&spi->lock, flags); - -@@ -254,7 +254,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) - { - u32 div, mbrdiv; - -- div = DIV_ROUND_UP(spi->clk_rate, speed_hz); -+ /* Ensure spi->clk_rate is even */ -+ div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz); - - /* - * SPI framework set xfer->speed_hz to master->max_speed_hz if -@@ -282,19 +283,22 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) - * stm32_spi_prepare_fthlv - Determine FIFO threshold level - * @spi: pointer to the spi controller data structure - */ --static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi) -+static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len) - { -- u32 fthlv, half_fifo; -+ u32 fthlv, half_fifo, packet; - - /* data packet should not exceed 1/2 of fifo space */ - half_fifo = (spi->fifo_size / 2); - -+ /* data_packet should not exceed transfer length */ -+ packet = (half_fifo > xfer_len) ? xfer_len : half_fifo; -+ - if (spi->cur_bpw <= 8) -- fthlv = half_fifo; -+ fthlv = packet; - else if (spi->cur_bpw <= 16) -- fthlv = half_fifo / 2; -+ fthlv = packet / 2; - else -- fthlv = half_fifo / 4; -+ fthlv = packet / 4; - - /* align packet size with data registers access */ - if (spi->cur_bpw > 8) -@@ -302,9 +306,28 @@ static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi) - else - fthlv -= (fthlv % 4); /* multiple of 4 */ - -+ if (!fthlv) -+ fthlv = 1; -+ - return fthlv; - } - -+static void stm32_spi_transfer_extension(struct stm32_spi *spi) -+{ -+ if (spi->cur_reload > 0) { -+ u32 cr2 = readl_relaxed(spi->base + STM32_SPI_CR2); -+ u32 tsize = FIELD_GET(SPI_CR2_TSIZE, cr2); -+ u32 tser = SPI_TSER_MAX - (SPI_TSER_MAX % spi->cur_fthlv); -+ -+ tser = min(spi->cur_reload, tser); -+ -+ writel_relaxed(FIELD_PREP(SPI_CR2_TSER, tser) | -+ FIELD_PREP(SPI_CR2_TSIZE, tsize), -+ spi->base + STM32_SPI_CR2); -+ spi->cur_reload -= tser; -+ } -+} -+ - /** - * stm32_spi_write_txfifo - Write bytes in Transmit Data Register - * @spi: pointer to the spi controller data structure -@@ -346,24 +369,24 @@ static void stm32_spi_write_txfifo(struct stm32_spi *spi) - * Write in rx_buf depends on remaining bytes to avoid to write beyond - * rx_buf end. - */ --static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush) -+static void stm32_spi_read_rxfifo(struct stm32_spi *spi) - { - u32 sr = readl_relaxed(spi->base + STM32_SPI_SR); -- u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; -+ u32 rxplvl = FIELD_GET(SPI_SR_RXPLVL, sr); - - while ((spi->rx_len > 0) && - ((sr & SPI_SR_RXP) || -- (flush && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { -+ ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { - u32 offs = spi->cur_xferlen - spi->rx_len; - -- if ((spi->rx_len >= sizeof(u32)) || -- (flush && (sr & SPI_SR_RXWNE))) { -+ if ((spi->rx_len >= sizeof(u32)) || (sr & SPI_SR_RXWNE)) { - u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); - - *rx_buf32 = readl_relaxed(spi->base + STM32_SPI_RXDR); - spi->rx_len -= sizeof(u32); - } else if ((spi->rx_len >= sizeof(u16)) || -- (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { -+ (!(sr & SPI_SR_RXWNE) && -+ (rxplvl >= 2 || spi->cur_bpw > 8))) { - u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); - - *rx_buf16 = readw_relaxed(spi->base + STM32_SPI_RXDR); -@@ -376,11 +399,11 @@ static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush) - } - - sr = readl_relaxed(spi->base + STM32_SPI_SR); -- rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; -+ rxplvl = FIELD_GET(SPI_SR_RXPLVL, sr); - } - -- dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, -- flush ? "(flush)" : "", spi->rx_len); -+ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", -+ __func__, spi->rx_len, sr); - } - - /** -@@ -402,8 +425,7 @@ static void stm32_spi_enable(struct stm32_spi *spi) - * @spi: pointer to the spi controller data structure - * - * RX-Fifo is flushed when SPI controller is disabled. To prevent any data -- * loss, use stm32_spi_read_rxfifo(flush) to read the remaining bytes in -- * RX-Fifo. -+ * loss, use stm32_spi_read_rxfifo to read the remaining bytes in RX-Fifo. - */ - static void stm32_spi_disable(struct stm32_spi *spi) - { -@@ -438,7 +460,7 @@ static void stm32_spi_disable(struct stm32_spi *spi) - } - - if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) -- stm32_spi_read_rxfifo(spi, true); -+ stm32_spi_read_rxfifo(spi); - - if (spi->cur_usedma && spi->tx_buf) - dmaengine_terminate_all(spi->dma_tx); -@@ -483,7 +505,7 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) - { - struct spi_master *master = dev_id; - struct stm32_spi *spi = spi_master_get_devdata(master); -- u32 sr, ier, mask; -+ u32 sr, ier, mask, ifcr; - unsigned long flags; - bool end = false; - -@@ -491,77 +513,81 @@ static irqreturn_t stm32_spi_irq(int irq, void *dev_id) - - sr = readl_relaxed(spi->base + STM32_SPI_SR); - ier = readl_relaxed(spi->base + STM32_SPI_IER); -+ ifcr = 0; - - mask = ier; -- /* EOTIE is triggered on EOT, SUSP and TXC events. */ -+ /* -+ * EOTIE enables irq from EOT, SUSP and TXC events. We need to set -+ * SUSP to acknowledge it later. TXC is automatically cleared -+ */ - mask |= SPI_SR_SUSP; - /* -- * When TXTF is set, DXPIE and TXPIE are cleared. So in case of -- * Full-Duplex, need to poll RXP event to know if there are remaining -- * data, before disabling SPI. -+ * DXPIE is set in Full-Duplex, one IT will be raised if TXP and RXP -+ * are set. So in case of Full-Duplex, need to poll TXP and RXP event. - */ -- if (spi->rx_buf && !spi->cur_usedma) -- mask |= SPI_SR_RXP; -+ if ((spi->cur_comm == SPI_FULL_DUPLEX) && (!spi->cur_usedma)) -+ mask |= SPI_SR_TXP | SPI_SR_RXP; - -- if (!(sr & mask)) { -- dev_dbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", -- sr, ier); -+ mask &= sr; -+ -+ if (!mask) { -+ dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", -+ sr, ier); - spin_unlock_irqrestore(&spi->lock, flags); - return IRQ_NONE; - } - -- if (sr & SPI_SR_SUSP) { -- dev_warn(spi->dev, "Communication suspended\n"); -+ if (mask & SPI_SR_TSERF) { -+ stm32_spi_transfer_extension(spi); -+ ifcr |= SPI_SR_TSERF; -+ } -+ -+ if (mask & SPI_SR_SUSP) { -+ dev_warn_once(spi->dev, -+ "System too slow is limiting data throughput\n"); -+ - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32_spi_read_rxfifo(spi, false); -- /* -- * If communication is suspended while using DMA, it means -- * that something went wrong, so stop the current transfer -- */ -- if (spi->cur_usedma) -- end = true; -+ stm32_spi_read_rxfifo(spi); -+ -+ ifcr |= SPI_SR_SUSP; - } - -- if (sr & SPI_SR_MODF) { -- dev_warn(spi->dev, "Mode fault: transfer aborted\n"); -+ if (mask & SPI_SR_OVR) { -+ dev_err(spi->dev, "Overrun: RX data lost\n"); -+ spi->xfer_status = -EIO; - end = true; -+ ifcr |= SPI_SR_OVR; - } - -- if (sr & SPI_SR_OVR) { -- dev_warn(spi->dev, "Overrun: received value discarded\n"); -- if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32_spi_read_rxfifo(spi, false); -- /* -- * If overrun is detected while using DMA, it means that -- * something went wrong, so stop the current transfer -- */ -- if (spi->cur_usedma) -- end = true; -- } -+ if (mask & SPI_SR_TXTF) -+ ifcr |= SPI_SR_TXTF; - -- if (sr & SPI_SR_EOT) { -+ if (mask & SPI_SR_EOT) { - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32_spi_read_rxfifo(spi, true); -+ stm32_spi_read_rxfifo(spi); - end = true; -+ ifcr |= SPI_SR_EOT; - } - -- if (sr & SPI_SR_TXP) -+ if (mask & SPI_SR_TXP) - if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) - stm32_spi_write_txfifo(spi); - -- if (sr & SPI_SR_RXP) -+ if (mask & SPI_SR_RXP) - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32_spi_read_rxfifo(spi, false); -- -- writel_relaxed(mask, spi->base + STM32_SPI_IFCR); -- -- spin_unlock_irqrestore(&spi->lock, flags); -+ stm32_spi_read_rxfifo(spi); - - if (end) { -- spi_finalize_current_transfer(master); -- stm32_spi_disable(spi); -+ /* Disable interrupts and clear status flags */ -+ writel_relaxed(0, spi->base + STM32_SPI_IER); -+ writel_relaxed(SPI_IFCR_ALL, spi->base + STM32_SPI_IFCR); -+ -+ complete(&spi->xfer_completion); -+ } else { -+ writel_relaxed(ifcr, spi->base + STM32_SPI_IFCR); - } - -+ spin_unlock_irqrestore(&spi->lock, flags); - return IRQ_HANDLED; - } - -@@ -642,25 +668,18 @@ static int stm32_spi_prepare_msg(struct spi_master *master, - /** - * stm32_spi_dma_cb - dma callback - * -- * DMA callback is called when the transfer is complete or when an error -- * occurs. If the transfer is complete, EOT flag is raised. -+ * DMA callback is called when the transfer is complete. - */ - static void stm32_spi_dma_cb(void *data) - { - struct stm32_spi *spi = data; - unsigned long flags; -- u32 sr; - - spin_lock_irqsave(&spi->lock, flags); - -- sr = readl_relaxed(spi->base + STM32_SPI_SR); -+ complete(&spi->dma_completion); - - spin_unlock_irqrestore(&spi->lock, flags); -- -- if (!(sr & SPI_SR_EOT)) -- dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); -- -- /* Now wait for EOT, or SUSP or OVR in case of error */ - } - - /** -@@ -709,11 +728,8 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, - /** - * stm32_spi_transfer_one_irq - transfer a single spi_transfer using - * interrupts -- * -- * It must returns 0 if the transfer is finished or 1 if the transfer is still -- * in progress. - */ --static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) -+static void stm32_spi_transfer_one_irq(struct stm32_spi *spi) - { - unsigned long flags; - u32 ier = 0; -@@ -727,7 +743,9 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) - ier |= SPI_IER_RXPIE; - - /* Enable the interrupts relative to the end of transfer */ -- ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE | SPI_IER_MODFIE; -+ ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE; -+ /* Enable the interrupt relative to transfer extension */ -+ ier |= SPI_IER_TSERFIE; - - spin_lock_irqsave(&spi->lock, flags); - -@@ -742,19 +760,15 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi) - writel_relaxed(ier, spi->base + STM32_SPI_IER); - - spin_unlock_irqrestore(&spi->lock, flags); -- -- return 1; - } - - /** - * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA -- * -- * It must returns 0 if the transfer is finished or 1 if the transfer is still -- * in progress. - */ --static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, -- struct spi_transfer *xfer) -+static void stm32_spi_transfer_one_dma(struct stm32_spi *spi, -+ struct spi_transfer *xfer) - { -+ dma_async_tx_callback rx_done = NULL, tx_done = NULL; - struct dma_slave_config tx_dma_conf, rx_dma_conf; - struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc; - unsigned long flags; -@@ -762,6 +776,13 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - - spin_lock_irqsave(&spi->lock, flags); - -+ if (spi->rx_buf) -+ rx_done = stm32_spi_dma_cb; -+ else if (spi->tx_buf) -+ tx_done = stm32_spi_dma_cb; -+ -+ reinit_completion(&spi->dma_completion); -+ - rx_dma_desc = NULL; - if (spi->rx_buf) { - stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); -@@ -794,7 +815,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - goto dma_desc_error; - - if (rx_dma_desc) { -- rx_dma_desc->callback = stm32_spi_dma_cb; -+ rx_dma_desc->callback = rx_done; - rx_dma_desc->callback_param = spi; - - if (dma_submit_error(dmaengine_submit(rx_dma_desc))) { -@@ -807,7 +828,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - - if (tx_dma_desc) { - if (spi->cur_comm == SPI_SIMPLEX_TX) { -- tx_dma_desc->callback = stm32_spi_dma_cb; -+ tx_dma_desc->callback = tx_done; - tx_dma_desc->callback_param = spi; - } - -@@ -823,7 +844,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - } - - /* Enable the interrupts relative to the end of transfer */ -- ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE | SPI_IER_MODFIE; -+ ier |= SPI_IER_EOTIE | SPI_IER_TXTFIE | SPI_IER_OVRIE; -+ /* Enable the interrupt relative to transfer extension */ -+ ier |= SPI_IER_TSERFIE; - writel_relaxed(ier, spi->base + STM32_SPI_IER); - - stm32_spi_enable(spi); -@@ -832,7 +855,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - - spin_unlock_irqrestore(&spi->lock, flags); - -- return 1; -+ return; - - dma_submit_error: - if (spi->rx_buf) -@@ -845,7 +868,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - - dev_info(spi->dev, "DMA issue: fall back to irq transfer\n"); - -- return stm32_spi_transfer_one_irq(spi); -+ spi->cur_usedma = false; -+ stm32_spi_transfer_one_irq(spi); - } - - /** -@@ -859,26 +883,26 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, - { - unsigned long flags; - u32 cfg1_clrb = 0, cfg1_setb = 0, cfg2_clrb = 0, cfg2_setb = 0; -- u32 mode, nb_words; -+ u32 fthlv, mode, nb_words, tsize; - int ret = 0; - - spin_lock_irqsave(&spi->lock, flags); - - if (spi->cur_bpw != transfer->bits_per_word) { -- u32 bpw, fthlv; -+ u32 bpw; - - spi->cur_bpw = transfer->bits_per_word; - bpw = spi->cur_bpw - 1; - - cfg1_clrb |= SPI_CFG1_DSIZE; -- cfg1_setb |= (bpw << SPI_CFG1_DSIZE_SHIFT) & SPI_CFG1_DSIZE; -+ cfg1_setb |= FIELD_PREP(SPI_CFG1_DSIZE, bpw); -+ } - -- spi->cur_fthlv = stm32_spi_prepare_fthlv(spi); -- fthlv = spi->cur_fthlv - 1; -+ spi->cur_fthlv = stm32_spi_prepare_fthlv(spi, transfer->len); -+ fthlv = spi->cur_fthlv - 1; - -- cfg1_clrb |= SPI_CFG1_FTHLV; -- cfg1_setb |= (fthlv << SPI_CFG1_FTHLV_SHIFT) & SPI_CFG1_FTHLV; -- } -+ cfg1_clrb |= SPI_CFG1_FTHLV; -+ cfg1_setb |= FIELD_PREP(SPI_CFG1_FTHLV, fthlv); - - if (spi->cur_speed != transfer->speed_hz) { - int mbr; -@@ -893,7 +917,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, - transfer->speed_hz = spi->cur_speed; - - cfg1_clrb |= SPI_CFG1_MBR; -- cfg1_setb |= ((u32)mbr << SPI_CFG1_MBR_SHIFT) & SPI_CFG1_MBR; -+ cfg1_setb |= FIELD_PREP(SPI_CFG1_MBR, (u32)mbr); - } - - if (cfg1_clrb || cfg1_setb) -@@ -924,19 +948,20 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, - spi->cur_comm = mode; - - cfg2_clrb |= SPI_CFG2_COMM; -- cfg2_setb |= (mode << SPI_CFG2_COMM_SHIFT) & SPI_CFG2_COMM; -+ cfg2_setb |= FIELD_PREP(SPI_CFG2_COMM, mode); - } - - cfg2_clrb |= SPI_CFG2_MIDI; - if ((transfer->len > 1) && (spi->cur_midi > 0)) { -- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); -- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -- (u32)SPI_CFG2_MIDI >> SPI_CFG2_MIDI_SHIFT); -+ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed); -+ u32 midi = min_t(u32, -+ DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -+ FIELD_GET(SPI_CFG2_MIDI, SPI_CFG2_MIDI)); - - dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", - sck_period_ns, midi, midi * sck_period_ns); - -- cfg2_setb |= (midi << SPI_CFG2_MIDI_SHIFT) & SPI_CFG2_MIDI; -+ cfg2_setb |= FIELD_PREP(SPI_CFG2_MIDI, midi); - } - - if (cfg2_clrb || cfg2_setb) -@@ -950,15 +975,20 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, - nb_words = DIV_ROUND_UP(transfer->len * 8, 16); - else - nb_words = DIV_ROUND_UP(transfer->len * 8, 32); -- nb_words <<= SPI_CR2_TSIZE_SHIFT; - -- if (nb_words <= SPI_CR2_TSIZE) { -- writel_relaxed(nb_words, spi->base + STM32_SPI_CR2); -+ if (nb_words <= SPI_TSIZE_MAX) { -+ tsize = nb_words; -+ spi->cur_reload = 0; - } else { -- ret = -EMSGSIZE; -- goto out; -+ tsize = SPI_TSIZE_MAX - (SPI_TSIZE_MAX % spi->cur_fthlv); -+ spi->cur_reload = nb_words - tsize; - } - -+ writel_relaxed(FIELD_PREP(SPI_CR2_TSIZE, tsize), -+ spi->base + STM32_SPI_CR2); -+ if (spi->cur_reload > 0) -+ stm32_spi_transfer_extension(spi); -+ - spi->cur_xferlen = transfer->len; - - dev_dbg(spi->dev, "transfer communication mode set to %d\n", -@@ -989,6 +1019,8 @@ static int stm32_spi_transfer_one(struct spi_master *master, - struct spi_transfer *transfer) - { - struct stm32_spi *spi = spi_master_get_devdata(master); -+ u32 xfer_time, midi_delay_ns; -+ unsigned long timeout; - int ret; - - spi->tx_buf = transfer->tx_buf; -@@ -1005,10 +1037,36 @@ static int stm32_spi_transfer_one(struct spi_master *master, - return ret; - } - -+ reinit_completion(&spi->xfer_completion); -+ spi->xfer_status = 0; -+ - if (spi->cur_usedma) -- return stm32_spi_transfer_one_dma(spi, transfer); -+ stm32_spi_transfer_one_dma(spi, transfer); - else -- return stm32_spi_transfer_one_irq(spi); -+ stm32_spi_transfer_one_irq(spi); -+ -+ /* Wait for transfer to complete */ -+ xfer_time = spi->cur_xferlen * 8 * MSEC_PER_SEC / spi->cur_speed; -+ midi_delay_ns = spi->cur_xferlen * 8 / spi->cur_bpw * spi->cur_midi; -+ xfer_time += DIV_ROUND_UP(midi_delay_ns, NSEC_PER_MSEC); -+ xfer_time = max(2 * xfer_time, 100U); -+ timeout = msecs_to_jiffies(xfer_time); -+ -+ timeout = wait_for_completion_timeout(&spi->xfer_completion, timeout); -+ if (timeout && spi->cur_usedma) -+ timeout = wait_for_completion_timeout(&spi->dma_completion, -+ timeout); -+ -+ if (!timeout) { -+ dev_err(spi->dev, "SPI transfer timeout (%u ms)\n", xfer_time); -+ spi->xfer_status = -ETIMEDOUT; -+ } -+ -+ stm32_spi_disable(spi); -+ -+ spi_finalize_current_transfer(master); -+ -+ return spi->xfer_status; - } - - /** -@@ -1076,7 +1134,7 @@ static int stm32_spi_probe(struct platform_device *pdev) - struct spi_master *master; - struct stm32_spi *spi; - struct resource *res; -- int i, ret; -+ int i, ret, num_cs, cs_gpio; - - master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); - if (!master) { -@@ -1089,6 +1147,8 @@ static int stm32_spi_probe(struct platform_device *pdev) - spi->dev = &pdev->dev; - spi->master = master; - spin_lock_init(&spi->lock); -+ init_completion(&spi->xfer_completion); -+ init_completion(&spi->dma_completion); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - spi->base = devm_ioremap_resource(&pdev->dev, res); -@@ -1100,8 +1160,9 @@ static int stm32_spi_probe(struct platform_device *pdev) - - spi->irq = platform_get_irq(pdev, 0); - if (spi->irq <= 0) { -- dev_err(&pdev->dev, "no irq: %d\n", spi->irq); -- ret = -ENOENT; -+ ret = spi->irq; -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "failed to get irq: %d\n", ret); - goto err_master_put; - } - ret = devm_request_threaded_irq(&pdev->dev, spi->irq, NULL, -@@ -1179,36 +1240,33 @@ static int stm32_spi_probe(struct platform_device *pdev) - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - -- ret = devm_spi_register_master(&pdev->dev, master); -- if (ret) { -- dev_err(&pdev->dev, "spi master registration failed: %d\n", -- ret); -- goto err_dma_release; -- } -+ num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios"); - -- if (!master->cs_gpios) { -- dev_err(&pdev->dev, "no CS gpios available\n"); -- ret = -EINVAL; -- goto err_dma_release; -- } -- -- for (i = 0; i < master->num_chipselect; i++) { -- if (!gpio_is_valid(master->cs_gpios[i])) { -- dev_err(&pdev->dev, "%i is not a valid gpio\n", -- master->cs_gpios[i]); -- ret = -EINVAL; -+ for (i = 0; i < num_cs; i++) { -+ cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i); -+ if (cs_gpio == -EPROBE_DEFER) { -+ ret = -EPROBE_DEFER; - goto err_dma_release; - } - -- ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], -- DRIVER_NAME); -- if (ret) { -- dev_err(&pdev->dev, "can't get CS gpio %i\n", -- master->cs_gpios[i]); -- goto err_dma_release; -+ if (gpio_is_valid(cs_gpio)) { -+ ret = devm_gpio_request(&pdev->dev, cs_gpio, -+ DRIVER_NAME); -+ if (ret) { -+ dev_err(&pdev->dev, "can't get CS gpio %i\n", -+ cs_gpio); -+ goto err_dma_release; -+ } - } - } - -+ ret = spi_register_master(master); -+ if (ret) { -+ dev_err(&pdev->dev, "spi master registration failed: %d\n", -+ ret); -+ goto err_dma_release; -+ } -+ - dev_info(&pdev->dev, "driver initialized\n"); - - return 0; -@@ -1233,6 +1291,9 @@ static int stm32_spi_remove(struct platform_device *pdev) - struct spi_master *master = platform_get_drvdata(pdev); - struct stm32_spi *spi = spi_master_get_devdata(master); - -+ pm_runtime_get_sync(&pdev->dev); -+ -+ spi_unregister_master(master); - stm32_spi_disable(spi); - - if (master->dma_tx) -@@ -1242,7 +1303,12 @@ static int stm32_spi_remove(struct platform_device *pdev) - - clk_disable_unprepare(spi->clk); - -+ pm_runtime_put_noidle(&pdev->dev); - pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_dont_use_autosuspend(&pdev->dev); -+ -+ pinctrl_pm_select_sleep_state(&pdev->dev); - - return 0; - } -@@ -1255,13 +1321,18 @@ static int stm32_spi_runtime_suspend(struct device *dev) - - clk_disable_unprepare(spi->clk); - -- return 0; -+ return pinctrl_pm_select_sleep_state(dev); - } - - static int stm32_spi_runtime_resume(struct device *dev) - { - struct spi_master *master = dev_get_drvdata(dev); - struct stm32_spi *spi = spi_master_get_devdata(master); -+ int ret; -+ -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret) -+ return ret; - - return clk_prepare_enable(spi->clk); - } -@@ -1291,10 +1362,23 @@ static int stm32_spi_resume(struct device *dev) - return ret; - - ret = spi_master_resume(master); -- if (ret) -+ if (ret) { - clk_disable_unprepare(spi->clk); -+ return ret; -+ } - -- return ret; -+ ret = pm_runtime_get_sync(dev); -+ if (ret) { -+ dev_err(dev, "Unable to power device:%d\n", ret); -+ return ret; -+ } -+ -+ stm32_spi_config(spi); -+ -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ -+ return 0; - } - #endif - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch deleted file mode 100644 index caafc4a..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch +++ /dev/null @@ -1,689 +0,0 @@ -From 69f90684b9d271fe91b53862b3a760d91b0fe7e4 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:46 +0100 -Subject: [PATCH 25/31] ARM stm32mp1 r3 THERMAL - ---- - drivers/thermal/Kconfig | 2 +- - drivers/thermal/Makefile | 2 +- - drivers/thermal/st/Kconfig | 14 + - drivers/thermal/st/Makefile | 1 + - drivers/thermal/st/stm_thermal.c | 604 +++++++++++++++++++++++++++++++++++++++ - 5 files changed, 621 insertions(+), 2 deletions(-) - create mode 100644 drivers/thermal/st/stm_thermal.c - -diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig -index 0e69edc..5422523 100644 ---- a/drivers/thermal/Kconfig -+++ b/drivers/thermal/Kconfig -@@ -432,7 +432,7 @@ source "drivers/thermal/samsung/Kconfig" - endmenu - - menu "STMicroelectronics thermal drivers" --depends on ARCH_STI && OF -+depends on (ARCH_STI || ARCH_STM32) && OF - source "drivers/thermal/st/Kconfig" - endmenu - -diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile -index 610344e..82bb50d 100644 ---- a/drivers/thermal/Makefile -+++ b/drivers/thermal/Makefile -@@ -53,7 +53,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ - obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ - obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o - obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o --obj-$(CONFIG_ST_THERMAL) += st/ -+obj-y += st/ - obj-$(CONFIG_QCOM_TSENS) += qcom/ - obj-y += tegra/ - obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o -diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig -index 490fdbe..b80f9a9 100644 ---- a/drivers/thermal/st/Kconfig -+++ b/drivers/thermal/st/Kconfig -@@ -1,3 +1,7 @@ -+# -+# STMicroelectronics thermal drivers configuration -+# -+ - config ST_THERMAL - tristate "Thermal sensors on STMicroelectronics STi series of SoCs" - help -@@ -10,3 +14,13 @@ config ST_THERMAL_SYSCFG - config ST_THERMAL_MEMMAP - select ST_THERMAL - tristate "STi series memory mapped access based thermal sensors" -+ -+config STM32_THERMAL -+ tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs" -+ depends on MACH_STM32MP157 -+ default y -+ help -+ Support for thermal framework on STMicroelectronics STM32 series of -+ SoCs. This thermal driver allows to access to general thermal framework -+ functionalities and to acces to SoC sensor functionalities. This -+ configuration is fully dependent of MACH_STM32MP157. -diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile -index b388789..b2b9e9b 100644 ---- a/drivers/thermal/st/Makefile -+++ b/drivers/thermal/st/Makefile -@@ -1,3 +1,4 @@ - obj-$(CONFIG_ST_THERMAL) := st_thermal.o - obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o - obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o -+obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o -\ No newline at end of file -diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c -new file mode 100644 -index 0000000..8cafc37 ---- /dev/null -+++ b/drivers/thermal/st/stm_thermal.c -@@ -0,0 +1,604 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: David Hernandez Sanchez for -+ * STMicroelectronics. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../thermal_core.h" -+#include "../thermal_hwmon.h" -+ -+/* DTS register offsets */ -+#define DTS_CFGR1_OFFSET 0x0 -+#define DTS_T0VALR1_OFFSET 0x8 -+#define DTS_RAMPVALR_OFFSET 0X10 -+#define DTS_ITR1_OFFSET 0x14 -+#define DTS_DR_OFFSET 0x1C -+#define DTS_SR_OFFSET 0x20 -+#define DTS_ITENR_OFFSET 0x24 -+#define DTS_ICIFR_OFFSET 0x28 -+ -+/* DTS_CFGR1 register mask definitions */ -+#define HSREF_CLK_DIV_MASK GENMASK(30, 24) -+#define TS1_SMP_TIME_MASK GENMASK(19, 16) -+#define TS1_INTRIG_SEL_MASK GENMASK(11, 8) -+ -+/* DTS_T0VALR1 register mask definitions */ -+#define TS1_T0_MASK GENMASK(17, 16) -+#define TS1_FMT0_MASK GENMASK(15, 0) -+ -+/* DTS_RAMPVALR register mask definitions */ -+#define TS1_RAMP_COEFF_MASK GENMASK(15, 0) -+ -+/* DTS_ITR1 register mask definitions */ -+#define TS1_HITTHD_MASK GENMASK(31, 16) -+#define TS1_LITTHD_MASK GENMASK(15, 0) -+ -+/* DTS_DR register mask definitions */ -+#define TS1_MFREQ_MASK GENMASK(15, 0) -+ -+/* DTS_ITENR register mask definitions */ -+#define ITENR_MASK (GENMASK(2, 0) | GENMASK(6, 4)) -+/* DTS_ICIFR register mask definitions */ -+#define ICIFR_MASK (GENMASK(2, 0) | GENMASK(6, 4)) -+ -+/* Less significant bit position definitions */ -+#define TS1_T0_POS 16 -+#define TS1_HITTHD_POS 16 -+#define TS1_LITTHD_POS 0 -+#define HSREF_CLK_DIV_POS 24 -+ -+/* DTS_CFGR1 bit definitions */ -+#define TS1_EN BIT(0) -+#define TS1_START BIT(4) -+#define REFCLK_SEL BIT(20) -+#define REFCLK_LSE REFCLK_SEL -+#define Q_MEAS_OPT BIT(21) -+#define CALIBRATION_CONTROL Q_MEAS_OPT -+ -+/* DTS_SR bit definitions */ -+#define TS_RDY BIT(15) -+/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */ -+#define HIGH_THRESHOLD BIT(2) -+#define LOW_THRESHOLD BIT(1) -+ -+/* Constants */ -+#define ADJUST 100 -+#define ONE_MHZ 1000000 -+#define POLL_TIMEOUT 5000 -+#define STARTUP_TIME 40 -+#define TS1_T0_VAL0 30000 /* 30 celsius */ -+#define TS1_T0_VAL1 110000 /* 110 celsius */ -+#define NO_HW_TRIG 0 -+#define SAMPLING_TIME 15 -+ -+struct stm_thermal_sensor { -+ struct device *dev; -+ struct thermal_zone_device *th_dev; -+ enum thermal_device_mode mode; -+ struct clk *clk; -+ int irq; -+ void __iomem *base; -+ int t0, fmt0, ramp_coeff; -+ int low_en, high_en; -+}; -+ -+static void stm_thermal_disable_irq(struct stm_thermal_sensor *sensor) -+{ -+ u32 itenr; -+ -+ /* Disable IT generation */ -+ itenr = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); -+ itenr &= ~ITENR_MASK; -+ writel_relaxed(itenr, sensor->base + DTS_ITENR_OFFSET); -+} -+ -+static void stm_thermal_set_irq_state(struct stm_thermal_sensor *sensor) -+{ -+ u32 itenr; -+ -+ dev_dbg(sensor->dev, "low:%d high:%d\n", sensor->low_en, -+ sensor->high_en); -+ -+ /* Disable IT generation for low and high thresholds */ -+ itenr = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); -+ itenr &= ~(LOW_THRESHOLD | HIGH_THRESHOLD); -+ -+ if (sensor->low_en) -+ itenr |= HIGH_THRESHOLD; -+ -+ if (sensor->high_en) -+ itenr |= LOW_THRESHOLD; -+ -+ /* Enable interrupts */ -+ writel_relaxed(itenr, sensor->base + DTS_ITENR_OFFSET); -+} -+ -+static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata) -+{ -+ struct stm_thermal_sensor *sensor = sdata; -+ -+ dev_dbg(sensor->dev, "sr:%d\n", -+ readl_relaxed(sensor->base + DTS_SR_OFFSET)); -+ -+ stm_thermal_disable_irq(sensor); -+ -+ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); -+ -+ stm_thermal_set_irq_state(sensor); -+ -+ /* Acknoledge all DTS irqs */ -+ writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET); -+ -+ return IRQ_HANDLED; -+} -+ -+static int stm_sensor_power_on(struct stm_thermal_sensor *sensor) -+{ -+ int ret; -+ u32 value; -+ -+ /* Enable sensor */ -+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); -+ value |= TS1_EN; -+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); -+ -+ /* -+ * The DTS block can be enabled by setting TSx_EN bit in -+ * DTS_CFGRx register. It requires a startup time of -+ * 40μs. Use 5 ms as arbitrary timeout. -+ */ -+ ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET, -+ value, (value & TS_RDY), -+ STARTUP_TIME, POLL_TIMEOUT); -+ if (ret) -+ return ret; -+ -+ /* Start continuous measuring */ -+ value = readl_relaxed(sensor->base + -+ DTS_CFGR1_OFFSET); -+ value |= TS1_START; -+ writel_relaxed(value, sensor->base + -+ DTS_CFGR1_OFFSET); -+ -+ sensor->mode = THERMAL_DEVICE_ENABLED; -+ -+ return 0; -+} -+ -+static int stm_sensor_power_off(struct stm_thermal_sensor *sensor) -+{ -+ u32 value; -+ -+ sensor->mode = THERMAL_DEVICE_DISABLED; -+ -+ /* Stop measuring */ -+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); -+ value &= ~TS1_START; -+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); -+ -+ /* Ensure stop is taken into account */ -+ usleep_range(STARTUP_TIME, POLL_TIMEOUT); -+ -+ /* Disable sensor */ -+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); -+ value &= ~TS1_EN; -+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); -+ -+ /* Ensure disable is taken into account */ -+ return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value, -+ !(value & TS_RDY), -+ STARTUP_TIME, POLL_TIMEOUT); -+} -+ -+static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) -+{ -+ u32 value, clk_freq; -+ u32 prescaler; -+ -+ /* Figure out prescaler value for PCLK during calibration */ -+ clk_freq = clk_get_rate(sensor->clk); -+ if (!clk_freq) -+ return -EINVAL; -+ -+ /* calculate divider for maximum 1MHz PCLK */ -+ prescaler = clk_freq / ONE_MHZ + 1; -+ -+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); -+ -+ /* Clear prescaler */ -+ value &= ~HSREF_CLK_DIV_MASK; -+ -+ /* Set prescaler. pclk_freq/prescaler < 1MHz */ -+ value |= (prescaler << HSREF_CLK_DIV_POS) & HSREF_CLK_DIV_MASK; -+ -+ /* Select PCLK as reference clock */ -+ value &= ~REFCLK_SEL; -+ -+ /* Set maximal sampling time for better precision */ -+ value |= TS1_SMP_TIME_MASK; -+ -+ /* Measure with calibration */ -+ value &= ~CALIBRATION_CONTROL; -+ -+ /* select trigger */ -+ value &= ~TS1_INTRIG_SEL_MASK; -+ value |= NO_HW_TRIG; -+ -+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); -+ -+ return 0; -+} -+ -+/* Fill in DTS structure with factory sensor values */ -+static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) -+{ -+ /* Retrieve engineering calibration temperature */ -+ sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) & -+ TS1_T0_MASK; -+ if (!sensor->t0) -+ sensor->t0 = TS1_T0_VAL0; -+ else -+ sensor->t0 = TS1_T0_VAL1; -+ -+ /* Retrieve fmt0 and put it on Hz */ -+ sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base + -+ DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK); -+ -+ /* Retrieve ramp coefficient */ -+ sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) & -+ TS1_RAMP_COEFF_MASK; -+ -+ if (!sensor->fmt0 || !sensor->ramp_coeff) { -+ dev_err(sensor->dev, "%s: wrong setting\n", __func__); -+ return -EINVAL; -+ } -+ -+ dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC", -+ __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff); -+ -+ return 0; -+} -+ -+static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor, -+ int temp, u32 *th) -+{ -+ int freqM; -+ -+ /* Figure out the CLK_PTAT frequency for a given temperature */ -+ freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 + -+ sensor->fmt0; -+ -+ /* Figure out the threshold sample number */ -+ *th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM; -+ if (!*th) -+ return -EINVAL; -+ -+ dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th); -+ -+ return 0; -+} -+ -+/* Callback to get temperature from HW */ -+static int stm_thermal_get_temp(void *data, int *temp) -+{ -+ struct stm_thermal_sensor *sensor = data; -+ u32 periods; -+ int freqM, ret; -+ -+ if (sensor->mode != THERMAL_DEVICE_ENABLED) -+ return -EAGAIN; -+ -+ /* Retrieve the number of periods sampled */ -+ ret = readl_relaxed_poll_timeout(sensor->base + DTS_DR_OFFSET, periods, -+ (periods & TS1_MFREQ_MASK), -+ STARTUP_TIME, POLL_TIMEOUT); -+ if (ret) -+ return ret; -+ -+ /* Figure out the CLK_PTAT frequency */ -+ freqM = (clk_get_rate(sensor->clk) * SAMPLING_TIME) / periods; -+ if (!freqM) -+ return -EINVAL; -+ -+ /* Figure out the temperature in mili celsius */ -+ *temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0; -+ -+ dev_dbg(sensor->dev, "periods=0x%x t=%d mC", periods, *temp); -+ -+ return 0; -+} -+ -+static int stm_thermal_set_trips(void *data, int low, int high) -+{ -+ struct stm_thermal_sensor *sensor = data; -+ u32 itr1, th; -+ int ret; -+ -+ dev_dbg(sensor->dev, "set trips %d <--> %d\n", low, high); -+ -+ /* Erase threshold content */ -+ itr1 = readl_relaxed(sensor->base + DTS_ITR1_OFFSET); -+ itr1 &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK); -+ -+ /* -+ * Disable low-temp if "low" is too small. As per thermal framework -+ * API, we use -INT_MAX rather than INT_MIN. -+ */ -+ -+ if (low > -INT_MAX) { -+ sensor->low_en = 1; -+ /* add 0.5 of hysteresis due to measurement error */ -+ ret = stm_thermal_calculate_threshold(sensor, low - 500, &th); -+ if (ret) -+ return ret; -+ -+ itr1 |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS)); -+ } else { -+ sensor->low_en = 0; -+ } -+ -+ /* Disable high-temp if "high" is too big. */ -+ if (high < INT_MAX) { -+ sensor->high_en = 1; -+ ret = stm_thermal_calculate_threshold(sensor, high, &th); -+ if (ret) -+ return ret; -+ -+ itr1 |= (TS1_LITTHD_MASK & (th << TS1_LITTHD_POS)); -+ } else { -+ sensor->high_en = 0; -+ } -+ -+ /* Write new threshod values*/ -+ writel_relaxed(itr1, sensor->base + DTS_ITR1_OFFSET); -+ -+ return 0; -+} -+ -+/* Registers DTS irq to be visible by GIC */ -+static int stm_register_irq(struct stm_thermal_sensor *sensor) -+{ -+ struct device *dev = sensor->dev; -+ struct platform_device *pdev = to_platform_device(dev); -+ int ret; -+ -+ sensor->irq = platform_get_irq(pdev, 0); -+ if (sensor->irq < 0) { -+ dev_err(dev, "%s: Unable to find IRQ\n", __func__); -+ return sensor->irq; -+ } -+ -+ ret = devm_request_threaded_irq(dev, sensor->irq, -+ NULL, stm_thermal_alarm_irq_thread, -+ IRQF_ONESHOT, -+ dev->driver->name, sensor); -+ if (ret) { -+ dev_err(dev, "%s: Failed to register IRQ %d\n", __func__, -+ sensor->irq); -+ return ret; -+ } -+ -+ dev_dbg(dev, "%s: thermal IRQ registered", __func__); -+ -+ return 0; -+} -+ -+static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor) -+{ -+ int ret; -+ -+ stm_thermal_disable_irq(sensor); -+ -+ ret = stm_sensor_power_off(sensor); -+ if (ret) -+ return ret; -+ -+ clk_disable_unprepare(sensor->clk); -+ -+ return 0; -+} -+ -+static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) -+{ -+ int ret; -+ -+ ret = clk_prepare_enable(sensor->clk); -+ if (ret) -+ return ret; -+ -+ ret = stm_thermal_read_factory_settings(sensor); -+ if (ret) -+ goto thermal_unprepare; -+ -+ ret = stm_thermal_calibration(sensor); -+ if (ret) -+ goto thermal_unprepare; -+ -+ return 0; -+ -+thermal_unprepare: -+ clk_disable_unprepare(sensor->clk); -+ -+ return ret; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm_thermal_suspend(struct device *dev) -+{ -+ int ret; -+ struct platform_device *pdev = to_platform_device(dev); -+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); -+ -+ ret = stm_thermal_sensor_off(sensor); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int stm_thermal_resume(struct device *dev) -+{ -+ int ret; -+ struct platform_device *pdev = to_platform_device(dev); -+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); -+ -+ ret = stm_thermal_prepare(sensor); -+ if (ret) -+ return ret; -+ -+ ret = stm_sensor_power_on(sensor); -+ if (ret) -+ return ret; -+ -+ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); -+ stm_thermal_set_irq_state(sensor); -+ -+ return 0; -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume); -+ -+static const struct thermal_zone_of_device_ops stm_tz_ops = { -+ .get_temp = stm_thermal_get_temp, -+ .set_trips = stm_thermal_set_trips, -+}; -+ -+static const struct of_device_id stm_thermal_of_match[] = { -+ { .compatible = "st,stm32-thermal"}, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, stm_thermal_of_match); -+ -+static int stm_thermal_probe(struct platform_device *pdev) -+{ -+ struct stm_thermal_sensor *sensor; -+ struct resource *res; -+ void __iomem *base; -+ int ret; -+ -+ if (!pdev->dev.of_node) { -+ dev_err(&pdev->dev, "%s: device tree node not found\n", -+ __func__); -+ return -EINVAL; -+ } -+ -+ sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, sensor); -+ -+ sensor->dev = &pdev->dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ /* Populate sensor */ -+ sensor->base = base; -+ -+ sensor->clk = devm_clk_get(&pdev->dev, "pclk"); -+ if (IS_ERR(sensor->clk)) { -+ dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n", -+ __func__); -+ return PTR_ERR(sensor->clk); -+ } -+ -+ stm_thermal_disable_irq(sensor); -+ -+ /* Clear irq flags */ -+ writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET); -+ -+ /* Configure and enable HW sensor */ -+ ret = stm_thermal_prepare(sensor); -+ if (ret) { -+ dev_err(&pdev->dev, "Error preprare sensor: %d\n", ret); -+ return ret; -+ } -+ -+ ret = stm_sensor_power_on(sensor); -+ if (ret) { -+ dev_err(&pdev->dev, "Error power on sensor: %d\n", ret); -+ return ret; -+ } -+ -+ sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, -+ sensor, -+ &stm_tz_ops); -+ -+ if (IS_ERR(sensor->th_dev)) { -+ dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n", -+ __func__); -+ ret = PTR_ERR(sensor->th_dev); -+ return ret; -+ } -+ -+ /* Register IRQ into GIC */ -+ ret = stm_register_irq(sensor); -+ if (ret) -+ goto err_tz; -+ -+ stm_thermal_set_irq_state(sensor); -+ -+ /* -+ * Thermal_zone doesn't enable hwmon as default, -+ * enable it here -+ */ -+ sensor->th_dev->tzp->no_hwmon = false; -+ ret = thermal_add_hwmon_sysfs(sensor->th_dev); -+ if (ret) -+ goto err_tz; -+ -+ dev_info(&pdev->dev, "%s: Driver initialized successfully\n", -+ __func__); -+ -+ return 0; -+ -+err_tz: -+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); -+ return ret; -+} -+ -+static int stm_thermal_remove(struct platform_device *pdev) -+{ -+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); -+ -+ stm_thermal_sensor_off(sensor); -+ thermal_remove_hwmon_sysfs(sensor->th_dev); -+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); -+ -+ return 0; -+} -+ -+static struct platform_driver stm_thermal_driver = { -+ .driver = { -+ .name = "stm_thermal", -+ .pm = &stm_thermal_pm_ops, -+ .of_match_table = stm_thermal_of_match, -+ }, -+ .probe = stm_thermal_probe, -+ .remove = stm_thermal_remove, -+}; -+module_platform_driver(stm_thermal_driver); -+ -+MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver"); -+MODULE_AUTHOR("David Hernandez Sanchez "); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:stm_thermal"); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch deleted file mode 100644 index a3a6140..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch +++ /dev/null @@ -1,3889 +0,0 @@ -From 6e8d34490963467552ebe1a996e0ad78b4e560ba Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:47 +0100 -Subject: [PATCH 26/31] ARM stm32mp1 r3 TTY USB - ---- - drivers/tty/serial/stm32-usart.c | 758 ++++++++++++++++++++------- - drivers/tty/serial/stm32-usart.h | 48 +- - drivers/usb/dwc2/Makefile | 2 +- - drivers/usb/dwc2/core.c | 123 +++-- - drivers/usb/dwc2/core.h | 50 ++ - drivers/usb/dwc2/debugfs.c | 1 + - drivers/usb/dwc2/drd.c | 191 +++++++ - drivers/usb/dwc2/gadget.c | 99 +++- - drivers/usb/dwc2/hcd.c | 36 +- - drivers/usb/dwc2/hw.h | 25 + - drivers/usb/dwc2/params.c | 40 ++ - drivers/usb/dwc2/platform.c | 166 +++++- - drivers/usb/gadget/function/u_serial.c | 35 +- - drivers/usb/host/ehci-platform.c | 59 +++ - drivers/usb/typec/Kconfig | 9 + - drivers/usb/typec/Makefile | 1 + - drivers/usb/typec/class.c | 15 + - drivers/usb/typec/typec_stusb.c | 918 +++++++++++++++++++++++++++++++++ - include/linux/usb/typec.h | 1 + - 19 files changed, 2265 insertions(+), 312 deletions(-) - create mode 100644 drivers/usb/dwc2/drd.c - create mode 100644 drivers/usb/typec/typec_stusb.c - -diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index e8d7a7b..c6acbcf 100644 ---- a/drivers/tty/serial/stm32-usart.c -+++ b/drivers/tty/serial/stm32-usart.c -@@ -24,6 +24,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -105,9 +107,7 @@ static int stm32_config_rs485(struct uart_port *port, - struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 usartdiv, baud, cr1, cr3; - bool over8; -- unsigned long flags; - -- spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - - port->rs485 = *rs485conf; -@@ -147,7 +147,6 @@ static int stm32_config_rs485(struct uart_port *port, - } - - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -- spin_unlock_irqrestore(&port->lock, flags); - - return 0; - } -@@ -169,101 +168,193 @@ static int stm32_init_rs485(struct uart_port *port, - return 0; - } - --static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, -- bool threaded) -+/* Returns 1 when data is pending in pio mode and 0 when no data is pending. */ -+static int stm32_pending_rx_pio(struct uart_port *port, u32 *sr) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- enum dma_status status; -- struct dma_tx_state state; - - *sr = readl_relaxed(port->membase + ofs->isr); -+ /* Get pending characters in RDR or FIFO */ -+ if (*sr & USART_SR_RXNE) { -+ /* -+ * Get all pending characters from the RDR or the FIFO when -+ * using interrupts -+ */ -+ if (!stm32_port->rx_ch) -+ return 1; - -- if (threaded && stm32_port->rx_ch) { -- status = dmaengine_tx_status(stm32_port->rx_ch, -- stm32_port->rx_ch->cookie, -- &state); -- if ((status == DMA_IN_PROGRESS) && -- (*last_res != state.residue)) -+ /* Handle only RX data errors when using dma */ -+ if (*sr & USART_SR_ERR_MASK) - return 1; -- else -- return 0; -- } else if (*sr & USART_SR_RXNE) { -- return 1; - } -+ - return 0; - } - --static unsigned long --stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) -+static unsigned long stm32_get_char_pio(struct uart_port *port) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - unsigned long c; - -- if (stm32_port->rx_ch) { -- c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; -- if ((*last_res) == 0) -- *last_res = RX_BUF_L; -- return c; -- } else { -- return readl_relaxed(port->membase + ofs->rdr); -- } -+ c = readl_relaxed(port->membase + ofs->rdr); -+ /* Apply RDR data mask */ -+ c &= stm32_port->rdr_mask; -+ -+ return c; - } - --static void stm32_receive_chars(struct uart_port *port, bool threaded) -+static void stm32_receive_chars_pio(struct uart_port *port) - { -- struct tty_port *tport = &port->state->port; - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - unsigned long c; - u32 sr; - char flag; - -- if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) -- pm_wakeup_event(tport->tty->dev, 0); -- -- while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { -+ while (stm32_pending_rx_pio(port, &sr)) { - sr |= USART_SR_DUMMY_RX; -- c = stm32_get_char(port, &sr, &stm32_port->last_res); - flag = TTY_NORMAL; -- port->icount.rx++; - -+ /* -+ * Status bits has to be cleared before reading the RDR: -+ * In FIFO mode, reading the RDR will pop the next data -+ * (if any) along with its status bits into the SR. -+ * Not doing so leads to misalignement between RDR and SR, -+ * and clear status bits of the next rx data. -+ * -+ * Clear errors flags for stm32f7 and stm32h7 compatible -+ * devices. On stm32f4 compatible devices, the error bit is -+ * cleared by the sequence [read SR - read DR]. -+ */ -+ if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG) -+ writel_relaxed(sr & USART_SR_ERR_MASK, -+ port->membase + ofs->icr); -+ -+ c = stm32_get_char_pio(port); -+ port->icount.rx++; - if (sr & USART_SR_ERR_MASK) { -- if (sr & USART_SR_LBD) { -- port->icount.brk++; -- if (uart_handle_break(port)) -- continue; -- } else if (sr & USART_SR_ORE) { -- if (ofs->icr != UNDEF_REG) -- writel_relaxed(USART_ICR_ORECF, -- port->membase + -- ofs->icr); -+ if (sr & USART_SR_ORE) { - port->icount.overrun++; - } else if (sr & USART_SR_PE) { - port->icount.parity++; - } else if (sr & USART_SR_FE) { -- port->icount.frame++; -+ /* Break detection if character is null */ -+ if (!c) { -+ port->icount.brk++; -+ if (uart_handle_break(port)) -+ continue; -+ } else { -+ port->icount.frame++; -+ } - } - - sr &= port->read_status_mask; -- -- if (sr & USART_SR_LBD) -- flag = TTY_BREAK; -- else if (sr & USART_SR_PE) -+ if (sr & USART_SR_PE) { - flag = TTY_PARITY; -- else if (sr & USART_SR_FE) -- flag = TTY_FRAME; -+ } else if (sr & USART_SR_FE) { -+ if (!c) -+ flag = TTY_BREAK; -+ else -+ flag = TTY_FRAME; -+ } - } - - if (uart_handle_sysrq_char(port, c)) - continue; - uart_insert_char(port, sr, USART_SR_ORE, c, flag); - } -+} -+ -+static void stm32_push_buffer_dma(struct uart_port *port, -+ unsigned int dma_size) -+{ -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct tty_port *ttyport = &stm32_port->port.state->port; -+ unsigned char *dma_start; -+ int dma_count; -+ -+ dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); -+ dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); -+ port->icount.rx += dma_count; -+ stm32_port->last_res -= dma_count; -+ if (stm32_port->last_res == 0) -+ stm32_port->last_res = RX_BUF_L; -+} -+ -+static void stm32_receive_chars_dma(struct uart_port *port) -+{ -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ unsigned int dma_size; -+ -+ /* -+ * DMA buffer is configured in cyclic mode and handles the rollback of -+ * the buffer. -+ */ -+ if (stm32_port->state.residue > stm32_port->last_res) { -+ /* Conditional first part: from last_res to end of dma buffer */ -+ dma_size = stm32_port->last_res; -+ stm32_push_buffer_dma(port, dma_size); -+ } - -- spin_unlock(&port->lock); -+ dma_size = stm32_port->last_res - stm32_port->state.residue; -+ stm32_push_buffer_dma(port, dma_size); -+} -+ -+static void stm32_receive_chars(struct uart_port *port, bool threaded) -+{ -+ struct tty_port *tport = &port->state->port; -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -+ unsigned long flags = 0; -+ u32 sr; -+ -+ if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) -+ pm_wakeup_event(tport->tty->dev, 0); -+ -+ if (threaded) -+ spin_lock_irqsave(&port->lock, flags); -+ else -+ spin_lock(&port->lock); -+ -+ if (stm32_port->rx_ch) { -+ stm32_port->status = -+ dmaengine_tx_status(stm32_port->rx_ch, -+ stm32_port->rx_ch->cookie, -+ &stm32_port->state); -+ if (stm32_port->status == DMA_IN_PROGRESS) { -+ /* Empty DMA buffer */ -+ stm32_receive_chars_dma(port); -+ sr = readl_relaxed(port->membase + ofs->isr); -+ if (sr & USART_SR_ERR_MASK) { -+ /* Disable DMA request line */ -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ -+ /* Switch to PIO mode handle the errors */ -+ stm32_receive_chars_pio(port); -+ -+ /* Switch back to DMA mode */ -+ stm32_set_bits(port, ofs->cr3, USART_CR3_DMAR); -+ } -+ } else { -+ /* Disable rx DMA */ -+ dmaengine_terminate_async(stm32_port->rx_ch); -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ /* fall back to interrupt mode */ -+ dev_dbg(port->dev, -+ "DMA error, fallback to irq mode\n"); -+ stm32_receive_chars_pio(port); -+ } -+ } else { -+ stm32_receive_chars_pio(port); -+ } -+ -+ if (threaded) -+ spin_unlock_irqrestore(&port->lock, flags); -+ else -+ spin_unlock(&port->lock); - tty_flip_buffer_push(tport); -- spin_lock(&port->lock); - } - - static void stm32_tx_dma_complete(void *arg) -@@ -271,27 +362,23 @@ static void stm32_tx_dma_complete(void *arg) - struct uart_port *port = arg; - struct stm32_port *stm32port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; -- unsigned int isr; -- int ret; -- -- ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, -- isr, -- (isr & USART_SR_TC), -- 10, 100000); -- -- if (ret) -- dev_err(port->dev, "terminal count not set\n"); -- -- if (ofs->icr == UNDEF_REG) -- stm32_clr_bits(port, ofs->isr, USART_SR_TC); -- else -- stm32_set_bits(port, ofs->icr, USART_CR_TC); -+ unsigned long flags; - -+ dmaengine_terminate_async(stm32port->tx_ch); - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; - - /* Let's see if we have pending data to send */ -+ spin_lock_irqsave(&port->lock, flags); - stm32_transmit_chars(port); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static void stm32_rx_dma_complete(void *arg) -+{ -+ struct uart_port *port = arg; -+ -+ stm32_receive_chars(port, true); - } - - static void stm32_transmit_chars_pio(struct uart_port *port) -@@ -299,27 +386,30 @@ static void stm32_transmit_chars_pio(struct uart_port *port) - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; -- unsigned int isr; -- int ret; - - if (stm32_port->tx_dma_busy) { - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } - -- ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, -- isr, -- (isr & USART_SR_TXE), -- 10, 100000); -- -- if (ret) -- dev_err(port->dev, "tx empty not set\n"); -- -- stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ while (!uart_circ_empty(xmit)) { -+ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) -+ break; -+ writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ } - -- writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); -- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -- port->icount.tx++; -+ if (uart_circ_empty(xmit)) -+ if (stm32_port->fifoen) -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); -+ else -+ stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ else -+ if (stm32_port->fifoen) -+ stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); -+ else -+ stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); - } - - static void stm32_transmit_chars_dma(struct uart_port *port) -@@ -377,7 +467,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) - /* Issue pending DMA TX requests */ - dma_async_issue_pending(stm32port->tx_ch); - -- stm32_clr_bits(port, ofs->isr, USART_SR_TC); - stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); - - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); -@@ -401,15 +490,18 @@ static void stm32_transmit_chars(struct uart_port *port) - return; - } - -- if (uart_tx_stopped(port)) { -- stm32_stop_tx(port); -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ if (stm32_port->fifoen) -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); -+ else -+ stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); - return; - } - -- if (uart_circ_empty(xmit)) { -- stm32_stop_tx(port); -- return; -- } -+ if (ofs->icr == UNDEF_REG) -+ stm32_clr_bits(port, ofs->isr, USART_SR_TC); -+ else -+ writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); - - if (stm32_port->tx_ch) - stm32_transmit_chars_dma(port); -@@ -419,8 +511,12 @@ static void stm32_transmit_chars(struct uart_port *port) - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - -- if (uart_circ_empty(xmit)) -- stm32_stop_tx(port); -+ if (uart_circ_empty(xmit)) { -+ if (stm32_port->fifoen) -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); -+ else -+ stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ } - } - - static irqreturn_t stm32_interrupt(int irq, void *ptr) -@@ -430,21 +526,30 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - u32 sr; - -- spin_lock(&port->lock); -- - sr = readl_relaxed(port->membase + ofs->isr); - -+ if ((sr & USART_SR_RTOF) && (ofs->icr != UNDEF_REG)) -+ writel_relaxed(USART_ICR_RTOCF, -+ port->membase + ofs->icr); -+ - if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) - writel_relaxed(USART_ICR_WUCF, - port->membase + ofs->icr); - -- if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) -+ /* -+ * rx errors in dma mode has to be handled ASAP to avoid overrun as the -+ * DMA request line has been masked by HW and rx data are stacking in -+ * FIFO. -+ */ -+ if (((sr & USART_SR_RXNE) && !stm32_port->rx_ch) || -+ ((sr & USART_SR_ERR_MASK) && stm32_port->rx_ch)) - stm32_receive_chars(port, false); - -- if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) -+ if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { -+ spin_lock(&port->lock); - stm32_transmit_chars(port); -- -- spin_unlock(&port->lock); -+ spin_unlock(&port->lock); -+ } - - if (stm32_port->rx_ch) - return IRQ_WAKE_THREAD; -@@ -455,14 +560,9 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) - static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) - { - struct uart_port *port = ptr; -- struct stm32_port *stm32_port = to_stm32_port(port); - -- spin_lock(&port->lock); -- -- if (stm32_port->rx_ch) -- stm32_receive_chars(port, true); -- -- spin_unlock(&port->lock); -+ /* Receiver timeout irq for dma rx */ -+ stm32_receive_chars(port, true); - - return IRQ_HANDLED; - } -@@ -472,7 +572,10 @@ static unsigned int stm32_tx_empty(struct uart_port *port) - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - -- return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; -+ if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) -+ return TIOCSER_TEMT; -+ -+ return 0; - } - - static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) -@@ -498,7 +601,15 @@ static void stm32_stop_tx(struct uart_port *port) - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - -- stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ if (stm32_port->fifoen) -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); -+ else -+ stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ -+ if (stm32_port->tx_dma_busy) { -+ dmaengine_terminate_async(stm32_port->tx_ch); -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); -+ } - } - - /* There are probably characters waiting to be transmitted. */ -@@ -512,6 +623,23 @@ static void stm32_start_tx(struct uart_port *port) - stm32_transmit_chars(port); - } - -+/* Flush the transmit buffer. */ -+static void stm32_flush_buffer(struct uart_port *port) -+{ -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -+ -+ if (stm32_port->tx_ch) { -+ /* Avoid deadlock with the DMA engine callback */ -+ spin_unlock(&port->lock); -+ dmaengine_terminate_async(stm32_port->tx_ch); -+ spin_lock(&port->lock); -+ -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); -+ stm32_port->tx_dma_busy = false; -+ } -+} -+ - /* Throttle the remote when input buffer is about to overflow. */ - static void stm32_throttle(struct uart_port *port) - { -@@ -520,7 +648,10 @@ static void stm32_throttle(struct uart_port *port) - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); -- stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); -+ if (stm32_port->cr3_irq) -+ stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ -+ stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); - spin_unlock_irqrestore(&port->lock, flags); - } - -@@ -532,7 +663,10 @@ static void stm32_unthrottle(struct uart_port *port) - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); -- stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE); -+ if (stm32_port->cr3_irq) -+ stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ -+ stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq); - spin_unlock_irqrestore(&port->lock, flags); - } - -@@ -542,7 +676,10 @@ static void stm32_stop_rx(struct uart_port *port) - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - -- stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); -+ if (stm32_port->cr3_irq) -+ stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ -+ stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); - } - - /* Handle breaks - ignored by us */ -@@ -554,8 +691,9 @@ static int stm32_startup(struct uart_port *port) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- struct stm32_usart_config *cfg = &stm32_port->info->cfg; - const char *name = to_platform_device(port->dev)->name; -+ struct dma_async_tx_descriptor *desc = NULL; -+ dma_cookie_t cookie; - u32 val; - int ret; - -@@ -565,18 +703,35 @@ static int stm32_startup(struct uart_port *port) - if (ret) - return ret; - -- if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { -- ret = dev_pm_set_dedicated_wake_irq(port->dev, -- stm32_port->wakeirq); -- if (ret) { -- free_irq(port->irq, port); -- return ret; -+ /* RX FIFO Flush */ -+ if (ofs->rqr != UNDEF_REG) -+ stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); -+ -+ if (stm32_port->rx_ch) { -+ stm32_port->last_res = RX_BUF_L; -+ /* Prepare a DMA cyclic transaction */ -+ desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, -+ stm32_port->rx_dma_buf, -+ RX_BUF_L, RX_BUF_P, -+ DMA_DEV_TO_MEM, -+ DMA_PREP_INTERRUPT); -+ if (!desc) { -+ dev_err(port->dev, "rx dma prep cyclic failed\n"); -+ return -ENODEV; - } -+ -+ desc->callback = stm32_rx_dma_complete; -+ desc->callback_param = port; -+ -+ /* Push current DMA transaction in the pending queue */ -+ cookie = dmaengine_submit(desc); -+ -+ /* Issue pending DMA requests */ -+ dma_async_issue_pending(stm32_port->rx_ch); - } - -- val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; -- if (stm32_port->fifoen) -- val |= USART_CR1_FIFOEN; -+ /* RX enabling */ -+ val = stm32_port->cr1_irq | USART_CR1_RE; - stm32_set_bits(port, ofs->cr1, val); - - return 0; -@@ -587,18 +742,65 @@ static void stm32_shutdown(struct uart_port *port) - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; -- u32 val; -+ u32 val, isr; -+ int ret; - -- val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; -+ val = USART_CR1_TXEIE | USART_CR1_TE; -+ val |= stm32_port->cr1_irq | USART_CR1_RE; - val |= BIT(cfg->uart_enable_bit); - if (stm32_port->fifoen) - val |= USART_CR1_FIFOEN; -+ -+ ret = readl_relaxed_poll_timeout(port->membase + ofs->isr, -+ isr, -+ (isr & USART_SR_TC), -+ 10, 100000); -+ -+ if (ret) -+ dev_err(port->dev, "transmission complete not set\n"); -+ - stm32_clr_bits(port, ofs->cr1, val); - -- dev_pm_clear_wake_irq(port->dev); -+ if (stm32_port->fifoen) -+ stm32_clr_bits(port, ofs->cr3, -+ USART_CR3_TXFTIE | USART_CR3_RXFTIE); -+ -+ if (stm32_port->rx_ch) -+ dmaengine_terminate_async(stm32_port->rx_ch); -+ - free_irq(port->irq, port); - } - -+static int stm32_get_databits(struct ktermios *termios) -+{ -+ unsigned int bits; -+ -+ tcflag_t cflag = termios->c_cflag; -+ -+ switch (cflag & CSIZE) { -+ /* -+ * CSIZE settings are not necessarily supported in hardware. -+ * CSIZE unsupported configurations are handled here to set word length -+ * to 8 bits word as default configuration and to print debug message. -+ */ -+ case CS5: -+ bits = 5; -+ break; -+ case CS6: -+ bits = 6; -+ break; -+ case CS7: -+ bits = 7; -+ break; -+ /* default including CS8 */ -+ default: -+ bits = 8; -+ break; -+ } -+ -+ return (bits); -+} -+ - static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) - { -@@ -606,11 +808,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; - struct serial_rs485 *rs485conf = &port->rs485; -- unsigned int baud; -+ unsigned int baud, bits; - u32 usartdiv, mantissa, fraction, oversampling; - tcflag_t cflag = termios->c_cflag; -- u32 cr1, cr2, cr3; -+ u32 cr1, cr2, cr3, isr; - unsigned long flags; -+ int ret; - - if (!stm32_port->hw_flow_control) - cflag &= ~CRTSCTS; -@@ -619,29 +822,80 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - - spin_lock_irqsave(&port->lock, flags); - -+ ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, -+ isr, -+ (isr & USART_SR_TC), -+ 10, 100000); -+ -+ if (ret) -+ dev_err(port->dev, "transmission complete not set\n"); -+ - /* Stop serial port and reset value */ - writel_relaxed(0, port->membase + ofs->cr1); - -- cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; -+ /* flush RX & TX FIFO */ -+ if (ofs->rqr != UNDEF_REG) -+ stm32_set_bits(port, ofs->rqr, -+ USART_RQR_TXFRQ | USART_RQR_RXFRQ); - -+ cr1 = USART_CR1_TE | USART_CR1_RE; - if (stm32_port->fifoen) - cr1 |= USART_CR1_FIFOEN; - cr2 = 0; -- cr3 = 0; -+ -+ /* Tx and RX FIFO configuration */ -+ cr3 = readl_relaxed(port->membase + ofs->cr3); -+ cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; -+ if (stm32_port->fifoen) { -+ cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; -+ cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; -+ } - - if (cflag & CSTOPB) - cr2 |= USART_CR2_STOP_2B; - -+ bits = stm32_get_databits(termios); -+ stm32_port->rdr_mask = (BIT(bits) - 1); -+ - if (cflag & PARENB) { -+ bits++; - cr1 |= USART_CR1_PCE; -- if ((cflag & CSIZE) == CS8) { -- if (cfg->has_7bits_data) -- cr1 |= USART_CR1_M0; -- else -- cr1 |= USART_CR1_M; -- } - } - -+ /* Word length configuration: -+ * CS8 + parity, 9 bits word aka [M1:M0] = 0b01 -+ * CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10 -+ * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00 -+ * M0 and M1 already cleared by cr1 initialization. -+ */ -+ if (bits == 9) -+ cr1 |= USART_CR1_M0; -+ else if ((bits == 7) && cfg->has_7bits_data) -+ cr1 |= USART_CR1_M1; -+ else if (bits != 8) -+ dev_dbg(port->dev, "Unsupported data bits config: %u bits\n" -+ , bits); -+ -+ if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || -+ stm32_port->fifoen)) { -+ if (cflag & CSTOPB) -+ bits = bits + 3; /* 1 start bit + 2 stop bits */ -+ else -+ bits = bits + 2; /* 1 start bit + 1 stop bit */ -+ -+ /* RX timeout irq to occur after last stop bit + bits */ -+ stm32_port->cr1_irq = USART_CR1_RTOIE; -+ writel_relaxed(bits, port->membase + ofs->rtor); -+ cr2 |= USART_CR2_RTOEN; -+ -+ /* Not using dma, enable fifo threshold irq */ -+ if (!stm32_port->rx_ch) -+ stm32_port->cr3_irq = USART_CR3_RXFTIE; -+ } -+ -+ cr1 |= stm32_port->cr1_irq; -+ cr3 |= stm32_port->cr3_irq; -+ - if (cflag & PARODD) - cr1 |= USART_CR1_PS; - -@@ -679,14 +933,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - if (termios->c_iflag & INPCK) - port->read_status_mask |= USART_SR_PE | USART_SR_FE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) -- port->read_status_mask |= USART_SR_LBD; -+ port->read_status_mask |= USART_SR_FE; - - /* Characters to ignore */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask = USART_SR_PE | USART_SR_FE; - if (termios->c_iflag & IGNBRK) { -- port->ignore_status_mask |= USART_SR_LBD; -+ port->ignore_status_mask |= USART_SR_FE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). -@@ -699,8 +953,16 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= USART_SR_DUMMY_RX; - -- if (stm32_port->rx_ch) -+ if (stm32_port->rx_ch) { -+ /* -+ * Setup DMA to collect only valid data and enable error irqs. -+ * This also enables break reception when using dma. -+ */ -+ cr1 |= USART_CR1_PEIE; -+ cr3 |= USART_CR3_EIE; - cr3 |= USART_CR3_DMAR; -+ cr3 |= USART_CR3_DDRE; -+ } - - if (rs485conf->flags & SER_RS485_ENABLED) { - stm32_config_reg_rs485(&cr1, &cr3, -@@ -715,8 +977,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - } - - } else { -- cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); -- cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); -+ cr3 &= ~USART_CR3_DEM; -+ cr3 &= ~USART_CR3_DEP; -+ cr1 &= ~USART_CR1_DEDT_MASK; -+ cr1 &= ~USART_CR1_DEAT_MASK; - } - - writel_relaxed(cr3, port->membase + ofs->cr3); -@@ -765,13 +1029,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, - - switch (state) { - case UART_PM_STATE_ON: -- clk_prepare_enable(stm32port->clk); -+ pm_runtime_get_sync(port->dev); - break; - case UART_PM_STATE_OFF: - spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - spin_unlock_irqrestore(&port->lock, flags); -- clk_disable_unprepare(stm32port->clk); -+ pm_runtime_put_sync(port->dev); - break; - } - } -@@ -788,6 +1052,7 @@ static const struct uart_ops stm32_uart_ops = { - .break_ctl = stm32_break_ctl, - .startup = stm32_startup, - .shutdown = stm32_shutdown, -+ .flush_buffer = stm32_flush_buffer, - .set_termios = stm32_set_termios, - .pm = stm32_pm, - .type = stm32_type, -@@ -802,20 +1067,60 @@ static int stm32_init_port(struct stm32_port *stm32port, - { - struct uart_port *port = &stm32port->port; - struct resource *res; -+ struct pinctrl *uart_pinctrl; - int ret; - - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - port->ops = &stm32_uart_ops; - port->dev = &pdev->dev; -- port->irq = platform_get_irq(pdev, 0); -- port->rs485_config = stm32_config_rs485; - -+ ret = platform_get_irq_byname(pdev, "event"); -+ if (ret <= 0) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Can't get event IRQ: %d\n", -+ ret); -+ return ret ? ret : -ENODEV; -+ } -+ port->irq = ret; -+ -+ port->fifosize = stm32port->info->cfg.fifosize; -+ -+ port->rs485_config = stm32_config_rs485; - stm32_init_rs485(port, pdev); - -- stm32port->wakeirq = platform_get_irq(pdev, 1); -+ if (stm32port->info->cfg.has_wakeup) { -+ stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); -+ if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) { -+ if (stm32port->wakeirq != -EPROBE_DEFER) -+ dev_err(&pdev->dev, -+ "Can't get event wake IRQ: %d\n", -+ stm32port->wakeirq); -+ return stm32port->wakeirq ? stm32port->wakeirq : -+ -ENODEV; -+ } -+ } -+ - stm32port->fifoen = stm32port->info->cfg.has_fifo; - -+ uart_pinctrl = devm_pinctrl_get(&pdev->dev); -+ if (IS_ERR(uart_pinctrl)) { -+ ret = PTR_ERR(uart_pinctrl); -+ if (ret != -ENODEV) { -+ dev_err(&pdev->dev,"Can't get pinctrl, error %d\n", -+ ret); -+ return ret; -+ } -+ stm32port->console_pins = ERR_PTR(-ENODEV); -+ } -+ else -+ stm32port->console_pins = pinctrl_lookup_state -+ (uart_pinctrl,"no_console_suspend"); -+ -+ if (IS_ERR(stm32port->console_pins) -+ && PTR_ERR(stm32port->console_pins) != -ENODEV) -+ return PTR_ERR(stm32port->console_pins); -+ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(port->membase)) -@@ -862,7 +1167,11 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) - stm32_ports[id].hw_flow_control = of_property_read_bool(np, - "st,hw-flow-ctrl"); - stm32_ports[id].port.line = id; -+ stm32_ports[id].cr1_irq = USART_CR1_RXNEIE; -+ stm32_ports[id].cr3_irq = 0; - stm32_ports[id].last_res = RX_BUF_L; -+ stm32_ports[id].rx_dma_buf = 0; -+ stm32_ports[id].tx_dma_buf = 0; - return &stm32_ports[id]; - } - -@@ -884,15 +1193,15 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - struct uart_port *port = &stm32port->port; - struct device *dev = &pdev->dev; - struct dma_slave_config config; -- struct dma_async_tx_descriptor *desc = NULL; -- dma_cookie_t cookie; - int ret; - - /* Request DMA RX channel */ -- stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); -- if (!stm32port->rx_ch) { -- dev_info(dev, "rx dma alloc failed\n"); -- return -ENODEV; -+ stm32port->rx_ch = dma_request_chan_linked(dev, "rx"); -+ if (IS_ERR(stm32port->rx_ch)) { -+ ret = PTR_ERR(stm32port->rx_ch); -+ stm32port->rx_ch = NULL; -+ dev_dbg(dev, "cannot get the DMA channel.\n"); -+ return ret; - } - stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, - &stm32port->rx_dma_buf, -@@ -914,27 +1223,6 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - goto config_err; - } - -- /* Prepare a DMA cyclic transaction */ -- desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, -- stm32port->rx_dma_buf, -- RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, -- DMA_PREP_INTERRUPT); -- if (!desc) { -- dev_err(dev, "rx dma prep cyclic failed\n"); -- ret = -ENODEV; -- goto config_err; -- } -- -- /* No callback as dma buffer is drained on usart interrupt */ -- desc->callback = NULL; -- desc->callback_param = NULL; -- -- /* Push current DMA transaction in the pending queue */ -- cookie = dmaengine_submit(desc); -- -- /* Issue pending DMA requests */ -- dma_async_issue_pending(stm32port->rx_ch); -- - return 0; - - config_err: -@@ -943,7 +1231,7 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - stm32port->rx_dma_buf); - - alloc_err: -- dma_release_channel(stm32port->rx_ch); -+ dma_release_chan_linked(dev, stm32port->rx_ch); - stm32port->rx_ch = NULL; - - return ret; -@@ -963,7 +1251,7 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, - /* Request DMA TX channel */ - stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); - if (!stm32port->tx_ch) { -- dev_info(dev, "tx dma alloc failed\n"); -+ dev_dbg(dev, "cannot get the DMA channel.\n"); - return -ENODEV; - } - stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, -@@ -1020,15 +1308,18 @@ static int stm32_serial_probe(struct platform_device *pdev) - if (ret) - return ret; - -- if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) { -+ if (stm32port->wakeirq > 0) { - ret = device_init_wakeup(&pdev->dev, true); - if (ret) - goto err_uninit; -- } - -- ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); -- if (ret) -- goto err_nowup; -+ ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, -+ stm32port->wakeirq); -+ if (ret) -+ goto err_nowup; -+ -+ device_set_wakeup_enable(&pdev->dev, false); -+ } - - ret = stm32_of_dma_rx_probe(stm32port, pdev); - if (ret) -@@ -1040,10 +1331,41 @@ static int stm32_serial_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, &stm32port->port); - -+ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); -+ if (ret) -+ goto err_dma; -+ -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_put_sync(&pdev->dev); -+ - return 0; - -+err_dma: -+ if (stm32port->rx_ch) -+ dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); -+ -+ if (stm32port->rx_dma_buf) -+ dma_free_coherent(&pdev->dev, -+ RX_BUF_L, stm32port->rx_buf, -+ stm32port->rx_dma_buf); -+ -+ if (stm32port->tx_ch) { -+ dmaengine_terminate_async(stm32port->tx_ch); -+ dma_release_channel(stm32port->tx_ch); -+ } -+ -+ if (stm32port->tx_dma_buf) -+ dma_free_coherent(&pdev->dev, -+ TX_BUF_L, stm32port->tx_buf, -+ stm32port->tx_dma_buf); -+ -+ if (stm32port->wakeirq > 0) -+ dev_pm_clear_wake_irq(&pdev->dev); -+ - err_nowup: -- if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) -+ if (stm32port->wakeirq > 0) - device_init_wakeup(&pdev->dev, false); - - err_uninit: -@@ -1057,12 +1379,22 @@ static int stm32_serial_remove(struct platform_device *pdev) - struct uart_port *port = platform_get_drvdata(pdev); - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- struct stm32_usart_config *cfg = &stm32_port->info->cfg; -+ int err; -+ u32 cr3; - -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ pm_runtime_get_sync(&pdev->dev); -+ -+ err = uart_remove_one_port(&stm32_usart_driver, port); -+ -+ stm32_clr_bits(port, ofs->cr1, USART_CR1_PEIE); -+ cr3 = readl_relaxed(port->membase + ofs->cr3); -+ cr3 &= ~USART_CR3_EIE; -+ cr3 &= ~USART_CR3_DMAR; -+ cr3 &= ~USART_CR3_DDRE; -+ writel_relaxed(cr3, port->membase + ofs->cr3); - - if (stm32_port->rx_ch) -- dma_release_channel(stm32_port->rx_ch); -+ dma_release_chan_linked(&pdev->dev, stm32_port->rx_ch); - - if (stm32_port->rx_dma_buf) - dma_free_coherent(&pdev->dev, -@@ -1071,20 +1403,27 @@ static int stm32_serial_remove(struct platform_device *pdev) - - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - -- if (stm32_port->tx_ch) -+ if (stm32_port->tx_ch) { -+ dmaengine_terminate_async(stm32_port->tx_ch); - dma_release_channel(stm32_port->tx_ch); -+ } - - if (stm32_port->tx_dma_buf) - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32_port->tx_buf, - stm32_port->tx_dma_buf); - -- if (cfg->has_wakeup && stm32_port->wakeirq >= 0) -+ if (stm32_port->wakeirq > 0) { -+ dev_pm_clear_wake_irq(&pdev->dev); - device_init_wakeup(&pdev->dev, false); -+ } - - clk_disable_unprepare(stm32_port->clk); - -- return uart_remove_one_port(&stm32_usart_driver, port); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return err; - } - - -@@ -1195,7 +1534,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) - struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; - -- if (!cfg->has_wakeup || stm32_port->wakeirq < 0) -+ if (stm32_port->wakeirq <= 0) - return; - - if (enable) { -@@ -1207,21 +1546,36 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) - val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; - writel_relaxed(val, port->membase + ofs->cr3); - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ enable_irq_wake(stm32_port->wakeirq); - } else { - stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); -+ disable_irq_wake(stm32_port->wakeirq); - } - } - - static int stm32_serial_suspend(struct device *dev) - { - struct uart_port *port = dev_get_drvdata(dev); -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ -+ if (device_may_wakeup(dev) || dev->power.wakeup_path) -+ stm32_serial_enable_wakeup(port, true); - - uart_suspend_port(&stm32_usart_driver, port); - -- if (device_may_wakeup(dev)) -- stm32_serial_enable_wakeup(port, true); -- else -- stm32_serial_enable_wakeup(port, false); -+ if (uart_console(port) && !console_suspend_enabled) { -+ if (IS_ERR(stm32_port->console_pins)) { -+ dev_err(dev, "no_console_suspend pinctrl not found\n"); -+ return PTR_ERR(stm32_port->console_pins); -+ } -+ -+ pinctrl_select_state(dev->pins->p, stm32_port->console_pins); -+ } else { -+ if (device_may_wakeup(dev) || dev->power.wakeup_path) -+ pinctrl_pm_select_idle_state(dev); -+ else -+ pinctrl_pm_select_sleep_state(dev); -+ } - - return 0; - } -@@ -1230,14 +1584,40 @@ static int stm32_serial_resume(struct device *dev) - { - struct uart_port *port = dev_get_drvdata(dev); - -- if (device_may_wakeup(dev)) -+ pinctrl_pm_select_default_state(dev); -+ -+ if (device_may_wakeup(dev) || dev->power.wakeup_path) - stm32_serial_enable_wakeup(port, false); - - return uart_resume_port(&stm32_usart_driver, port); - } - #endif /* CONFIG_PM_SLEEP */ - -+#ifdef CONFIG_PM -+static int stm32_serial_runtime_suspend(struct device *dev) -+{ -+ struct uart_port *port = dev_get_drvdata(dev); -+ struct stm32_port *stm32port = container_of(port, -+ struct stm32_port, port); -+ -+ clk_disable_unprepare(stm32port->clk); -+ -+ return 0; -+} -+ -+static int stm32_serial_runtime_resume(struct device *dev) -+{ -+ struct uart_port *port = dev_get_drvdata(dev); -+ struct stm32_port *stm32port = container_of(port, -+ struct stm32_port, port); -+ -+ return clk_prepare_enable(stm32port->clk); -+} -+#endif /* CONFIG_PM */ -+ - static const struct dev_pm_ops stm32_serial_pm_ops = { -+ SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, -+ stm32_serial_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) - }; - -diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h -index 6f294e2..ddd87c9 100644 ---- a/drivers/tty/serial/stm32-usart.h -+++ b/drivers/tty/serial/stm32-usart.h -@@ -27,6 +27,7 @@ struct stm32_usart_config { - bool has_7bits_data; - bool has_wakeup; - bool has_fifo; -+ int fifosize; - }; - - struct stm32_usart_info { -@@ -54,6 +55,7 @@ struct stm32_usart_info stm32f4_info = { - .cfg = { - .uart_enable_bit = 13, - .has_7bits_data = false, -+ .fifosize = 1, - } - }; - -@@ -74,6 +76,7 @@ struct stm32_usart_info stm32f7_info = { - .cfg = { - .uart_enable_bit = 0, - .has_7bits_data = true, -+ .fifosize = 1, - } - }; - -@@ -96,19 +99,19 @@ struct stm32_usart_info stm32h7_info = { - .has_7bits_data = true, - .has_wakeup = true, - .has_fifo = true, -+ .fifosize = 16, - } - }; - - /* USART_SR (F4) / USART_ISR (F7) */ - #define USART_SR_PE BIT(0) - #define USART_SR_FE BIT(1) --#define USART_SR_NF BIT(2) -+#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ - #define USART_SR_ORE BIT(3) - #define USART_SR_IDLE BIT(4) - #define USART_SR_RXNE BIT(5) - #define USART_SR_TC BIT(6) - #define USART_SR_TXE BIT(7) --#define USART_SR_LBD BIT(8) - #define USART_SR_CTSIF BIT(9) - #define USART_SR_CTS BIT(10) /* F7 */ - #define USART_SR_RTOF BIT(11) /* F7 */ -@@ -120,14 +123,11 @@ struct stm32_usart_info stm32h7_info = { - #define USART_SR_SBKF BIT(18) /* F7 */ - #define USART_SR_WUF BIT(20) /* H7 */ - #define USART_SR_TEACK BIT(21) /* F7 */ --#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ -- USART_SR_FE | USART_SR_PE) -+#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE\ -+ | USART_SR_PE) - /* Dummy bits */ - #define USART_SR_DUMMY_RX BIT(16) - --/* USART_ICR (F7) */ --#define USART_CR_TC BIT(6) -- - /* USART_DR */ - #define USART_DR_MASK GENMASK(8, 0) - -@@ -151,8 +151,7 @@ struct stm32_usart_info stm32h7_info = { - #define USART_CR1_PS BIT(9) - #define USART_CR1_PCE BIT(10) - #define USART_CR1_WAKE BIT(11) --#define USART_CR1_M BIT(12) --#define USART_CR1_M0 BIT(12) /* F7 */ -+#define USART_CR1_M0 BIT(12) /* F7 (CR1_M for F4) */ - #define USART_CR1_MME BIT(13) /* F7 */ - #define USART_CR1_CMIE BIT(14) /* F7 */ - #define USART_CR1_OVER8 BIT(15) -@@ -169,8 +168,6 @@ struct stm32_usart_info stm32h7_info = { - /* USART_CR2 */ - #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ - #define USART_CR2_ADDM7 BIT(4) /* F7 */ --#define USART_CR2_LBDL BIT(5) --#define USART_CR2_LBDIE BIT(6) - #define USART_CR2_LBCL BIT(8) - #define USART_CR2_CPHA BIT(9) - #define USART_CR2_CPOL BIT(10) -@@ -209,6 +206,19 @@ struct stm32_usart_info stm32h7_info = { - #define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */ - #define USART_CR3_WUS_START_BIT BIT(21) /* H7 */ - #define USART_CR3_WUFIE BIT(22) /* H7 */ -+#define USART_CR3_TXFTIE BIT(23) /* H7 */ -+#define USART_CR3_TCBGTIE BIT(24) /* H7 */ -+#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */ -+#define USART_CR3_RXFTCFG_SHIFT 25 /* H7 */ -+#define USART_CR3_RXFTIE BIT(28) /* H7 */ -+#define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ -+#define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ -+ -+/* TX FIFO threashold set to half of its depth */ -+#define USART_CR3_TXFTCFG_HALF 0x2 -+ -+/* RX FIFO threashold set to half of its depth */ -+#define USART_CR3_RXFTCFG_HALF 0x2 - - /* USART_GTPR */ - #define USART_GTPR_PSC_MASK GENMASK(7, 0) -@@ -227,12 +237,10 @@ struct stm32_usart_info stm32h7_info = { - - /* USART_ICR */ - #define USART_ICR_PECF BIT(0) /* F7 */ --#define USART_ICR_FFECF BIT(1) /* F7 */ --#define USART_ICR_NCF BIT(2) /* F7 */ -+#define USART_ICR_FECF BIT(1) /* F7 */ - #define USART_ICR_ORECF BIT(3) /* F7 */ - #define USART_ICR_IDLECF BIT(4) /* F7 */ - #define USART_ICR_TCCF BIT(6) /* F7 */ --#define USART_ICR_LBDCF BIT(8) /* F7 */ - #define USART_ICR_CTSCF BIT(9) /* F7 */ - #define USART_ICR_RTOCF BIT(11) /* F7 */ - #define USART_ICR_EOBCF BIT(12) /* F7 */ -@@ -242,9 +250,9 @@ struct stm32_usart_info stm32h7_info = { - #define STM32_SERIAL_NAME "ttySTM" - #define STM32_MAX_PORTS 8 - --#define RX_BUF_L 200 /* dma rx buffer length */ --#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ --#define TX_BUF_L 200 /* dma tx buffer length */ -+#define RX_BUF_L 4096 /* dma rx buffer length */ -+#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ -+#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ - - struct stm32_port { - struct uart_port port; -@@ -256,11 +264,17 @@ struct stm32_port { - struct dma_chan *tx_ch; /* dma tx channel */ - dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ - unsigned char *tx_buf; /* dma tx buffer cpu address */ -+ u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ -+ u32 cr3_irq; /* USART_CR3_RXFTIE */ - int last_res; - bool tx_dma_busy; /* dma tx busy */ - bool hw_flow_control; - bool fifoen; - int wakeirq; -+ struct pinctrl_state *console_pins; -+ int rdr_mask; /* receive data register mask */ -+ struct dma_tx_state state; -+ enum dma_status status; - }; - - static struct stm32_port stm32_ports[STM32_MAX_PORTS]; -diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile -index 440320c..2bcd694 100644 ---- a/drivers/usb/dwc2/Makefile -+++ b/drivers/usb/dwc2/Makefile -@@ -3,7 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG - ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG - - obj-$(CONFIG_USB_DWC2) += dwc2.o --dwc2-y := core.o core_intr.o platform.o -+dwc2-y := core.o core_intr.o platform.o drd.o - dwc2-y += params.o - - ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) -diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c -index 633ba01..8ad88d2 100644 ---- a/drivers/usb/dwc2/core.c -+++ b/drivers/usb/dwc2/core.c -@@ -83,6 +83,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) - gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); - gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); - gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); -+ gr->ggpio = dwc2_readl(hsotg, GGPIO); - gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); - - gr->valid = true; -@@ -112,21 +113,82 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) - gr->valid = false; - - dwc2_writel(hsotg, 0xffffffff, GINTSTS); -+ dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); -+ dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); - dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); - dwc2_writel(hsotg, gr->gintmsk, GINTMSK); -- dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); -- dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); - dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); - dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); - dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); - dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); - dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); - dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); -+ dwc2_writel(hsotg, gr->ggpio, GGPIO); - dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); - - return 0; - } - -+int dwc2_backup_registers(struct dwc2_hsotg *hsotg) -+{ -+ int ret; -+ -+ /* Backup all registers */ -+ ret = dwc2_backup_global_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup global registers\n", -+ __func__); -+ return ret; -+ } -+ -+ if (dwc2_is_host_mode(hsotg)) { -+ ret = dwc2_backup_host_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup host registers\n", -+ __func__); -+ return ret; -+ } -+ } else { -+ ret = dwc2_backup_device_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to backup device registers\n", -+ __func__); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+int dwc2_restore_registers(struct dwc2_hsotg *hsotg) -+{ -+ int ret; -+ -+ ret = dwc2_restore_global_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore registers\n", -+ __func__); -+ return ret; -+ } -+ if (dwc2_is_host_mode(hsotg)) { -+ ret = dwc2_restore_host_registers(hsotg); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore host registers\n", -+ __func__); -+ return ret; -+ } -+ } else { -+ ret = dwc2_restore_device_registers(hsotg, 0); -+ if (ret) { -+ dev_err(hsotg->dev, "%s: failed to restore device registers\n", -+ __func__); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ - /** - * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. - * -@@ -136,7 +198,6 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) - int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - { - u32 pcgcctl; -- int ret = 0; - - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) - return -ENOTSUPP; -@@ -154,31 +215,11 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - dwc2_writel(hsotg, pcgcctl, PCGCTL); - - udelay(100); -- if (restore) { -- ret = dwc2_restore_global_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore registers\n", -- __func__); -- return ret; -- } -- if (dwc2_is_host_mode(hsotg)) { -- ret = dwc2_restore_host_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore host registers\n", -- __func__); -- return ret; -- } -- } else { -- ret = dwc2_restore_device_registers(hsotg, 0); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to restore device registers\n", -- __func__); -- return ret; -- } -- } -- } - -- return ret; -+ if (restore) -+ return dwc2_restore_registers(hsotg); -+ -+ return 0; - } - - /** -@@ -189,34 +230,14 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) - int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) - { - u32 pcgcctl; -- int ret = 0; -+ int ret; - - if (!hsotg->params.power_down) - return -ENOTSUPP; - -- /* Backup all registers */ -- ret = dwc2_backup_global_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup global registers\n", -- __func__); -+ ret = dwc2_backup_registers(hsotg); -+ if (ret) - return ret; -- } -- -- if (dwc2_is_host_mode(hsotg)) { -- ret = dwc2_backup_host_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup host registers\n", -- __func__); -- return ret; -- } -- } else { -- ret = dwc2_backup_device_registers(hsotg); -- if (ret) { -- dev_err(hsotg->dev, "%s: failed to backup device registers\n", -- __func__); -- return ret; -- } -- } - - /* - * Clear any pending interrupts since dwc2 will not be able to -@@ -238,7 +259,7 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) - pcgcctl |= PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); - -- return ret; -+ return 0; - } - - /** -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index cc9c93a..74d81f6 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -393,10 +393,28 @@ enum dwc2_ep0_state { - * 0 - No - * 1 - Yes - * @hird_threshold: Value of BESL or HIRD Threshold. -+ * @ref_clk_per: Indicates in terms of pico seconds the period -+ * of ref_clk. -+ * 62500 - 16MHz -+ * 58823 - 17MHz -+ * 52083 - 19.2MHz -+ * 50000 - 20MHz -+ * 41666 - 24MHz -+ * 33333 - 30MHz (default) -+ * 25000 - 40MHz -+ * @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which -+ * the controller should generate an interrupt if the -+ * device had been in L1 state until that period. -+ * This is used by SW to initiate Remote WakeUp in the -+ * controller so as to sync to the uF number from the host. - * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO - * register. - * 0 - Deactivate the transceiver (default) - * 1 - Activate the transceiver -+ * @activate_stm_id_vb_detection: Activate external ID pin and Vbuslevel -+ * detection using GGPIO register. -+ * 0 - Deactivate the external level detection (default) -+ * 1 - Activate the external level detection - * @g_dma: Enables gadget dma usage (default: autodetect). - * @g_dma_desc: Enables gadget descriptor DMA (default: autodetect). - * @g_rx_fifo_size: The periodic rx fifo size for the device, in -@@ -416,6 +434,9 @@ enum dwc2_ep0_state { - * back to DWC2_SPEED_PARAM_HIGH while device is gone. - * 0 - No (default) - * 1 - Yes -+ * @service_interval: Enable service interval based scheduling. -+ * 0 - No -+ * 1 - Yes - * - * The following parameters may be specified when starting the module. These - * parameters define how the DWC_otg controller should be configured. A -@@ -461,13 +482,19 @@ struct dwc2_core_params { - bool lpm_clock_gating; - bool besl; - bool hird_threshold_en; -+ bool service_interval; - u8 hird_threshold; - bool activate_stm_fs_transceiver; -+ bool activate_stm_id_vb_detection; - bool ipg_isoc_en; - u16 max_packet_count; - u32 max_transfer_size; - u32 ahbcfg; - -+ /* GREFCLK parameters */ -+ u32 ref_clk_per; -+ u16 sof_cnt_wkup_alert; -+ - /* Host parameters */ - bool host_dma; - bool dma_desc_enable; -@@ -605,6 +632,10 @@ struct dwc2_core_params { - * FIFO sizing is enabled 16 to 32768 - * Actual maximum value is autodetected and also - * the default. -+ * @service_interval_mode: For enabling service interval based scheduling in the -+ * controller. -+ * 0 - Disable -+ * 1 - Enable - */ - struct dwc2_hw_params { - unsigned op_mode:3; -@@ -635,6 +666,7 @@ struct dwc2_hw_params { - unsigned utmi_phy_data_width:2; - unsigned lpm_mode:1; - unsigned ipg_isoc_en:1; -+ unsigned service_interval_mode:1; - u32 snpsid; - u32 dev_ep_dirs; - u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; -@@ -653,6 +685,7 @@ struct dwc2_hw_params { - * @grxfsiz: Backup of GRXFSIZ register - * @gnptxfsiz: Backup of GNPTXFSIZ register - * @gi2cctl: Backup of GI2CCTL register -+ * @ggpio: Backup of GGPIO register - * @glpmcfg: Backup of GLPMCFG register - * @gdfifocfg: Backup of GDFIFOCFG register - * @pcgcctl: Backup of PCGCCTL register -@@ -669,6 +702,7 @@ struct dwc2_gregs_backup { - u32 grxfsiz; - u32 gnptxfsiz; - u32 gi2cctl; -+ u32 ggpio; - u32 glpmcfg; - u32 pcgcctl; - u32 pcgcctl1; -@@ -828,6 +862,8 @@ struct dwc2_hregs_backup { - * - USB_DR_MODE_PERIPHERAL - * - USB_DR_MODE_HOST - * - USB_DR_MODE_OTG -+ * @edev: extcon handle -+ * @edev_nb: extcon notifier - * @hcd_enabled: Host mode sub-driver initialization indicator. - * @gadget_enabled: Peripheral mode sub-driver initialization indicator. - * @ll_hw_enabled: Status of low-level hardware resources. -@@ -842,6 +878,8 @@ struct dwc2_hregs_backup { - * removed once all SoCs support usb transceiver. - * @supplies: Definition of USB power supplies - * @vbus_supply: Regulator supplying vbus. -+ * @usb33d: Optional 3.3v regulator used on some stm32 devices to -+ * supply ID and VBUS detection hardware. - * @phyif: PHY interface width - * @lock: Spinlock that protects all the driver data structures - * @priv: Stores a pointer to the struct usb_hcd -@@ -974,6 +1012,7 @@ struct dwc2_hregs_backup { - * @ctrl_out_desc_dma: EP0 OUT data phase desc chain DMA address - * @ctrl_out_desc: EP0 OUT data phase desc chain pointer - * @irq: Interrupt request line number -+ * @wakeirq: Wakeup interrupt request line number - * @clk: Pointer to otg clock - * @reset: Pointer to dwc2 reset controller - * @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10. -@@ -1014,6 +1053,8 @@ struct dwc2_hsotg { - struct dwc2_core_params params; - enum usb_otg_state op_state; - enum usb_dr_mode dr_mode; -+ struct extcon_dev *edev; -+ struct notifier_block edev_nb; - unsigned int hcd_enabled:1; - unsigned int gadget_enabled:1; - unsigned int ll_hw_enabled:1; -@@ -1025,11 +1066,13 @@ struct dwc2_hsotg { - struct dwc2_hsotg_plat *plat; - struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; - struct regulator *vbus_supply; -+ struct regulator *usb33d; - u32 phyif; - - spinlock_t lock; - void *priv; - int irq; -+ int wakeirq; - struct clk *clk; - struct reset_control *reset; - struct reset_control *reset_ecc; -@@ -1276,6 +1319,8 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); - - void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, - int is_host); -+int dwc2_backup_registers(struct dwc2_hsotg *hsotg); -+int dwc2_restore_registers(struct dwc2_hsotg *hsotg); - int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg); - int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg); - -@@ -1325,6 +1370,8 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) - return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0; - } - -+int dwc2_drd_init(struct dwc2_hsotg *hsotg); -+ - /* - * Dump core registers and SPRAM - */ -@@ -1341,6 +1388,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); - int dwc2_gadget_init(struct dwc2_hsotg *hsotg); - void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, - bool reset); -+void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg); - void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); - void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); - int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); -@@ -1354,6 +1402,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); - int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); - int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); - void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); -+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg); - #else - static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) - { return 0; } -@@ -1388,6 +1437,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) - static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) - { return 0; } - static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} -+static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {} - #endif - - #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) -diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c -index 22d015b..7f62f4c 100644 ---- a/drivers/usb/dwc2/debugfs.c -+++ b/drivers/usb/dwc2/debugfs.c -@@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v) - print_param(seq, p, besl); - print_param(seq, p, hird_threshold_en); - print_param(seq, p, hird_threshold); -+ print_param(seq, p, service_interval); - print_param(seq, p, host_dma); - print_param(seq, p, g_dma); - print_param(seq, p, g_dma_desc); -diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c -new file mode 100644 -index 0000000..7d812b7 ---- /dev/null -+++ b/drivers/usb/dwc2/drd.c -@@ -0,0 +1,191 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * drd.c - DesignWare USB2 DRD Controller Dual-role support -+ * -+ * Copyright (C) 2019 STMicroelectronics -+ * -+ * Author(s): Amelie Delaunay -+ */ -+ -+#include -+#include -+#include -+#include "core.h" -+ -+static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) -+{ -+ unsigned long flags; -+ u32 gotgctl; -+ -+ spin_lock_irqsave(&hsotg->lock, flags); -+ -+ gotgctl = dwc2_readl(hsotg, GOTGCTL); -+ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN; -+ gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; -+ gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); -+ dwc2_writel(hsotg, gotgctl, GOTGCTL); -+ -+ spin_unlock_irqrestore(&hsotg->lock, flags); -+} -+ -+static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) -+{ -+ u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); -+ -+ /* Check if A-Session is already in the right state */ -+ if ((valid && (gotgctl & GOTGCTL_ASESVLD)) || -+ (!valid && !(gotgctl & GOTGCTL_ASESVLD))) -+ return -EALREADY; -+ -+ if (valid) -+ gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; -+ else -+ gotgctl &= ~(GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); -+ dwc2_writel(hsotg, gotgctl, GOTGCTL); -+ -+ return 0; -+} -+ -+static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) -+{ -+ u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); -+ -+ /* Check if B-Session is already in the right state */ -+ if ((valid && (gotgctl & GOTGCTL_BSESVLD)) || -+ (!valid && !(gotgctl & GOTGCTL_BSESVLD))) -+ return -EALREADY; -+ -+ if (valid) -+ gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; -+ else -+ gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL); -+ dwc2_writel(hsotg, gotgctl, GOTGCTL); -+ -+ return 0; -+} -+ -+static void dwc2_drd_update(struct dwc2_hsotg *hsotg) -+{ -+ int avalid, bvalid; -+ unsigned long flags; -+ -+ avalid = extcon_get_state(hsotg->edev, EXTCON_USB_HOST); -+ if (avalid < 0) -+ avalid = 0; -+ -+ bvalid = extcon_get_state(hsotg->edev, EXTCON_USB); -+ if (bvalid < 0) -+ bvalid = 0; -+ -+ /* Skip session not in line with dr_mode */ -+ if ((avalid && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || -+ (bvalid && hsotg->dr_mode == USB_DR_MODE_HOST)) -+ return; -+ -+ /* Skip session if core is in test mode */ -+ if (!avalid && !bvalid && hsotg->test_mode) { -+ dev_dbg(hsotg->dev, "Core is in test mode\n"); -+ return; -+ } -+ -+ spin_lock_irqsave(&hsotg->lock, flags); -+ -+ if (avalid) { -+ if (dwc2_ovr_avalid(hsotg, true)) -+ goto unlock; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_OTG) -+ /* -+ * This will raise a Connector ID Status Change -+ * Interrupt - connID A -+ */ -+ dwc2_force_mode(hsotg, true); -+ } else if (bvalid) { -+ if (dwc2_ovr_bvalid(hsotg, true)) -+ goto unlock; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_OTG) -+ /* -+ * This will raise a Connector ID Status Change -+ * Interrupt - connID B -+ */ -+ dwc2_force_mode(hsotg, false); -+ -+ /* This clear DCTL.SFTDISCON bit */ -+ dwc2_hsotg_core_connect(hsotg); -+ } else { -+ if (dwc2_ovr_avalid(hsotg, false) && -+ dwc2_ovr_bvalid(hsotg, false)) -+ goto unlock; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) -+ /* This set DCTL.SFTDISCON bit */ -+ dwc2_hsotg_core_disconnect(hsotg); -+ -+ dwc2_force_dr_mode(hsotg); -+ } -+ -+ dev_dbg(hsotg->dev, "%s-session valid\n", -+ avalid ? "A" : bvalid ? "B" : "No"); -+ -+unlock: -+ spin_unlock_irqrestore(&hsotg->lock, flags); -+} -+ -+static int dwc2_drd_notifier(struct notifier_block *nb, -+ unsigned long event, void *ptr) -+{ -+ struct dwc2_hsotg *hsotg = container_of(nb, struct dwc2_hsotg, edev_nb); -+ -+ dwc2_drd_update(hsotg); -+ -+ return NOTIFY_DONE; -+} -+ -+int dwc2_drd_init(struct dwc2_hsotg *hsotg) -+{ -+ struct extcon_dev *edev; -+ int ret; -+ -+ if (of_property_read_bool(hsotg->dev->of_node, "extcon")) { -+ edev = extcon_get_edev_by_phandle(hsotg->dev, 0); -+ if (IS_ERR(edev)) { -+ ret = PTR_ERR(edev); -+ if (ret != -EPROBE_DEFER) -+ dev_err(hsotg->dev, -+ "couldn't get extcon device: %d\n", -+ ret); -+ return ret; -+ } -+ -+ hsotg->edev_nb.notifier_call = dwc2_drd_notifier; -+ ret = devm_extcon_register_notifier(hsotg->dev, edev, -+ EXTCON_USB, -+ &hsotg->edev_nb); -+ if (ret < 0) { -+ dev_err(hsotg->dev, -+ "USB cable notifier register failed: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = devm_extcon_register_notifier(hsotg->dev, edev, -+ EXTCON_USB_HOST, -+ &hsotg->edev_nb); -+ if (ret < 0) { -+ dev_err(hsotg->dev, -+ "USB-HOST cable notifier register failed: %d\n", -+ ret); -+ return ret; -+ } -+ -+ hsotg->edev = edev; -+ -+ /* Enable override and initialize values */ -+ dwc2_ovr_init(hsotg); -+ -+ dwc2_drd_update(hsotg); -+ } -+ -+ return 0; -+} -diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c -index 3f68edd..3ebd5dd 100644 ---- a/drivers/usb/dwc2/gadget.c -+++ b/drivers/usb/dwc2/gadget.c -@@ -123,6 +123,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) - } - - /** -+ * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number -+ * by one. -+ * @hs_ep: The endpoint. -+ * -+ * This function used in service interval based scheduling flow to calculate -+ * descriptor frame number filed value. For service interval mode frame -+ * number in descriptor should point to last (u)frame in the interval. -+ * -+ */ -+static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) -+{ -+ if (hs_ep->target_frame) -+ hs_ep->target_frame -= 1; -+ else -+ hs_ep->target_frame = DSTS_SOFFN_LIMIT; -+} -+ -+/** - * dwc2_hsotg_en_gsint - enable one or more of the general interrupt - * @hsotg: The device state - * @ints: A bitmask of the interrupts to enable -@@ -228,6 +246,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) - } - - /** -+ * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt -+ * -+ * @hsotg: Programming view of the DWC_otg controller -+ * -+ */ -+static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) -+{ -+ u32 gintsts2; -+ u32 gintmsk2; -+ -+ gintsts2 = dwc2_readl(hsotg, GINTSTS2); -+ gintmsk2 = dwc2_readl(hsotg, GINTMSK2); -+ -+ if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { -+ dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); -+ dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); -+ dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); -+ } -+} -+ -+/** - * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode - * TX FIFOs - * -@@ -2810,6 +2849,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) - if (using_desc_dma(hsotg)) { - hs_ep->target_frame = hsotg->frame_number; - dwc2_gadget_incr_frame_num(hs_ep); -+ -+ /* In service interval mode target_frame must -+ * be set to last (u)frame of the service interval. -+ */ -+ if (hsotg->params.service_interval) { -+ /* Set target_frame to the first (u)frame of -+ * the service interval -+ */ -+ hs_ep->target_frame &= ~hs_ep->interval + 1; -+ -+ /* Set target_frame to the last (u)frame of -+ * the service interval -+ */ -+ dwc2_gadget_incr_frame_num(hs_ep); -+ dwc2_gadget_dec_frame_num_by_one(hs_ep); -+ } -+ - dwc2_gadget_start_isoc_ddma(hs_ep); - return; - } -@@ -3322,6 +3378,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); - } - -+ /* Enable Service Interval mode if supported */ -+ if (using_desc_dma(hsotg) && hsotg->params.service_interval) -+ dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); -+ - dwc2_writel(hsotg, 0, DAINTMSK); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -@@ -3378,6 +3438,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - /* configure the core to support LPM */ - dwc2_gadget_init_lpm(hsotg); - -+ /* program GREFCLK register if needed */ -+ if (using_desc_dma(hsotg) && hsotg->params.service_interval) -+ dwc2_gadget_program_ref_clk(hsotg); -+ - /* must be at-least 3ms to allow bus to see disconnect */ - mdelay(3); - -@@ -3390,7 +3454,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - dwc2_readl(hsotg, DOEPCTL0)); - } - --static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) -+void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) - { - /* set the soft-disconnect bit */ - dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); -@@ -3399,7 +3463,8 @@ static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) - void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) - { - /* remove the soft-disconnect and let's go */ -- dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); -+ if (!hsotg->edev || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) -+ dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); - } - - /** -@@ -3686,6 +3751,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) - if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) - goto irq_retry; - -+ /* Check WKUP_ALERT interrupt*/ -+ if (hsotg->params.service_interval) -+ dwc2_gadget_wkup_alert_handler(hsotg); -+ - spin_unlock(&hsotg->lock); - - return IRQ_HANDLED; -@@ -4795,7 +4864,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock_irqrestore(&hsotg->lock, flags); - -- for (ep = 0; ep < hsotg->num_of_eps; ep++) { -+ for (ep = 1; ep < hsotg->num_of_eps; ep++) { - if (hsotg->eps_in[ep]) - dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); - if (hsotg->eps_out[ep]) -@@ -4966,8 +5035,32 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) - val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; - val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; - val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; -+ val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; - dwc2_writel(hsotg, val, GLPMCFG); - dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); -+ -+ /* Unmask WKUP_ALERT Interrupt */ -+ if (hsotg->params.service_interval) -+ dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); -+} -+ -+/** -+ * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode -+ * -+ * @hsotg: Programming view of DWC_otg controller -+ * -+ */ -+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) -+{ -+ u32 val = 0; -+ -+ val |= GREFCLK_REF_CLK_MODE; -+ val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; -+ val |= hsotg->params.sof_cnt_wkup_alert << -+ GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; -+ -+ dwc2_writel(hsotg, val, GREFCLK); -+ dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); - } - - /** -diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index a5c8329..67bbf94 100644 ---- a/drivers/usb/dwc2/hcd.c -+++ b/drivers/usb/dwc2/hcd.c -@@ -125,7 +125,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) - - static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) - { -- u32 usbcfg, ggpio, i2cctl; -+ u32 usbcfg, i2cctl; - int retval = 0; - - /* -@@ -149,19 +149,6 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) - return retval; - } - } -- -- if (hsotg->params.activate_stm_fs_transceiver) { -- ggpio = dwc2_readl(hsotg, GGPIO); -- if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { -- dev_dbg(hsotg->dev, "Activating transceiver\n"); -- /* -- * STM32F4x9 uses the GGPIO register as general -- * core configuration register. -- */ -- ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; -- dwc2_writel(hsotg, ggpio, GGPIO); -- } -- } - } - - /* -@@ -358,16 +345,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) - - static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) - { -- int ret; -- -- hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); -- if (IS_ERR(hsotg->vbus_supply)) { -- ret = PTR_ERR(hsotg->vbus_supply); -- hsotg->vbus_supply = NULL; -- return ret == -ENODEV ? 0 : ret; -- } -+ if (hsotg->vbus_supply) -+ return regulator_enable(hsotg->vbus_supply); - -- return regulator_enable(hsotg->vbus_supply); -+ return 0; - } - - static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg) -@@ -1328,14 +1309,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg, - u32 remaining_count; - u32 byte_count; - u32 dword_count; -- u32 __iomem *data_fifo; - u32 *data_buf = (u32 *)chan->xfer_buf; - - if (dbg_hc(chan)) - dev_vdbg(hsotg->dev, "%s()\n", __func__); - -- data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num)); -- - remaining_count = chan->xfer_len - chan->xfer_count; - if (remaining_count > chan->max_packet) - byte_count = chan->max_packet; -@@ -1934,7 +1912,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) - * release_channel_ddma(), which is called from ep_disable when - * device disconnects - */ -- channel->qh = NULL; -+ if (hsotg->params.host_dma && hsotg->params.dma_desc_enable) -+ channel->qh = NULL; - } - /* All channels have been freed, mark them available */ - if (hsotg->params.uframe_sched) { -@@ -3804,7 +3783,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) - goto error; - -- if (!hsotg->flags.b.port_connect_status) { -+ if (!hsotg->flags.b.port_connect_status && -+ !dwc2_is_host_mode(hsotg)) { - /* - * The port is disconnected, which means the core is - * either in device mode or it soon will be. Just -diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h -index 0ca8e7b..7500954 100644 ---- a/drivers/usb/dwc2/hw.h -+++ b/drivers/usb/dwc2/hw.h -@@ -54,6 +54,12 @@ - #define GOTGCTL_HSTSETHNPEN BIT(10) - #define GOTGCTL_HNPREQ BIT(9) - #define GOTGCTL_HSTNEGSCS BIT(8) -+#define GOTGCTL_BVALOVAL BIT(7) -+#define GOTGCTL_BVALOEN BIT(6) -+#define GOTGCTL_AVALOVAL BIT(5) -+#define GOTGCTL_AVALOEN BIT(4) -+#define GOTGCTL_VBVALOVAL BIT(3) -+#define GOTGCTL_VBVALOEN BIT(2) - #define GOTGCTL_SESREQ BIT(1) - #define GOTGCTL_SESREQSCS BIT(0) - -@@ -227,6 +233,8 @@ - #define GPVNDCTL HSOTG_REG(0x0034) - #define GGPIO HSOTG_REG(0x0038) - #define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) -+#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) -+#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) - - #define GUID HSOTG_REG(0x003c) - #define GSNPSID HSOTG_REG(0x0040) -@@ -312,6 +320,7 @@ - #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 - #define GHWCFG4_ACG_SUPPORTED BIT(12) - #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) -+#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) - #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 - #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 - #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 -@@ -332,6 +341,8 @@ - #define GLPMCFG_SNDLPM BIT(24) - #define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) - #define GLPMCFG_RETRY_CNT_SHIFT 21 -+#define GLPMCFG_LPM_ACCEPT_CTRL_CONTROL BIT(21) -+#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) - #define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) - #define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 - #define GLPMCFG_L1RESUMEOK BIT(16) -@@ -404,6 +415,19 @@ - #define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) - #define ADPCTL_PRB_DSCHRG_SHIFT 0 - -+#define GREFCLK HSOTG_REG(0x0064) -+#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) -+#define GREFCLK_REFCLKPER_SHIFT 15 -+#define GREFCLK_REF_CLK_MODE BIT(14) -+#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) -+#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0 -+ -+#define GINTMSK2 HSOTG_REG(0x0068) -+#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) -+ -+#define GINTSTS2 HSOTG_REG(0x006c) -+#define GINTSTS2_WKUP_ALERT_INT BIT(0) -+ - #define HPTXFSIZ HSOTG_REG(0x100) - /* Use FIFOSIZE_* constants to access this register */ - -@@ -443,6 +467,7 @@ - #define DCFG_DEVSPD_FS48 3 - - #define DCTL HSOTG_REG(0x804) -+#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) - #define DCTL_PWRONPRGDONE BIT(11) - #define DCTL_CGOUTNAK BIT(10) - #define DCTL_SGOUTNAK BIT(9) -diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index a93415f..8af461c 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -152,6 +152,36 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) - p->host_perio_tx_fifo_size = 256; - } - -+static void dwc2_set_stm32mp1_fsotg_params(struct dwc2_hsotg *hsotg) -+{ -+ struct dwc2_core_params *p = &hsotg->params; -+ -+ p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; -+ p->speed = DWC2_SPEED_PARAM_FULL; -+ p->host_rx_fifo_size = 128; -+ p->host_nperio_tx_fifo_size = 96; -+ p->host_perio_tx_fifo_size = 96; -+ p->max_packet_count = 256; -+ p->phy_type = DWC2_PHY_TYPE_PARAM_FS; -+ p->i2c_enable = false; -+ p->activate_stm_fs_transceiver = true; -+ p->activate_stm_id_vb_detection = true; -+ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; -+} -+ -+static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg) -+{ -+ struct dwc2_core_params *p = &hsotg->params; -+ struct device_node *np = hsotg->dev->of_node; -+ -+ p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; -+ p->activate_stm_id_vb_detection = !of_property_read_bool(np, "extcon"); -+ p->host_rx_fifo_size = 440; -+ p->host_nperio_tx_fifo_size = 256; -+ p->host_perio_tx_fifo_size = 256; -+ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; -+} -+ - const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, - { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, -@@ -173,6 +203,10 @@ const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "st,stm32f4x9-hsotg" }, - { .compatible = "st,stm32f7-hsotg", - .data = dwc2_set_stm32f7_hsotg_params }, -+ { .compatible = "st,stm32mp1-fsotg", -+ .data = dwc2_set_stm32mp1_fsotg_params }, -+ { .compatible = "st,stm32mp1-hsotg", -+ .data = dwc2_set_stm32mp1_hsotg_params }, - {}, - }; - MODULE_DEVICE_TABLE(of, dwc2_of_match_table); -@@ -309,9 +343,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) - p->hird_threshold_en = true; - p->hird_threshold = 4; - p->ipg_isoc_en = false; -+ p->service_interval = false; - p->max_packet_count = hw->max_packet_count; - p->max_transfer_size = hw->max_transfer_size; - p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; -+ p->ref_clk_per = 33333; -+ p->sof_cnt_wkup_alert = 100; - - if ((hsotg->dr_mode == USB_DR_MODE_HOST) || - (hsotg->dr_mode == USB_DR_MODE_OTG)) { -@@ -602,6 +639,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) - CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)); - CHECK_BOOL(hird_threshold_en, hsotg->params.lpm); - CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0); -+ CHECK_BOOL(service_interval, hw->service_interval_mode); - CHECK_RANGE(max_packet_count, - 15, hw->max_packet_count, - hw->max_packet_count); -@@ -790,6 +828,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) - GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; - hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); - hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); -+ hw->service_interval_mode = !!(hwcfg4 & -+ GHWCFG4_SERVICE_INTERVAL_SUPPORTED); - - /* fifo sizes */ - hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 5776428..3d61100 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -46,6 +46,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -318,12 +319,18 @@ static int dwc2_driver_remove(struct platform_device *dev) - { - struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); - -+ if (hsotg->wakeirq > 0) -+ dev_pm_clear_wake_irq(&dev->dev); -+ - dwc2_debugfs_exit(hsotg); - if (hsotg->hcd_enabled) - dwc2_hcd_remove(hsotg); - if (hsotg->gadget_enabled) - dwc2_hsotg_remove(hsotg); - -+ if (hsotg->params.activate_stm_id_vb_detection) -+ regulator_disable(hsotg->usb33d); -+ - if (hsotg->ll_hw_enabled) - dwc2_lowlevel_hw_disable(hsotg); - -@@ -432,6 +439,24 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) - return retval; - -+ hsotg->wakeirq = platform_get_irq(dev, 1); -+ if (hsotg->wakeirq > 0) { -+ retval = dev_pm_set_dedicated_wake_irq(&dev->dev, -+ hsotg->wakeirq); -+ if (retval) -+ return retval; -+ } else if (hsotg->wakeirq == -EPROBE_DEFER) { -+ return hsotg->wakeirq; -+ } -+ -+ hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); -+ if (IS_ERR(hsotg->vbus_supply)) { -+ retval = PTR_ERR(hsotg->vbus_supply); -+ hsotg->vbus_supply = NULL; -+ if (retval != -ENODEV) -+ return retval; -+ } -+ - retval = dwc2_lowlevel_hw_enable(hsotg); - if (retval) - return retval; -@@ -466,10 +491,55 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) - goto error; - -+ if (hsotg->params.activate_stm_id_vb_detection) { -+ u32 ggpio; -+ -+ hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); -+ if (IS_ERR(hsotg->usb33d)) { -+ retval = PTR_ERR(hsotg->usb33d); -+ dev_err(hsotg->dev, -+ "can't get voltage level detector supply\n"); -+ goto error; -+ } -+ retval = regulator_enable(hsotg->usb33d); -+ if (retval) { -+ dev_err(hsotg->dev, -+ "can't enable voltage level detector supply\n"); -+ goto error; -+ } -+ -+ ggpio = dwc2_readl(hsotg, GGPIO); -+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; -+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; -+ dwc2_writel(hsotg, ggpio, GGPIO); -+ } -+ -+ retval = dwc2_drd_init(hsotg); -+ if (retval) { -+ if (retval != -EPROBE_DEFER) -+ dev_err(hsotg->dev, "failed to initialize dual-role\n"); -+ goto error_init; -+ } -+ -+ if (hsotg->params.activate_stm_fs_transceiver) { -+ u32 ggpio; -+ -+ ggpio = dwc2_readl(hsotg, GGPIO); -+ if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { -+ dev_dbg(hsotg->dev, "Activating transceiver\n"); -+ /* -+ * STM32 uses the GGPIO register as general -+ * core configuration register. -+ */ -+ ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; -+ dwc2_writel(hsotg, ggpio, GGPIO); -+ } -+ } -+ - if (hsotg->dr_mode != USB_DR_MODE_HOST) { - retval = dwc2_gadget_init(hsotg); - if (retval) -- goto error; -+ goto error_init; - hsotg->gadget_enabled = 1; - } - -@@ -478,7 +548,7 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) { - if (hsotg->gadget_enabled) - dwc2_hsotg_remove(hsotg); -- goto error; -+ goto error_init; - } - hsotg->hcd_enabled = 1; - } -@@ -494,7 +564,13 @@ static int dwc2_driver_probe(struct platform_device *dev) - - return 0; - -+error_init: -+ if (hsotg->params.activate_stm_id_vb_detection) -+ regulator_disable(hsotg->usb33d); - error: -+ if (hsotg->wakeirq > 0) -+ dev_pm_clear_wake_irq(&dev->dev); -+ - dwc2_lowlevel_hw_disable(hsotg); - return retval; - } -@@ -507,9 +583,58 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - if (dwc2_is_device_mode(dwc2)) - dwc2_hsotg_suspend(dwc2); - -+ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { -+ /* -+ * Backup host registers when power_down param is 'none', if -+ * controller power is disabled. -+ * This shouldn't be needed, when using other power_down modes. -+ */ -+ ret = dwc2_backup_registers(dwc2); -+ if (ret) { -+ dev_err(dwc2->dev, "backup regs failed %d\n", ret); -+ return ret; -+ } -+ } -+ -+ if (dwc2->params.activate_stm_id_vb_detection) { -+ unsigned long flags; -+ u32 ggpio, gotgctl; -+ int is_host = dwc2_is_host_mode(dwc2); -+ -+ /* -+ * Need to force the mode to the current mode to avoid Mode -+ * Mismatch Interrupt when ID detection will be disabled. -+ */ -+ dwc2_force_mode(dwc2, is_host); -+ -+ spin_lock_irqsave(&dwc2->lock, flags); -+ gotgctl = dwc2_readl(dwc2, GOTGCTL); -+ /* bypass debounce filter, enable overrides */ -+ gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; -+ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; -+ /* Force A / B session if needed */ -+ if (gotgctl & GOTGCTL_ASESVLD) -+ gotgctl |= GOTGCTL_AVALOVAL; -+ if (gotgctl & GOTGCTL_BSESVLD) -+ gotgctl |= GOTGCTL_BVALOVAL; -+ dwc2_writel(dwc2, gotgctl, GOTGCTL); -+ spin_unlock_irqrestore(&dwc2->lock, flags); -+ -+ ggpio = dwc2_readl(dwc2, GGPIO); -+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; -+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; -+ dwc2_writel(dwc2, ggpio, GGPIO); -+ -+ regulator_disable(dwc2->usb33d); -+ } -+ - if (dwc2->ll_hw_enabled) - ret = __dwc2_lowlevel_hw_disable(dwc2); - -+ if (dwc2->wakeirq > 0 && -+ (device_may_wakeup(dev) || dev->power.wakeup_path)) -+ enable_irq_wake(dwc2->wakeirq); -+ - return ret; - } - -@@ -518,12 +643,49 @@ static int __maybe_unused dwc2_resume(struct device *dev) - struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); - int ret = 0; - -+ if (dwc2->wakeirq > 0 && -+ (device_may_wakeup(dev) || dev->power.wakeup_path)) -+ disable_irq_wake(dwc2->wakeirq); -+ - if (dwc2->ll_hw_enabled) { - ret = __dwc2_lowlevel_hw_enable(dwc2); - if (ret) - return ret; - } - -+ if (dwc2->params.activate_stm_id_vb_detection) { -+ unsigned long flags; -+ u32 ggpio, gotgctl; -+ -+ ret = regulator_enable(dwc2->usb33d); -+ if (ret) -+ return ret; -+ -+ ggpio = dwc2_readl(dwc2, GGPIO); -+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; -+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; -+ dwc2_writel(dwc2, ggpio, GGPIO); -+ -+ /* ID/VBUS detection startup time */ -+ usleep_range(5000, 7000); -+ -+ spin_lock_irqsave(&dwc2->lock, flags); -+ gotgctl = dwc2_readl(dwc2, GOTGCTL); -+ gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; -+ gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | -+ GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); -+ dwc2_writel(dwc2, gotgctl, GOTGCTL); -+ spin_unlock_irqrestore(&dwc2->lock, flags); -+ } -+ -+ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { -+ ret = dwc2_restore_registers(dwc2); -+ if (ret) { -+ dev_err(dwc2->dev, "restore regs failed %d\n", ret); -+ return ret; -+ } -+ } -+ - if (dwc2_is_device_mode(dwc2)) - ret = dwc2_hsotg_resume(dwc2); - -diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c -index d4d317d..bb1e2e1 100644 ---- a/drivers/usb/gadget/function/u_serial.c -+++ b/drivers/usb/gadget/function/u_serial.c -@@ -16,7 +16,6 @@ - - #include - #include --#include - #include - #include - #include -@@ -26,6 +25,7 @@ - #include - #include - #include -+#include - #include - - #include "u_serial.h" -@@ -110,7 +110,7 @@ struct gs_port { - int read_allocated; - struct list_head read_queue; - unsigned n_read; -- struct tasklet_struct push; -+ struct delayed_work push; - - struct list_head write_pool; - int write_started; -@@ -352,9 +352,10 @@ __acquires(&port->port_lock) - * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) - * can be buffered before the TTY layer's buffers (currently 64 KB). - */ --static void gs_rx_push(unsigned long _port) -+static void gs_rx_push(struct work_struct *work) - { -- struct gs_port *port = (void *)_port; -+ struct delayed_work *w = to_delayed_work(work); -+ struct gs_port *port = container_of(w, struct gs_port, push); - struct tty_struct *tty; - struct list_head *queue = &port->read_queue; - bool disconnect = false; -@@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port) - - /* We want our data queue to become empty ASAP, keeping data - * in the tty and ldisc (not here). If we couldn't push any -- * this time around, there may be trouble unless there's an -- * implicit tty_unthrottle() call on its way... -+ * this time around, RX may be starved, so wait until next jiffy. - * -- * REVISIT we should probably add a timer to keep the tasklet -- * from starving ... but it's not clear that case ever happens. -+ * We may leave non-empty queue only when there is a tty, and -+ * either it is throttled or there is no more room in flip buffer. - */ -- if (!list_empty(queue) && tty) { -- if (!tty_throttled(tty)) { -- if (do_push) -- tasklet_schedule(&port->push); -- else -- pr_warn("ttyGS%d: RX not scheduled?\n", -- port->port_num); -- } -- } -+ if (!list_empty(queue) && !tty_throttled(tty)) -+ schedule_delayed_work(&port->push, 1); - - /* If we're still connected, refill the USB RX queue. */ - if (!disconnect && port->port_usb) -@@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) - /* Queue all received data until the tty layer is ready for it. */ - spin_lock(&port->port_lock); - list_add_tail(&req->list, &port->read_queue); -- tasklet_schedule(&port->push); -+ schedule_delayed_work(&port->push, 0); - spin_unlock(&port->port_lock); - } - -@@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty) - * rts/cts, or other handshaking with the host, but if the - * read queue backs up enough we'll be NAKing OUT packets. - */ -- tasklet_schedule(&port->push); - pr_vdebug("ttyGS%d: unthrottle\n", port->port_num); -+ schedule_delayed_work(&port->push, 0); - } - spin_unlock_irqrestore(&port->port_lock, flags); - } -@@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) - init_waitqueue_head(&port->drain_wait); - init_waitqueue_head(&port->close_wait); - -- tasklet_init(&port->push, gs_rx_push, (unsigned long) port); -+ INIT_DELAYED_WORK(&port->push, gs_rx_push); - - INIT_LIST_HEAD(&port->read_pool); - INIT_LIST_HEAD(&port->read_queue); -@@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port) - - static void gserial_free_port(struct gs_port *port) - { -- tasklet_kill(&port->push); -+ cancel_delayed_work_sync(&port->push); - /* wait for old opens to finish */ - wait_event(port->close_wait, gs_closed(port)); - WARN_ON(port->port_usb != NULL); -diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c -index 4c306fb..b915c0f 100644 ---- a/drivers/usb/host/ehci-platform.c -+++ b/drivers/usb/host/ehci-platform.c -@@ -28,6 +28,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -43,6 +45,8 @@ - struct ehci_platform_priv { - struct clk *clks[EHCI_MAX_CLKS]; - struct reset_control *rsts; -+ struct regulator *vbus_supply; -+ int wakeirq; - bool reset_on_resume; - }; - -@@ -73,6 +77,26 @@ static int ehci_platform_reset(struct usb_hcd *hcd) - return 0; - } - -+static int ehci_platform_port_power(struct usb_hcd *hcd, int portnum, -+ bool enable) -+{ -+ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); -+ int ret; -+ -+ if (!priv->vbus_supply) -+ return 0; -+ -+ if (enable) -+ ret = regulator_enable(priv->vbus_supply); -+ else -+ ret = regulator_disable(priv->vbus_supply); -+ if (ret) -+ dev_err(hcd->self.controller, "failed to %s vbus supply: %d\n", -+ enable ? "enable" : "disable", ret); -+ -+ return ret; -+} -+ - static int ehci_platform_power_on(struct platform_device *dev) - { - struct usb_hcd *hcd = platform_get_drvdata(dev); -@@ -110,6 +134,7 @@ static struct hc_driver __read_mostly ehci_platform_hc_driver; - static const struct ehci_driver_overrides platform_overrides __initconst = { - .reset = ehci_platform_reset, - .extra_priv_size = sizeof(struct ehci_platform_priv), -+ .port_power = ehci_platform_port_power, - }; - - static struct usb_ehci_pdata ehci_platform_defaults = { -@@ -200,6 +225,15 @@ static int ehci_platform_probe(struct platform_device *dev) - if (err) - goto err_put_clks; - -+ priv->vbus_supply = devm_regulator_get_optional(&dev->dev, "vbus"); -+ if (IS_ERR(priv->vbus_supply)) { -+ err = PTR_ERR(priv->vbus_supply); -+ if (err == -ENODEV) -+ priv->vbus_supply = NULL; -+ else -+ goto err_reset; -+ } -+ - if (pdata->big_endian_desc) - ehci->big_endian_desc = 1; - if (pdata->big_endian_mmio) -@@ -245,12 +279,24 @@ static int ehci_platform_probe(struct platform_device *dev) - if (err) - goto err_power; - -+ priv->wakeirq = platform_get_irq(dev, 1); -+ if (priv->wakeirq > 0) { -+ err = dev_pm_set_dedicated_wake_irq(hcd->self.controller, -+ priv->wakeirq); -+ if (err) -+ goto err_hcd; -+ } else if (priv->wakeirq == -EPROBE_DEFER) { -+ goto err_hcd; -+ } -+ - device_wakeup_enable(hcd->self.controller); - device_enable_async_suspend(hcd->self.controller); - platform_set_drvdata(dev, hcd); - - return err; - -+err_hcd: -+ usb_remove_hcd(hcd); - err_power: - if (pdata->power_off) - pdata->power_off(dev); -@@ -275,6 +321,9 @@ static int ehci_platform_remove(struct platform_device *dev) - struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk; - -+ if (priv->wakeirq > 0) -+ dev_pm_clear_wake_irq(hcd->self.controller); -+ - usb_remove_hcd(hcd); - - if (pdata->power_off) -@@ -299,9 +348,14 @@ static int ehci_platform_suspend(struct device *dev) - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev_get_platdata(dev); - struct platform_device *pdev = to_platform_device(dev); -+ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - bool do_wakeup = device_may_wakeup(dev); - int ret; - -+ if (priv->wakeirq > 0 && -+ (do_wakeup || dev->power.wakeup_path)) -+ enable_irq_wake(priv->wakeirq); -+ - ret = ehci_suspend(hcd, do_wakeup); - if (ret) - return ret; -@@ -333,6 +387,11 @@ static int ehci_platform_resume(struct device *dev) - } - - ehci_resume(hcd, priv->reset_on_resume); -+ -+ if (priv->wakeirq > 0 && -+ (device_may_wakeup(dev) || dev->power.wakeup_path)) -+ disable_irq_wake(priv->wakeirq); -+ - return 0; - } - #endif /* CONFIG_PM_SLEEP */ -diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig -index 00878c3..1dbbf16 100644 ---- a/drivers/usb/typec/Kconfig -+++ b/drivers/usb/typec/Kconfig -@@ -102,6 +102,15 @@ config TYPEC_TPS6598X - If you choose to build this driver as a dynamically linked module, the - module will be called tps6598x.ko. - -+config TYPEC_STUSB -+ tristate "STMicroelectronics STUSB Type-C controller driver" -+ depends on I2C -+ select EXTCON -+ help -+ The STMicroelectronics STUSB Type-C controller driver that works -+ with Type-C Port Controller Manager to provide USB Type-C -+ functionalities. -+ - source "drivers/usb/typec/mux/Kconfig" - - source "drivers/usb/typec/altmodes/Kconfig" -diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile -index 45b0aef..aedb153 100644 ---- a/drivers/usb/typec/Makefile -+++ b/drivers/usb/typec/Makefile -@@ -7,6 +7,7 @@ obj-y += fusb302/ - obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o - obj-$(CONFIG_TYPEC_UCSI) += ucsi/ - obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o -+obj-$(CONFIG_TYPEC_STUSB) += typec_stusb.o - obj-$(CONFIG_TYPEC) += mux/ - obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o - obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o -diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c -index 1916ee1..df4cadd 100644 ---- a/drivers/usb/typec/class.c -+++ b/drivers/usb/typec/class.c -@@ -1382,6 +1382,21 @@ void typec_set_pwr_opmode(struct typec_port *port, - EXPORT_SYMBOL_GPL(typec_set_pwr_opmode); - - /** -+ * typec_find_power_opmode - Get the typec port power operation mode -+ * @name: port power operation mode string -+ * -+ * This routine is used to find the typec_pwr_opmodes by its string name. -+ * -+ * Returns typec_pwr_opmodes if success, otherwise negative error code. -+ */ -+int typec_find_port_power_opmode(const char *name) -+{ -+ return match_string(typec_pwr_opmodes, -+ ARRAY_SIZE(typec_pwr_opmodes), name); -+} -+EXPORT_SYMBOL_GPL(typec_find_port_power_opmode); -+ -+/** - * typec_find_port_power_role - Get the typec port power capability - * @name: port power capability string - * -diff --git a/drivers/usb/typec/typec_stusb.c b/drivers/usb/typec/typec_stusb.c -new file mode 100644 -index 0000000..86737dc ---- /dev/null -+++ b/drivers/usb/typec/typec_stusb.c -@@ -0,0 +1,918 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * STMicroelectronics STUSB Type-C controller family driver -+ * -+ * Copyright (C) 2019, STMicroelectronics -+ * Author(s): Amelie Delaunay -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define STUSB_ALERT_STATUS 0x0B /* RC */ -+#define STUSB_ALERT_STATUS_MASK_CTRL 0x0C /* RW */ -+#define STUSB_CC_CONNECTION_STATUS_TRANS 0x0D /* RC */ -+#define STUSB_CC_CONNECTION_STATUS 0x0E /* RO */ -+#define STUSB_MONITORING_STATUS_TRANS 0x0F /* RC */ -+#define STUSB_MONITORING_STATUS 0x10 /* RO */ -+#define STUSB_CC_OPERATION_STATUS 0x11 /* RO */ -+#define STUSB_HW_FAULT_STATUS_TRANS 0x12 /* RC */ -+#define STUSB_HW_FAULT_STATUS 0x13 /* RO */ -+#define STUSB_CC_CAPABILITY_CTRL 0x18 /* RW */ -+#define STUSB_CC_VCONN_SWITCH_CTRL 0x1E /* RW */ -+#define STUSB_VCONN_MONITORING_CTRL 0x20 /* RW */ -+#define STUSB_VBUS_MONITORING_RANGE_CTRL 0x22 /* RW */ -+#define STUSB_RESET_CTRL 0x23 /* RW */ -+#define STUSB_VBUS_DISCHARGE_TIME_CTRL 0x25 /* RW */ -+#define STUSB_VBUS_DISCHARGE_STATUS 0x26 /* RO */ -+#define STUSB_VBUS_ENABLE_STATUS 0x27 /* RO */ -+#define STUSB_CC_POWER_MODE_CTRL 0x28 /* RW */ -+#define STUSB_VBUS_MONITORING_CTRL 0x2E /* RW */ -+#define STUSB1600_REG_MAX 0x2F /* RO - Reserved */ -+ -+/* STUSB_ALERT_STATUS/STUSB_ALERT_STATUS_MASK_CTRL bitfields */ -+#define STUSB_HW_FAULT BIT(4) -+#define STUSB_MONITORING BIT(5) -+#define STUSB_CC_CONNECTION BIT(6) -+#define STUSB_ALL_ALERTS GENMASK(6, 4) -+ -+/* STUSB_CC_CONNECTION_STATUS_TRANS bitfields */ -+#define STUSB_CC_ATTACH_TRANS BIT(0) -+ -+/* STUSB_CC_CONNECTION_STATUS bitfields */ -+#define STUSB_CC_ATTACH BIT(0) -+#define STUSB_CC_VCONN_SUPPLY BIT(1) -+#define STUSB_CC_DATA_ROLE(s) (!!((s) & BIT(2))) -+#define STUSB_CC_POWER_ROLE(s) (!!((s) & BIT(3))) -+#define STUSB_CC_ATTACHED_MODE GENMASK(7, 5) -+ -+/* STUSB_MONITORING_STATUS_TRANS bitfields */ -+#define STUSB_VCONN_PRESENCE_TRANS BIT(0) -+#define STUSB_VBUS_PRESENCE_TRANS BIT(1) -+#define STUSB_VBUS_VSAFE0V_TRANS BIT(2) -+#define STUSB_VBUS_VALID_TRANS BIT(3) -+ -+/* STUSB_MONITORING_STATUS bitfields */ -+#define STUSB_VCONN_PRESENCE BIT(0) -+#define STUSB_VBUS_PRESENCE BIT(1) -+#define STUSB_VBUS_VSAFE0V BIT(2) -+#define STUSB_VBUS_VALID BIT(3) -+ -+/* STUSB_CC_OPERATION_STATUS bitfields */ -+#define STUSB_TYPEC_FSM_STATE GENMASK(4, 0) -+#define STUSB_SINK_POWER_STATE GENMASK(6, 5) -+#define STUSB_CC_ATTACHED BIT(7) -+ -+/* STUSB_HW_FAULT_STATUS_TRANS bitfields */ -+#define STUSB_VCONN_SW_OVP_FAULT_TRANS BIT(0) -+#define STUSB_VCONN_SW_OCP_FAULT_TRANS BIT(1) -+#define STUSB_VCONN_SW_RVP_FAULT_TRANS BIT(2) -+#define STUSB_VPU_VALID_TRANS BIT(4) -+#define STUSB_VPU_OVP_FAULT_TRANS BIT(5) -+#define STUSB_THERMAL_FAULT BIT(7) -+ -+/* STUSB_HW_FAULT_STATUS bitfields */ -+#define STUSB_VCONN_SW_OVP_FAULT_CC2 BIT(0) -+#define STUSB_VCONN_SW_OVP_FAULT_CC1 BIT(1) -+#define STUSB_VCONN_SW_OCP_FAULT_CC2 BIT(2) -+#define STUSB_VCONN_SW_OCP_FAULT_CC1 BIT(3) -+#define STUSB_VCONN_SW_RVP_FAULT_CC2 BIT(4) -+#define STUSB_VCONN_SW_RVP_FAULT_CC1 BIT(5) -+#define STUSB_VPU_VALID BIT(6) -+#define STUSB_VPU_OVP_FAULT BIT(7) -+ -+/* STUSB_CC_CAPABILITY_CTRL bitfields */ -+#define STUSB_CC_VCONN_SUPPLY_EN BIT(0) -+#define STUSB_CC_VCONN_DISCHARGE_EN BIT(4) -+#define STUSB_CC_CURRENT_ADVERTISED GENMASK(7, 6) -+ -+/* STUSB_VCONN_SWITCH_CTRL bitfields */ -+#define STUSB_CC_VCONN_SWITCH_ILIM GENMASK(3, 0) -+ -+/* STUSB_VCONN_MONITORING_CTRL bitfields */ -+#define STUSB_VCONN_UVLO_THRESHOLD BIT(6) -+#define STUSB_VCONN_MONITORING_EN BIT(7) -+ -+/* STUSB_VBUS_MONITORING_RANGE_CTRL bitfields */ -+#define STUSB_SHIFT_LOW_VBUS_LIMIT GENMASK(3, 0) -+#define STUSB_SHIFT_HIGH_VBUS_LIMIT GENMASK(7, 4) -+ -+/* STUSB_RESET_CTRL bitfields */ -+#define STUSB_SW_RESET_EN BIT(0) -+ -+/* STUSB_VBUS_DISCHARGE_TIME_CTRL bitfields */ -+#define STUSBXX02_VBUS_DISCHARGE_TIME_TO_PDO GENMASK(3, 0) -+#define STUSB_VBUS_DISCHARGE_TIME_TO_0V GENMASK(7, 4) -+ -+/* STUSB_VBUS_DISCHARGE_STATUS bitfields */ -+#define STUSB_VBUS_DISCHARGE_EN BIT(7) -+ -+/* STUSB_VBUS_ENABLE_STATUS bitfields */ -+#define STUSB_VBUS_SOURCE_EN BIT(0) -+#define STUSB_VBUS_SINK_EN BIT(1) -+ -+/* STUSB_CC_POWER_MODE_CTRL bitfields */ -+#define STUSB_CC_POWER_MODE GENMASK(2, 0) -+ -+/* STUSB_VBUS_MONITORING_CTRL bitfields */ -+#define STUSB_VDD_UVLO_DISABLE BIT(0) -+#define STUSB_VBUS_VSAFE0V_THRESHOLD GENMASK(2, 1) -+#define STUSB_VBUS_RANGE_DISABLE BIT(4) -+#define STUSB_VDD_OVLO_DISABLE BIT(6) -+ -+enum stusb_pwr_mode { -+ SOURCE_WITH_ACCESSORY, -+ SINK_WITH_ACCESSORY, -+ SINK_WITHOUT_ACCESSORY, -+ DUAL_WITH_ACCESSORY, -+ DUAL_WITH_ACCESSORY_AND_TRY_SRC, -+ DUAL_WITH_ACCESSORY_AND_TRY_SNK, -+}; -+ -+enum stusb_attached_mode { -+ NO_DEVICE_ATTACHED, -+ SINK_ATTACHED, -+ SOURCE_ATTACHED, -+ DEBUG_ACCESSORY_ATTACHED, -+ AUDIO_ACCESSORY_ATTACHED, -+}; -+ -+struct stusb { -+ struct device *dev; -+ struct regmap *regmap; -+ struct regulator *vdd_supply; -+ struct regulator *vsys_supply; -+ struct regulator *vconn_supply; -+ struct regulator *main_supply; -+ -+ struct typec_port *port; -+ struct typec_capability capability; -+ struct typec_partner *partner; -+ -+ enum typec_port_type port_type; -+ enum typec_pwr_opmode pwr_opmode; -+ bool vbus_on; -+ struct extcon_dev *edev; -+ struct work_struct wq_detcable; -+}; -+ -+static const unsigned int stusb_extcon_cable[] = { -+ EXTCON_USB, -+ EXTCON_USB_HOST, -+ EXTCON_NONE, -+}; -+ -+static bool stusb_reg_writeable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case STUSB_ALERT_STATUS_MASK_CTRL: -+ case STUSB_CC_CAPABILITY_CTRL: -+ case STUSB_CC_VCONN_SWITCH_CTRL: -+ case STUSB_VCONN_MONITORING_CTRL: -+ case STUSB_VBUS_MONITORING_RANGE_CTRL: -+ case STUSB_RESET_CTRL: -+ case STUSB_VBUS_DISCHARGE_TIME_CTRL: -+ case STUSB_CC_POWER_MODE_CTRL: -+ case STUSB_VBUS_MONITORING_CTRL: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool stusb_reg_readable(struct device *dev, unsigned int reg) -+{ -+ if (reg <= 0x0A || -+ (reg >= 0x14 && reg <= 0x17) || -+ (reg >= 0x19 && reg <= 0x1D) || -+ (reg >= 0x29 && reg <= 0x2D) || -+ (reg == 0x1F || reg == 0x21 || reg == 0x24 || reg == 0x2F)) -+ return false; -+ else -+ return true; -+} -+ -+static bool stusb_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case STUSB_ALERT_STATUS: -+ case STUSB_CC_CONNECTION_STATUS_TRANS: -+ case STUSB_CC_CONNECTION_STATUS: -+ case STUSB_MONITORING_STATUS_TRANS: -+ case STUSB_MONITORING_STATUS: -+ case STUSB_CC_OPERATION_STATUS: -+ case STUSB_HW_FAULT_STATUS_TRANS: -+ case STUSB_HW_FAULT_STATUS: -+ case STUSB_VBUS_DISCHARGE_STATUS: -+ case STUSB_VBUS_ENABLE_STATUS: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool stusb_reg_precious(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case STUSB_ALERT_STATUS: -+ case STUSB_CC_CONNECTION_STATUS_TRANS: -+ case STUSB_MONITORING_STATUS_TRANS: -+ case STUSB_HW_FAULT_STATUS_TRANS: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static const struct regmap_config stusb1600_regmap_config = { -+ .reg_bits = 8, -+ .reg_stride = 1, -+ .val_bits = 8, -+ .max_register = STUSB1600_REG_MAX, -+ .writeable_reg = stusb_reg_writeable, -+ .readable_reg = stusb_reg_readable, -+ .volatile_reg = stusb_reg_volatile, -+ .precious_reg = stusb_reg_precious, -+ .cache_type = REGCACHE_RBTREE, -+}; -+ -+static void stusb_extcon_detect_cable(struct work_struct *work) -+{ -+ struct stusb *chip = container_of(work, struct stusb, wq_detcable); -+ u32 conn_status, vbus_status; -+ bool id, vbus; -+ int ret; -+ -+ /* Check ID and Vbus to update cable state */ -+ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, -+ &conn_status); -+ if (ret) -+ return; -+ -+ ret = regmap_read(chip->regmap, STUSB_VBUS_ENABLE_STATUS, -+ &vbus_status); -+ if (ret) -+ return; -+ -+ /* 0 = Device, 1 = Host */ -+ id = STUSB_CC_DATA_ROLE(conn_status); -+ -+ if (STUSB_CC_POWER_ROLE(conn_status)) /* Source */ -+ vbus = !!(vbus_status & STUSB_VBUS_SOURCE_EN); -+ else /* Sink */ -+ vbus = !!(vbus_status & STUSB_VBUS_SINK_EN); -+ -+ dev_dbg(chip->dev, "role=%s vbus=%sable\n", -+ id ? "Host" : "Device", vbus ? "en" : "dis"); -+ -+ /* -+ * !vbus = detached, so neither B-Session Valid nor A-Session Valid -+ * !vbus = !EXTCON_USB && !EXTCON_USB_HOST -+ * vbus = attached, so either B-Session Valid or A-Session Valid -+ * vbus && !id = B-Session Valid = EXTCON_USB && !EXTCON_USB_HOST -+ * vbus && id = A-Session Valid = !EXTCON_USB && EXTCON_USB_HOST -+ */ -+ -+ if (!vbus || !id) /* Detached or B-Session */ -+ extcon_set_state_sync(chip->edev, EXTCON_USB_HOST, false); -+ if (!vbus || id) /* Detached or A-Session */ -+ extcon_set_state_sync(chip->edev, EXTCON_USB, false); -+ -+ if (vbus && id) /* Attached and A-Session Valid */ -+ extcon_set_state_sync(chip->edev, EXTCON_USB_HOST, true); -+ if (vbus && !id) /* Attached and B-Session Valid */ -+ extcon_set_state_sync(chip->edev, EXTCON_USB, true); -+} -+ -+static bool stusb_get_vconn(struct stusb *chip) -+{ -+ u32 val; -+ int ret; -+ -+ ret = regmap_read(chip->regmap, STUSB_CC_CAPABILITY_CTRL, &val); -+ if (ret) { -+ dev_err(chip->dev, "Unable to get Vconn status: %d\n", ret); -+ return false; -+ } -+ -+ return !!FIELD_GET(STUSB_CC_VCONN_SUPPLY_EN, val); -+} -+ -+static int stusb_set_vconn(struct stusb *chip, bool on) -+{ -+ int ret; -+ -+ /* Manage VCONN input supply */ -+ if (chip->vconn_supply) { -+ if (on) { -+ ret = regulator_enable(chip->vconn_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "failed to enable vconn supply: %d\n", -+ ret); -+ return ret; -+ } -+ } else { -+ regulator_disable(chip->vconn_supply); -+ } -+ } -+ -+ /* Manage VCONN monitoring and power path */ -+ ret = regmap_update_bits(chip->regmap, STUSB_VCONN_MONITORING_CTRL, -+ STUSB_VCONN_MONITORING_EN, -+ on ? STUSB_VCONN_MONITORING_EN : 0); -+ if (ret) -+ goto vconn_reg_disable; -+ -+ return 0; -+ -+vconn_reg_disable: -+ if (chip->vconn_supply && on) -+ regulator_disable(chip->vconn_supply); -+ -+ return ret; -+} -+ -+static enum typec_pwr_opmode stusb_get_pwr_opmode(struct stusb *chip) -+{ -+ u32 val; -+ int ret; -+ -+ ret = regmap_read(chip->regmap, STUSB_CC_CAPABILITY_CTRL, &val); -+ if (ret) { -+ dev_err(chip->dev, "Unable to get pwr opmode: %d\n", ret); -+ return TYPEC_PWR_MODE_USB; -+ } -+ -+ return FIELD_GET(STUSB_CC_CURRENT_ADVERTISED, val); -+} -+ -+static enum typec_accessory stusb_get_accessory(u32 status) -+{ -+ enum stusb_attached_mode mode; -+ -+ mode = FIELD_GET(STUSB_CC_ATTACHED_MODE, status); -+ -+ switch (mode) { -+ case DEBUG_ACCESSORY_ATTACHED: -+ return TYPEC_ACCESSORY_DEBUG; -+ case AUDIO_ACCESSORY_ATTACHED: -+ return TYPEC_ACCESSORY_AUDIO; -+ default: -+ return TYPEC_ACCESSORY_NONE; -+ } -+} -+ -+static enum typec_role stusb_get_vconn_role(u32 status) -+{ -+ if (FIELD_GET(STUSB_CC_VCONN_SUPPLY, status)) -+ return TYPEC_SOURCE; -+ else -+ return TYPEC_SINK; -+} -+ -+static int stusb_attach(struct stusb *chip, u32 status) -+{ -+ struct typec_partner_desc desc; -+ int ret; -+ -+ if ((STUSB_CC_POWER_ROLE(status) == TYPEC_SOURCE) && -+ chip->vdd_supply) { -+ ret = regulator_enable(chip->vdd_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to enable Vbus supply: %d\n", ret); -+ return ret; -+ } -+ chip->vbus_on = true; -+ } -+ -+ desc.usb_pd = false; -+ desc.accessory = stusb_get_accessory(status); -+ desc.identity = NULL; -+ -+ chip->partner = typec_register_partner(chip->port, &desc); -+ if (IS_ERR(chip->partner)) { -+ ret = PTR_ERR(chip->partner); -+ goto vbus_disable; -+ } -+ -+ typec_set_pwr_role(chip->port, STUSB_CC_POWER_ROLE(status)); -+ typec_set_pwr_opmode(chip->port, stusb_get_pwr_opmode(chip)); -+ typec_set_vconn_role(chip->port, stusb_get_vconn_role(status)); -+ typec_set_data_role(chip->port, STUSB_CC_DATA_ROLE(status)); -+ -+ queue_work(system_power_efficient_wq, &chip->wq_detcable); -+ -+ return 0; -+ -+vbus_disable: -+ if (chip->vbus_on) { -+ regulator_disable(chip->vdd_supply); -+ chip->vbus_on = false; -+ } -+ -+ return ret; -+} -+ -+static void stusb_detach(struct stusb *chip, u32 status) -+{ -+ typec_unregister_partner(chip->partner); -+ chip->partner = NULL; -+ -+ queue_work(system_power_efficient_wq, &chip->wq_detcable); -+ -+ typec_set_pwr_role(chip->port, STUSB_CC_POWER_ROLE(status)); -+ typec_set_pwr_opmode(chip->port, TYPEC_PWR_MODE_USB); -+ typec_set_vconn_role(chip->port, stusb_get_vconn_role(status)); -+ typec_set_data_role(chip->port, STUSB_CC_DATA_ROLE(status)); -+ -+ if (chip->vbus_on) { -+ regulator_disable(chip->vdd_supply); -+ chip->vbus_on = false; -+ } -+} -+ -+static irqreturn_t stusb_irq_handler(int irq, void *data) -+{ -+ struct stusb *chip = data; -+ u32 pending, trans, status; -+ int ret; -+ -+ ret = regmap_read(chip->regmap, STUSB_ALERT_STATUS, &pending); -+ if (ret) -+ return IRQ_NONE; -+ -+ if (pending & STUSB_CC_CONNECTION) { -+ ret = regmap_read(chip->regmap, -+ STUSB_CC_CONNECTION_STATUS_TRANS, &trans); -+ if (ret) -+ goto err; -+ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, -+ &status); -+ if (ret) -+ goto err; -+ -+ if (trans & STUSB_CC_ATTACH_TRANS) { -+ if (status & STUSB_CC_ATTACH) { -+ ret = stusb_attach(chip, status); -+ if (ret) -+ goto err; -+ } else { -+ stusb_detach(chip, status); -+ } -+ } -+ } -+err: -+ return IRQ_HANDLED; -+} -+ -+static int stusb_irq_init(struct stusb *chip, int irq) -+{ -+ u32 status; -+ int ret; -+ -+ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, &status); -+ if (ret) -+ return ret; -+ -+ if (status & STUSB_CC_ATTACH) { -+ ret = stusb_attach(chip, status); -+ if (ret) -+ dev_err(chip->dev, "attach failed: %d\n", ret); -+ } -+ -+ ret = devm_request_threaded_irq(chip->dev, irq, NULL, stusb_irq_handler, -+ IRQF_ONESHOT, dev_name(chip->dev), -+ chip); -+ if (ret) -+ goto partner_unregister; -+ -+ /* Unmask CC_CONNECTION events */ -+ ret = regmap_write_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, -+ STUSB_CC_CONNECTION, 0); -+ if (ret) -+ goto partner_unregister; -+ -+ return 0; -+ -+partner_unregister: -+ if (chip->partner) { -+ typec_unregister_partner(chip->partner); -+ chip->partner = NULL; -+ } -+ -+ return ret; -+} -+ -+static int stusb_init(struct stusb *chip) -+{ -+ u32 val; -+ int ret; -+ -+ /* Change the default Type-C power mode */ -+ if (chip->port_type == TYPEC_PORT_SRC) -+ ret = regmap_update_bits(chip->regmap, -+ STUSB_CC_POWER_MODE_CTRL, -+ STUSB_CC_POWER_MODE, -+ SOURCE_WITH_ACCESSORY); -+ else if (chip->port_type == TYPEC_PORT_SNK) -+ ret = regmap_update_bits(chip->regmap, -+ STUSB_CC_POWER_MODE_CTRL, -+ STUSB_CC_POWER_MODE, -+ SINK_WITH_ACCESSORY); -+ else /* (capability->type == TYPEC_PORT_DRP) */ -+ ret = regmap_update_bits(chip->regmap, -+ STUSB_CC_POWER_MODE_CTRL, -+ STUSB_CC_POWER_MODE, -+ DUAL_WITH_ACCESSORY); -+ if (ret) -+ return ret; -+ -+ if (chip->port_type == TYPEC_PORT_SNK) -+ goto skip_src; -+ -+ /* Change the default Type-C Source power operation mode capability */ -+ ret = regmap_update_bits(chip->regmap, STUSB_CC_CAPABILITY_CTRL, -+ STUSB_CC_CURRENT_ADVERTISED, -+ FIELD_PREP(STUSB_CC_CURRENT_ADVERTISED, -+ chip->pwr_opmode)); -+ if (ret) -+ return ret; -+ -+ /* Manage Type-C Source Vconn supply */ -+ if (stusb_get_vconn(chip)) { -+ ret = stusb_set_vconn(chip, true); -+ if (ret) -+ return ret; -+ } -+ -+skip_src: -+ /* Mask all events interrupts - to be unmasked with interrupt support */ -+ ret = regmap_update_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, -+ STUSB_ALL_ALERTS, STUSB_ALL_ALERTS); -+ if (ret) -+ return ret; -+ -+ /* Read status at least once to clear any stale interrupts */ -+ regmap_read(chip->regmap, STUSB_ALERT_STATUS, &val); -+ regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS_TRANS, &val); -+ regmap_read(chip->regmap, STUSB_MONITORING_STATUS_TRANS, &val); -+ regmap_read(chip->regmap, STUSB_HW_FAULT_STATUS_TRANS, &val); -+ -+ return 0; -+} -+ -+static int stusb_fw_get_caps(struct stusb *chip) -+{ -+ struct fwnode_handle *fwnode = device_get_named_child_node(chip->dev, -+ "connector"); -+ const char *cap_str; -+ int ret; -+ -+ if (!fwnode) -+ return -EINVAL; -+ -+ chip->capability.fwnode = fwnode; -+ -+ ret = fwnode_property_read_string(fwnode, "power-role", &cap_str); -+ if (!ret) { -+ chip->port_type = typec_find_port_power_role(cap_str); -+ if (chip->port_type < 0) -+ return -EINVAL; -+ -+ chip->capability.type = chip->port_type; -+ } -+ -+ if (chip->port_type == TYPEC_PORT_SNK) -+ goto sink; -+ -+ if (chip->port_type == TYPEC_PORT_DRP) -+ chip->capability.prefer_role = TYPEC_SINK; -+ -+ ret = fwnode_property_read_string(fwnode, "power-opmode", &cap_str); -+ if (!ret) { -+ chip->pwr_opmode = typec_find_port_power_opmode(cap_str); -+ -+ /* Power delivery not yet supported */ -+ if (chip->pwr_opmode < 0 || -+ chip->pwr_opmode == TYPEC_PWR_MODE_PD) { -+ dev_err(chip->dev, "bad power operation mode: %d\n", -+ chip->pwr_opmode); -+ return -EINVAL; -+ } -+ -+ } else { -+ chip->pwr_opmode = stusb_get_pwr_opmode(chip); -+ } -+ -+sink: -+ return 0; -+} -+ -+static int stusb_get_caps(struct stusb *chip, bool *try) -+{ -+ enum typec_port_type *type = &chip->capability.type; -+ enum typec_port_data *data = &chip->capability.data; -+ enum typec_accessory *accessory = chip->capability.accessory; -+ u32 val; -+ int ret; -+ -+ chip->capability.revision = USB_TYPEC_REV_1_2; -+ -+ ret = regmap_read(chip->regmap, STUSB_CC_POWER_MODE_CTRL, &val); -+ if (ret) -+ return ret; -+ -+ *try = false; -+ -+ switch (FIELD_GET(STUSB_CC_POWER_MODE, val)) { -+ case SOURCE_WITH_ACCESSORY: -+ *type = TYPEC_PORT_SRC; -+ *data = TYPEC_PORT_DFP; -+ *accessory++ = TYPEC_ACCESSORY_AUDIO; -+ *accessory++ = TYPEC_ACCESSORY_DEBUG; -+ break; -+ case SINK_WITH_ACCESSORY: -+ *type = TYPEC_PORT_SNK; -+ *data = TYPEC_PORT_UFP; -+ *accessory++ = TYPEC_ACCESSORY_AUDIO; -+ *accessory++ = TYPEC_ACCESSORY_DEBUG; -+ break; -+ case SINK_WITHOUT_ACCESSORY: -+ *type = TYPEC_PORT_SNK; -+ *data = TYPEC_PORT_UFP; -+ break; -+ case DUAL_WITH_ACCESSORY: -+ *type = TYPEC_PORT_DRP; -+ *data = TYPEC_PORT_DRD; -+ *accessory++ = TYPEC_ACCESSORY_AUDIO; -+ *accessory++ = TYPEC_ACCESSORY_DEBUG; -+ break; -+ case DUAL_WITH_ACCESSORY_AND_TRY_SRC: -+ case DUAL_WITH_ACCESSORY_AND_TRY_SNK: -+ *type = TYPEC_PORT_DRP; -+ *data = TYPEC_PORT_DRD; -+ *accessory++ = TYPEC_ACCESSORY_AUDIO; -+ *accessory++ = TYPEC_ACCESSORY_DEBUG; -+ *try = true; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ chip->port_type = *type; -+ -+ return stusb_fw_get_caps(chip); -+} -+ -+static const struct of_device_id stusb_of_match[] = { -+ { .compatible = "st,stusb1600", .data = &stusb1600_regmap_config}, -+ {}, -+}; -+ -+static int stusb_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct stusb *chip; -+ const struct of_device_id *match; -+ struct regmap_config *regmap_config; -+ bool try_role; -+ int ret; -+ -+ chip = devm_kzalloc(&client->dev, sizeof(struct stusb), GFP_KERNEL); -+ if (!chip) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, chip); -+ -+ match = i2c_of_match_device(stusb_of_match, client); -+ regmap_config = (struct regmap_config *)match->data; -+ chip->regmap = devm_regmap_init_i2c(client, regmap_config); -+ if (IS_ERR(chip->regmap)) { -+ ret = PTR_ERR(chip->regmap); -+ dev_err(&client->dev, -+ "Failed to allocate register map:%d\n", ret); -+ return ret; -+ } -+ -+ chip->dev = &client->dev; -+ -+ chip->vsys_supply = devm_regulator_get_optional(chip->dev, "vsys"); -+ if (IS_ERR(chip->vsys_supply)) { -+ ret = PTR_ERR(chip->vsys_supply); -+ if (ret != -ENODEV) -+ return ret; -+ chip->vsys_supply = NULL; -+ } -+ -+ chip->vdd_supply = devm_regulator_get_optional(chip->dev, "vdd"); -+ if (IS_ERR(chip->vdd_supply)) { -+ ret = PTR_ERR(chip->vdd_supply); -+ if (ret != -ENODEV) -+ return ret; -+ chip->vdd_supply = NULL; -+ } -+ -+ chip->vconn_supply = devm_regulator_get_optional(chip->dev, "vconn"); -+ if (IS_ERR(chip->vconn_supply)) { -+ ret = PTR_ERR(chip->vconn_supply); -+ if (ret != -ENODEV) -+ return ret; -+ chip->vconn_supply = NULL; -+ } -+ -+ /* -+ * When both VDD and VSYS power supplies are present, the low power -+ * supply VSYS is selected when VSYS voltage is above 3.1 V. -+ * Otherwise VDD is selected. -+ */ -+ if (chip->vdd_supply && -+ (!chip->vsys_supply || -+ (regulator_get_voltage(chip->vsys_supply) <= 3100000))) -+ chip->main_supply = chip->vdd_supply; -+ else -+ chip->main_supply = chip->vsys_supply; -+ -+ if (chip->main_supply) { -+ ret = regulator_enable(chip->main_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to enable main supply: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = stusb_get_caps(chip, &try_role); -+ if (ret) { -+ dev_err(chip->dev, "Failed to get port caps: %d\n", ret); -+ goto main_reg_disable; -+ } -+ -+ ret = stusb_init(chip); -+ if (ret) { -+ dev_err(chip->dev, "Failed to init port: %d\n", ret); -+ goto main_reg_disable; -+ } -+ -+ chip->port = typec_register_port(chip->dev, &chip->capability); -+ if (!chip->port) { -+ ret = -ENODEV; -+ goto all_reg_disable; -+ } -+ -+ /* -+ * Default power operation mode initialization: will be updated upon -+ * attach/detach interrupt -+ */ -+ typec_set_pwr_opmode(chip->port, chip->pwr_opmode); -+ -+ if (!client->irq) { -+ /* -+ * If Source or Dual power role, need to enable VDD supply -+ * providing Vbus if present. In case of interrupt support, -+ * VDD supply will be dynamically managed upon attach/detach -+ * interrupt. -+ */ -+ if ((chip->port_type != TYPEC_PORT_SNK) && chip->vdd_supply) { -+ ret = regulator_enable(chip->vdd_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to enable VDD supply: %d\n", -+ ret); -+ goto port_unregister; -+ } -+ chip->vbus_on = true; -+ } -+ -+ return 0; -+ } -+ -+ chip->edev = devm_extcon_dev_allocate(chip->dev, stusb_extcon_cable); -+ if (IS_ERR(chip->edev)) { -+ ret = PTR_ERR(chip->edev); -+ dev_err(chip->dev, -+ "Failed to allocate extcon device: %d\n", ret); -+ goto port_unregister; -+ } -+ -+ ret = devm_extcon_dev_register(chip->dev, chip->edev); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to register extcon device: %d\n", ret); -+ goto port_unregister; -+ } -+ -+ INIT_WORK(&chip->wq_detcable, stusb_extcon_detect_cable); -+ -+ ret = stusb_irq_init(chip, client->irq); -+ if (ret) -+ goto cancel_work_sync; -+ -+ return 0; -+ -+cancel_work_sync: -+ cancel_work_sync(&chip->wq_detcable); -+port_unregister: -+ typec_unregister_port(chip->port); -+all_reg_disable: -+ if (stusb_get_vconn(chip)) -+ stusb_set_vconn(chip, false); -+main_reg_disable: -+ if (chip->main_supply) -+ regulator_disable(chip->main_supply); -+ -+ return ret; -+} -+ -+static int stusb_remove(struct i2c_client *client) -+{ -+ struct stusb *chip = i2c_get_clientdata(client); -+ -+ if (chip->partner) { -+ typec_unregister_partner(chip->partner); -+ chip->partner = NULL; -+ } -+ -+ if (chip->vbus_on) -+ regulator_disable(chip->vdd_supply); -+ -+ if (chip->edev) -+ cancel_work_sync(&chip->wq_detcable); -+ -+ typec_unregister_port(chip->port); -+ -+ if (stusb_get_vconn(chip)) -+ stusb_set_vconn(chip, false); -+ -+ if (chip->main_supply) -+ regulator_disable(chip->main_supply); -+ -+ return 0; -+} -+ -+static int __maybe_unused stusb_suspend(struct device *dev) -+{ -+ struct stusb *chip = dev_get_drvdata(dev); -+ -+ /* Mask interrupts */ -+ return regmap_update_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, -+ STUSB_ALL_ALERTS, STUSB_ALL_ALERTS); -+} -+ -+static int __maybe_unused stusb_resume(struct device *dev) -+{ -+ struct stusb *chip = dev_get_drvdata(dev); -+ u32 status; -+ int ret; -+ -+ ret = regcache_sync(chip->regmap); -+ if (ret) -+ return ret; -+ -+ /* Unmask CC_CONNECTION events - chip->edev implies IRQ support */ -+ if (chip->edev) -+ return regmap_write_bits(chip->regmap, -+ STUSB_ALERT_STATUS_MASK_CTRL, -+ STUSB_CC_CONNECTION, 0); -+ -+ /* Check if attach/detach occurred during low power */ -+ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, &status); -+ if (ret) -+ return ret; -+ -+ if (chip->partner && !(status & STUSB_CC_ATTACH)) -+ stusb_detach(chip, status); -+ -+ if (!chip->partner && (status & STUSB_CC_ATTACH)) { -+ ret = stusb_attach(chip, status); -+ if (ret) -+ dev_err(chip->dev, "attach failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+static SIMPLE_DEV_PM_OPS(stusb_pm_ops, stusb_suspend, stusb_resume); -+ -+static struct i2c_driver stusb_driver = { -+ .driver = { -+ .name = "typec_stusb", -+ .pm = &stusb_pm_ops, -+ .of_match_table = stusb_of_match, -+ }, -+ .probe = stusb_probe, -+ .remove = stusb_remove, -+}; -+module_i2c_driver(stusb_driver); -+ -+MODULE_AUTHOR("Amelie Delaunay "); -+MODULE_DESCRIPTION("STMicroelectronics STUSB Type-C controller driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h -index 7df4eca..2671776 100644 ---- a/include/linux/usb/typec.h -+++ b/include/linux/usb/typec.h -@@ -241,6 +241,7 @@ int typec_set_orientation(struct typec_port *port, - enum typec_orientation typec_get_orientation(struct typec_port *port); - int typec_set_mode(struct typec_port *port, int mode); - -+int typec_find_port_power_opmode(const char *name); - int typec_find_port_power_role(const char *name); - int typec_find_power_role(const char *name); - int typec_find_port_data_role(const char *name); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch deleted file mode 100644 index e98714d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch +++ /dev/null @@ -1,361 +0,0 @@ -From 918e6c75e00bcae7481c4560ebbca237d991b2c0 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:48 +0100 -Subject: [PATCH 27/31] ARM stm32mp1 r3 WATCHDOG - ---- - drivers/watchdog/Kconfig | 12 ++++ - drivers/watchdog/Makefile | 1 + - drivers/watchdog/stm32_iwdg.c | 83 ++++++++++++++++-------- - drivers/watchdog/stpmic1_wdt.c | 140 +++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 211 insertions(+), 25 deletions(-) - create mode 100644 drivers/watchdog/stpmic1_wdt.c - -diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index b165c46..9790eca 100644 ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -806,6 +806,18 @@ config STM32_WATCHDOG - To compile this driver as a module, choose M here: the - module will be called stm32_iwdg. - -+config STPMIC1_WATCHDOG -+ tristate "STPMIC1 PMIC watchdog support" -+ depends on MFD_STPMIC1 -+ select WATCHDOG_CORE -+ help -+ Say Y here to include watchdog support embedded into STPMIC1 PMIC. -+ If the watchdog timer expires, stpmic1 will shut down all its power -+ supplies. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called spmic1_wdt. -+ - config UNIPHIER_WATCHDOG - tristate "UniPhier watchdog support" - depends on ARCH_UNIPHIER || COMPILE_TEST -diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index bf92e7b..2649cf3 100644 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -217,3 +217,4 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o - obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o - obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o - obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o -+obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o -diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c -index e00e3b3..56a3ffd 100644 ---- a/drivers/watchdog/stm32_iwdg.c -+++ b/drivers/watchdog/stm32_iwdg.c -@@ -34,18 +34,10 @@ - #define KR_KEY_EWA 0x5555 /* write access enable */ - #define KR_KEY_DWA 0x0000 /* write access disable */ - --/* IWDG_PR register bit values */ --#define PR_4 0x00 /* prescaler set to 4 */ --#define PR_8 0x01 /* prescaler set to 8 */ --#define PR_16 0x02 /* prescaler set to 16 */ --#define PR_32 0x03 /* prescaler set to 32 */ --#define PR_64 0x04 /* prescaler set to 64 */ --#define PR_128 0x05 /* prescaler set to 128 */ --#define PR_256 0x06 /* prescaler set to 256 */ -+#define PR_SHIFT 2 - - /* IWDG_RLR register values */ --#define RLR_MIN 0x07C /* min value supported by reload register */ --#define RLR_MAX 0xFFF /* max value supported by reload register */ -+#define RLR_MAX GENMASK(11, 0) /* max value of reload register */ - - /* IWDG_SR register bit mask */ - #define FLAG_PVU BIT(0) /* Watchdog prescaler value update */ -@@ -55,15 +47,28 @@ - #define TIMEOUT_US 100000 - #define SLEEP_US 1000 - --#define HAS_PCLK true -+struct stm32_iwdg_data { -+ bool has_pclk; -+ u32 max_prescaler; -+}; -+ -+static const struct stm32_iwdg_data stm32_iwdg_data = { -+ .has_pclk = false, -+ .max_prescaler = 256, -+}; -+ -+static const struct stm32_iwdg_data stm32mp1_iwdg_data = { -+ .has_pclk = true, -+ .max_prescaler = 1024, -+}; - - struct stm32_iwdg { - struct watchdog_device wdd; -+ const struct stm32_iwdg_data *data; - void __iomem *regs; - struct clk *clk_lsi; - struct clk *clk_pclk; - unsigned int rate; -- bool has_pclk; - }; - - static inline u32 reg_read(void __iomem *base, u32 reg) -@@ -80,21 +85,30 @@ static int stm32_iwdg_start(struct watchdog_device *wdd) - { - struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); - u32 val = FLAG_PVU | FLAG_RVU; -- u32 reload; -+ u32 timeout, presc, iwdg_rlr, iwdg_pr; - int ret; - - dev_dbg(wdd->parent, "%s\n", __func__); - -- /* prescaler fixed to 256 */ -- reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1, -- RLR_MIN, RLR_MAX); -+ timeout = clamp_t(unsigned int, wdd->timeout, -+ wdd->min_timeout, wdd->max_hw_heartbeat_ms / 1000); -+ -+ if (timeout != wdd->timeout) -+ dev_warn(wdd->parent, "timeout skrinked to %d\n", timeout); -+ -+ presc = DIV_ROUND_UP(timeout * wdt->rate, RLR_MAX + 1); -+ -+ /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */ -+ presc = roundup_pow_of_two(presc); -+ iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2(presc) - PR_SHIFT; -+ iwdg_rlr = ((timeout * wdt->rate) / presc) - 1; - - /* enable write access */ - reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA); - - /* set prescaler & reload registers */ -- reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */ -- reg_write(wdt->regs, IWDG_RLR, reload); -+ reg_write(wdt->regs, IWDG_PR, iwdg_pr); -+ reg_write(wdt->regs, IWDG_RLR, iwdg_rlr); - reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); - - /* wait for the registers to be updated (max 100ms) */ -@@ -150,7 +164,7 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, - } - - /* optional peripheral clock */ -- if (wdt->has_pclk) { -+ if (wdt->data->has_pclk) { - wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(wdt->clk_pclk)) { - dev_err(&pdev->dev, "Unable to get pclk clock\n"); -@@ -191,8 +205,8 @@ static const struct watchdog_ops stm32_iwdg_ops = { - }; - - static const struct of_device_id stm32_iwdg_of_match[] = { -- { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, -- { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, -+ { .compatible = "st,stm32-iwdg", .data = &stm32_iwdg_data }, -+ { .compatible = "st,stm32mp1-iwdg", .data = &stm32mp1_iwdg_data }, - { /* end node */ } - }; - MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); -@@ -206,14 +220,14 @@ static int stm32_iwdg_probe(struct platform_device *pdev) - int ret; - - match = of_match_device(stm32_iwdg_of_match, &pdev->dev); -- if (!match) -+ if (!match || !match->data) - return -ENODEV; - - wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); - if (!wdt) - return -ENOMEM; - -- wdt->has_pclk = match->data; -+ wdt->data = match->data; - - /* This is the timer base. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -231,8 +245,9 @@ static int stm32_iwdg_probe(struct platform_device *pdev) - wdd = &wdt->wdd; - wdd->info = &stm32_iwdg_info; - wdd->ops = &stm32_iwdg_ops; -- wdd->min_timeout = ((RLR_MIN + 1) * 256) / wdt->rate; -- wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 256 * 1000) / wdt->rate; -+ wdd->min_timeout = 1; -+ wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * wdt->data->max_prescaler * -+ 1000) / wdt->rate; - wdd->parent = &pdev->dev; - - watchdog_set_drvdata(wdd, wdt); -@@ -243,6 +258,24 @@ static int stm32_iwdg_probe(struct platform_device *pdev) - dev_warn(&pdev->dev, - "unable to set timeout value, using default\n"); - -+ /* -+ * In case of CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set -+ * (Means U-Boot/bootloaders leaves the watchdog running) -+ * When we get here we should make a decision to prevent -+ * any side effects before user space daemon will take care of it. -+ * The best option, taking into consideration that there is no -+ * way to read values back from hardware, is to enforce watchdog -+ * being run with deterministic values. -+ */ -+ if (IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) { -+ ret = stm32_iwdg_start(wdd); -+ if (ret) -+ return ret; -+ -+ /* Make sure the watchdog is serviced */ -+ set_bit(WDOG_HW_RUNNING, &wdd->status); -+ } -+ - ret = watchdog_register_device(wdd); - if (ret) { - dev_err(&pdev->dev, "failed to register watchdog device\n"); -diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c -new file mode 100644 -index 0000000..45d0c54 ---- /dev/null -+++ b/drivers/watchdog/stpmic1_wdt.c -@@ -0,0 +1,140 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2018 -+// Author: Pascal Paillet for STMicroelectronics. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* WATCHDOG CONTROL REGISTER bit */ -+#define WDT_START BIT(0) -+#define WDT_PING BIT(1) -+#define WDT_START_MASK BIT(0) -+#define WDT_PING_MASK BIT(1) -+#define WDT_STOP 0 -+ -+#define PMIC_WDT_MIN_TIMEOUT 1 -+#define PMIC_WDT_MAX_TIMEOUT 256 -+#define PMIC_WDT_DEFAULT_TIMEOUT 30 -+ -+static bool nowayout = WATCHDOG_NOWAYOUT; -+module_param(nowayout, bool, 0); -+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" -+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -+ -+struct stpmic1_wdt { -+ struct stpmic1 *pmic; -+ struct watchdog_device wdtdev; -+}; -+ -+static int pmic_wdt_start(struct watchdog_device *wdd) -+{ -+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); -+ -+ return regmap_update_bits(wdt->pmic->regmap, -+ WCHDG_CR, WDT_START_MASK, WDT_START); -+} -+ -+static int pmic_wdt_stop(struct watchdog_device *wdd) -+{ -+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); -+ -+ return regmap_update_bits(wdt->pmic->regmap, -+ WCHDG_CR, WDT_START_MASK, WDT_STOP); -+} -+ -+static int pmic_wdt_ping(struct watchdog_device *wdd) -+{ -+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); -+ -+ return regmap_update_bits(wdt->pmic->regmap, -+ WCHDG_CR, WDT_PING_MASK, WDT_PING); -+} -+ -+static int pmic_wdt_set_timeout(struct watchdog_device *wdd, -+ unsigned int timeout) -+{ -+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); -+ -+ wdd->timeout = timeout; -+ /* timeout is equal to register value + 1 */ -+ return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1); -+} -+ -+static const struct watchdog_info pmic_watchdog_info = { -+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, -+ .identity = "STPMIC1 PMIC Watchdog", -+}; -+ -+static const struct watchdog_ops pmic_watchdog_ops = { -+ .owner = THIS_MODULE, -+ .start = pmic_wdt_start, -+ .stop = pmic_wdt_stop, -+ .ping = pmic_wdt_ping, -+ .set_timeout = pmic_wdt_set_timeout, -+}; -+ -+static int pmic_wdt_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ int ret; -+ struct stpmic1 *pmic; -+ struct stpmic1_wdt *wdt; -+ -+ if (!dev->parent) -+ return -EINVAL; -+ -+ pmic = dev_get_drvdata(dev->parent); -+ if (!pmic) -+ return -EINVAL; -+ -+ wdt = devm_kzalloc(dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); -+ if (!wdt) -+ return -ENOMEM; -+ -+ wdt->pmic = pmic; -+ -+ wdt->wdtdev.info = &pmic_watchdog_info; -+ wdt->wdtdev.ops = &pmic_watchdog_ops; -+ wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT; -+ wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT; -+ wdt->wdtdev.parent = dev; -+ -+ wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT; -+ watchdog_init_timeout(&wdt->wdtdev, 0, dev); -+ -+ watchdog_set_nowayout(&wdt->wdtdev, nowayout); -+ watchdog_set_drvdata(&wdt->wdtdev, wdt); -+ -+ ret = devm_watchdog_register_device(dev, &wdt->wdtdev); -+ if (ret) -+ return ret; -+ -+ dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n"); -+ return 0; -+} -+ -+static const struct of_device_id of_pmic_wdt_match[] = { -+ { .compatible = "st,stpmic1-wdt" }, -+ { }, -+}; -+ -+MODULE_DEVICE_TABLE(of, of_pmic_wdt_match); -+ -+static struct platform_driver stpmic1_wdt_driver = { -+ .probe = pmic_wdt_probe, -+ .driver = { -+ .name = "stpmic1-wdt", -+ .of_match_table = of_pmic_wdt_match, -+ }, -+}; -+module_platform_driver(stpmic1_wdt_driver); -+ -+MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device"); -+MODULE_AUTHOR("Pascal Paillet "); -+MODULE_LICENSE("GPL v2"); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch deleted file mode 100644 index 24e1f9b..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch +++ /dev/null @@ -1,2806 +0,0 @@ -From f3a6e1e545c6a1810b2560ea821a3ed61b751d60 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 20 Jan 2020 18:09:29 +0100 -Subject: [PATCH 28/31] ARM stm32mp1 r3 SOUND - ---- - sound/soc/codecs/Kconfig | 4 +- - sound/soc/codecs/cs42l51-i2c.c | 34 ++- - sound/soc/codecs/cs42l51.c | 231 +++++++++++++++-- - sound/soc/codecs/cs42l51.h | 21 ++ - sound/soc/codecs/wm8994.c | 80 +++++- - sound/soc/stm/Kconfig | 1 + - sound/soc/stm/stm32_adfsdm.c | 52 +++- - sound/soc/stm/stm32_i2s.c | 186 +++++++++----- - sound/soc/stm/stm32_sai.c | 134 ++++++++-- - sound/soc/stm/stm32_sai.h | 59 ++++- - sound/soc/stm/stm32_sai_sub.c | 562 +++++++++++++++++++++++++++++++++-------- - sound/soc/stm/stm32_spdifrx.c | 132 ++++++++-- - 12 files changed, 1245 insertions(+), 251 deletions(-) - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index efb095d..58161d1 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -575,7 +575,7 @@ config SND_SOC_DA9055 - tristate - - config SND_SOC_DMIC -- tristate -+ tristate "Generic DMIC codec" - - config SND_SOC_HDMI_CODEC - tristate -@@ -1227,7 +1227,7 @@ config SND_SOC_WM8993 - tristate - - config SND_SOC_WM8994 -- tristate -+ tristate "Wolfson Microelectronics WM8994 codec" - - config SND_SOC_WM8995 - tristate -diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c -index 4b5731a..9abbd98 100644 ---- a/sound/soc/codecs/cs42l51-i2c.c -+++ b/sound/soc/codecs/cs42l51-i2c.c -@@ -29,18 +29,48 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c, - struct regmap_config config; - - config = cs42l51_regmap; -- config.val_bits = 8; -- config.reg_bits = 8; - - return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config)); - } - -+static int cs42l51_i2c_remove(struct i2c_client *i2c) -+{ -+ return cs42l51_remove(&i2c->dev); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int cs42l51_suspend(struct device *dev) -+{ -+ struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); -+ -+ regcache_cache_only(cs42l51->regmap, true); -+ regcache_mark_dirty(cs42l51->regmap); -+ -+ return 0; -+} -+ -+static int cs42l51_resume(struct device *dev) -+{ -+ struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); -+ -+ regcache_cache_only(cs42l51->regmap, false); -+ -+ return regcache_sync(cs42l51->regmap); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static const struct dev_pm_ops cs42l51_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume) -+}; -+ - static struct i2c_driver cs42l51_i2c_driver = { - .driver = { - .name = "cs42l51", - .of_match_table = cs42l51_of_match, -+ .pm = &cs42l51_pm_ops, - }, - .probe = cs42l51_i2c_probe, -+ .remove = cs42l51_i2c_remove, - .id_table = cs42l51_i2c_id, - }; - -diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c -index 5080d7a3..83313ec 100644 ---- a/sound/soc/codecs/cs42l51.c -+++ b/sound/soc/codecs/cs42l51.c -@@ -21,6 +21,7 @@ - * - master mode *NOT* supported - */ - -+#include - #include - #include - #include -@@ -29,20 +30,14 @@ - #include - #include - #include --#include -- -+#include - #include "cs42l51.h" - --enum master_slave_mode { -- MODE_SLAVE, -- MODE_SLAVE_AUTO, -- MODE_MASTER, --}; -- --struct cs42l51_private { -- unsigned int mclk; -- unsigned int audio_mode; /* The mode (I2S or left-justified) */ -- enum master_slave_mode func; -+static const char *cs42l51_supply_names[CS42L51_NUM_SUPPLIES] = { -+ "VL", -+ "VD", -+ "VA", -+ "VAHP", - }; - - #define CS42L51_FORMATS ( \ -@@ -109,6 +104,7 @@ static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); - static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0); - - static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0); -+static const DECLARE_TLV_DB_SCALE(adc_boost_tlv, 2000, 2000, 0); - static const char *chan_mix[] = { - "L R", - "L+R", -@@ -137,6 +133,8 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { - SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0), - SOC_DOUBLE_TLV("Mic Boost Volume", - CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv), -+ SOC_DOUBLE_TLV("ADC Boost Volume", -+ CS42L51_MIC_CTL, 5, 6, 1, 0, adc_boost_tlv), - SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv), - SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv), - SOC_ENUM_EXT("PCM channel mixer", -@@ -165,6 +163,7 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, - case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, CS42L51_POWER_CTL1, - CS42L51_POWER_CTL1_PDN, 0); -+ msleep(20); - break; - } - -@@ -193,7 +192,8 @@ static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = - SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); - - static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { -- SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1), -+ SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1, NULL, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0, - cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), - SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0, -@@ -237,6 +237,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { - &cs42l51_adcr_mux_controls), - }; - -+static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = { -+ SND_SOC_DAPM_CLOCK_SUPPLY("MCLK") -+}; -+ - static const struct snd_soc_dapm_route cs42l51_routes[] = { - {"HPL", NULL, "Left DAC"}, - {"HPR", NULL, "Right DAC"}, -@@ -323,6 +327,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = { - { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, - }; - -+/* -+ * Master mode mclk/fs ratios. -+ * Recommended configurations are SSM for 4-50khz and DSM for 50-100kHz ranges -+ * The table below provides support of following ratios: -+ * 128: SSM (%128) with div2 disabled -+ * 256: SSM (%128) with div2 enabled -+ * In both cases, if sampling rate is above 50kHz, SSM is overridden -+ * with DSM (%128) configuration -+ */ -+static struct cs42l51_ratios master_ratios[] = { -+ { 128, CS42L51_SSM_MODE, 0 }, { 256, CS42L51_SSM_MODE, 1 }, -+}; -+ - static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) - { -@@ -345,11 +362,13 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream, - unsigned int ratio; - struct cs42l51_ratios *ratios = NULL; - int nr_ratios = 0; -- int intf_ctl, power_ctl, fmt; -+ int intf_ctl, power_ctl, fmt, mode; - - switch (cs42l51->func) { - case MODE_MASTER: -- return -EINVAL; -+ ratios = master_ratios; -+ nr_ratios = ARRAY_SIZE(master_ratios); -+ break; - case MODE_SLAVE: - ratios = slave_ratios; - nr_ratios = ARRAY_SIZE(slave_ratios); -@@ -385,7 +404,16 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream, - switch (cs42l51->func) { - case MODE_MASTER: - intf_ctl |= CS42L51_INTF_CTL_MASTER; -- power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); -+ mode = ratios[i].speed_mode; -+ /* Force DSM mode if sampling rate is above 50kHz */ -+ if (rate > 50000) -+ mode = CS42L51_DSM_MODE; -+ power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(mode); -+ /* -+ * Auto detect mode is not applicable for master mode and has to -+ * be disabled. Otherwise SPEED[1:0] bits will be ignored. -+ */ -+ power_ctl &= ~CS42L51_MIC_POWER_CTL_AUTO; - break; - case MODE_SLAVE: - power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); -@@ -458,6 +486,13 @@ static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute) - return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg); - } - -+static int cs42l51_of_xlate_dai_id(struct snd_soc_component *component, -+ struct device_node *endpoint) -+{ -+ /* return dai id 0, whatever the endpoint index */ -+ return 0; -+} -+ - static const struct snd_soc_dai_ops cs42l51_dai_ops = { - .hw_params = cs42l51_hw_params, - .set_sysclk = cs42l51_set_dai_sysclk, -@@ -487,6 +522,14 @@ static struct snd_soc_dai_driver cs42l51_dai = { - static int cs42l51_component_probe(struct snd_soc_component *component) - { - int ret, reg; -+ struct snd_soc_dapm_context *dapm; -+ struct cs42l51_private *cs42l51; -+ -+ cs42l51 = snd_soc_component_get_drvdata(component); -+ dapm = snd_soc_component_get_dapm(component); -+ -+ if (cs42l51->mclk_handle) -+ snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); - - /* - * DAC configuration -@@ -512,13 +555,113 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = { - .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets), - .dapm_routes = cs42l51_routes, - .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), -+ .of_xlate_dai_id = cs42l51_of_xlate_dai_id, - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, - }; - -+static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case CS42L51_POWER_CTL1: -+ case CS42L51_MIC_POWER_CTL: -+ case CS42L51_INTF_CTL: -+ case CS42L51_MIC_CTL: -+ case CS42L51_ADC_CTL: -+ case CS42L51_ADC_INPUT: -+ case CS42L51_DAC_OUT_CTL: -+ case CS42L51_DAC_CTL: -+ case CS42L51_ALC_PGA_CTL: -+ case CS42L51_ALC_PGB_CTL: -+ case CS42L51_ADCA_ATT: -+ case CS42L51_ADCB_ATT: -+ case CS42L51_ADCA_VOL: -+ case CS42L51_ADCB_VOL: -+ case CS42L51_PCMA_VOL: -+ case CS42L51_PCMB_VOL: -+ case CS42L51_BEEP_FREQ: -+ case CS42L51_BEEP_VOL: -+ case CS42L51_BEEP_CONF: -+ case CS42L51_TONE_CTL: -+ case CS42L51_AOUTA_VOL: -+ case CS42L51_AOUTB_VOL: -+ case CS42L51_PCM_MIXER: -+ case CS42L51_LIMIT_THRES_DIS: -+ case CS42L51_LIMIT_REL: -+ case CS42L51_LIMIT_ATT: -+ case CS42L51_ALC_EN: -+ case CS42L51_ALC_REL: -+ case CS42L51_ALC_THRES: -+ case CS42L51_NOISE_CONF: -+ case CS42L51_CHARGE_FREQ: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool cs42l51_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case CS42L51_STATUS: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool cs42l51_readable_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case CS42L51_CHIP_REV_ID: -+ case CS42L51_POWER_CTL1: -+ case CS42L51_MIC_POWER_CTL: -+ case CS42L51_INTF_CTL: -+ case CS42L51_MIC_CTL: -+ case CS42L51_ADC_CTL: -+ case CS42L51_ADC_INPUT: -+ case CS42L51_DAC_OUT_CTL: -+ case CS42L51_DAC_CTL: -+ case CS42L51_ALC_PGA_CTL: -+ case CS42L51_ALC_PGB_CTL: -+ case CS42L51_ADCA_ATT: -+ case CS42L51_ADCB_ATT: -+ case CS42L51_ADCA_VOL: -+ case CS42L51_ADCB_VOL: -+ case CS42L51_PCMA_VOL: -+ case CS42L51_PCMB_VOL: -+ case CS42L51_BEEP_FREQ: -+ case CS42L51_BEEP_VOL: -+ case CS42L51_BEEP_CONF: -+ case CS42L51_TONE_CTL: -+ case CS42L51_AOUTA_VOL: -+ case CS42L51_AOUTB_VOL: -+ case CS42L51_PCM_MIXER: -+ case CS42L51_LIMIT_THRES_DIS: -+ case CS42L51_LIMIT_REL: -+ case CS42L51_LIMIT_ATT: -+ case CS42L51_ALC_EN: -+ case CS42L51_ALC_REL: -+ case CS42L51_ALC_THRES: -+ case CS42L51_NOISE_CONF: -+ case CS42L51_STATUS: -+ case CS42L51_CHARGE_FREQ: -+ return true; -+ default: -+ return false; -+ } -+} -+ - const struct regmap_config cs42l51_regmap = { -+ .reg_bits = 8, -+ .reg_stride = 1, -+ .val_bits = 8, -+ .use_single_rw = true, -+ .readable_reg = cs42l51_readable_reg, -+ .volatile_reg = cs42l51_volatile_reg, -+ .writeable_reg = cs42l51_writeable_reg, - .max_register = CS42L51_CHARGE_FREQ, - .cache_type = REGCACHE_RBTREE, - }; -@@ -528,7 +671,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) - { - struct cs42l51_private *cs42l51; - unsigned int val; -- int ret; -+ int ret, i; - - if (IS_ERR(regmap)) - return PTR_ERR(regmap); -@@ -539,6 +682,42 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) - return -ENOMEM; - - dev_set_drvdata(dev, cs42l51); -+ cs42l51->regmap = regmap; -+ -+ cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); -+ if (IS_ERR(cs42l51->mclk_handle)) { -+ if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT) -+ return PTR_ERR(cs42l51->mclk_handle); -+ cs42l51->mclk_handle = NULL; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++) -+ cs42l51->supplies[i].supply = cs42l51_supply_names[i]; -+ -+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs42l51->supplies), -+ cs42l51->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to request supplies: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42l51->supplies), -+ cs42l51->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to enable supplies: %d\n", ret); -+ return ret; -+ } -+ -+ cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset", -+ GPIOD_OUT_LOW); -+ if (IS_ERR(cs42l51->reset_gpio)) -+ return PTR_ERR(cs42l51->reset_gpio); -+ -+ if (cs42l51->reset_gpio) { -+ dev_dbg(dev, "Release reset gpio\n"); -+ gpiod_set_value_cansleep(cs42l51->reset_gpio, 0); -+ mdelay(2); -+ } - - /* Verify that we have a CS42L51 */ - ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); -@@ -558,11 +737,29 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) - - ret = devm_snd_soc_register_component(dev, - &soc_component_device_cs42l51, &cs42l51_dai, 1); -+ if (ret < 0) -+ goto error; -+ -+ return 0; -+ - error: -+ regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), -+ cs42l51->supplies); - return ret; - } - EXPORT_SYMBOL_GPL(cs42l51_probe); - -+int cs42l51_remove(struct device *dev) -+{ -+ struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); -+ -+ gpiod_set_value_cansleep(cs42l51->reset_gpio, 1); -+ -+ return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), -+ cs42l51->supplies); -+} -+EXPORT_SYMBOL_GPL(cs42l51_remove); -+ - const struct of_device_id cs42l51_of_match[] = { - { .compatible = "cirrus,cs42l51", }, - { } -diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h -index 0ca8054..a086f7e 100644 ---- a/sound/soc/codecs/cs42l51.h -+++ b/sound/soc/codecs/cs42l51.h -@@ -18,10 +18,14 @@ - #ifndef _CS42L51_H - #define _CS42L51_H - -+#include -+#include -+ - struct device; - - extern const struct regmap_config cs42l51_regmap; - int cs42l51_probe(struct device *dev, struct regmap *regmap); -+int cs42l51_remove(struct device *dev); - extern const struct of_device_id cs42l51_of_match[]; - - #define CS42L51_CHIP_ID 0x1B -@@ -164,5 +168,22 @@ extern const struct of_device_id cs42l51_of_match[]; - */ - #define CS42L51_LASTREG 0x20 - #define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1) -+#define CS42L51_NUM_SUPPLIES 4 -+ -+enum master_slave_mode { -+ MODE_SLAVE, -+ MODE_SLAVE_AUTO, -+ MODE_MASTER, -+}; -+ -+struct cs42l51_private { -+ unsigned int mclk; -+ struct clk *mclk_handle; -+ unsigned int audio_mode; /* The mode (I2S or left-justified) */ -+ enum master_slave_mode func; -+ struct regulator_bulk_data supplies[CS42L51_NUM_SUPPLIES]; -+ struct gpio_desc *reset_gpio; -+ struct regmap *regmap; -+}; - - #endif -diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index 01acb8d..c902ac7 100644 ---- a/sound/soc/codecs/wm8994.c -+++ b/sound/soc/codecs/wm8994.c -@@ -11,6 +11,7 @@ - * published by the Free Software Foundation. - */ - -+#include - #include - #include - #include -@@ -844,6 +845,42 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, - return 0; - } - -+static int mclk_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); -+ struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(comp); -+ struct wm8994 *control = wm8994->wm8994; -+ struct wm8994_pdata *pdata = &control->pdata; -+ struct clk *mclk = pdata->mclk1; -+ int ret, mclk_id = 0; -+ -+ if (!strncmp(w->name, "MCLK2", 5)) { -+ mclk_id = 1; -+ mclk = pdata->mclk2; -+ } -+ -+ switch (event) { -+ case SND_SOC_DAPM_PRE_PMU: -+ dev_dbg(comp->dev, "Enable master clock %s\n", -+ mclk_id ? "MCLK2" : "MCLK1"); -+ -+ ret = clk_prepare_enable(mclk); -+ if (ret < 0) { -+ dev_err(comp->dev, "Failed to enable clock: %d\n", ret); -+ return ret; -+ } -+ break; -+ case SND_SOC_DAPM_POST_PMD: -+ dev_dbg(comp->dev, "Disable master clock %s\n", -+ mclk_id ? "MCLK2" : "MCLK1"); -+ clk_disable_unprepare(mclk); -+ break; -+ } -+ -+ return 0; -+} -+ - static void vmid_reference(struct snd_soc_component *component) - { - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -@@ -1161,7 +1198,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, - else - adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA; - -- - val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_2); - if ((val & WM8994_AIF2DACL_SRC) && - (val & WM8994_AIF2DACR_SRC)) -@@ -1780,6 +1816,16 @@ static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = { - SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux), - }; - -+static const struct snd_soc_dapm_widget wm8994_mclk1_dapm_widgets[] = { -+SND_SOC_DAPM_SUPPLY("MCLK1", SND_SOC_NOPM, 0, 0, mclk_event, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -+}; -+ -+static const struct snd_soc_dapm_widget wm8994_mclk2_dapm_widgets[] = { -+SND_SOC_DAPM_SUPPLY("MCLK2", SND_SOC_NOPM, 0, 0, mclk_event, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -+}; -+ - static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0), - SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux), -@@ -2004,10 +2050,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { - }; - - static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { -- { "AIF1DACDAT", NULL, "AIF2DACDAT" }, -- { "AIF2DACDAT", NULL, "AIF1DACDAT" }, -- { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, -- { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, -+// { "AIF1DACDAT", NULL, "AIF2DACDAT" }, -+// { "AIF2DACDAT", NULL, "AIF1DACDAT" }, -+// { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, -+// { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, - { "MICBIAS1", NULL, "CLK_SYS" }, - { "MICBIAS1", NULL, "MICBIAS Supply" }, - { "MICBIAS2", NULL, "CLK_SYS" }, -@@ -2381,11 +2427,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, - { - struct snd_soc_component *component = dai->component; - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -+ struct wm8994 *control = wm8994->wm8994; -+ struct wm8994_pdata *pdata = &control->pdata; - int i; - -+ /* -+ * Simple card provides unconditionnaly clock_id = 0. -+ * Workaround to select master clock for aif1/2 -+ */ - switch (dai->id) { - case 1: -+ if (pdata->mclk1) -+ clk_id = WM8994_SYSCLK_MCLK1; -+ else if (pdata->mclk2) -+ clk_id = WM8994_SYSCLK_MCLK2; -+ break; - case 2: -+ if (pdata->mclk2) -+ clk_id = WM8994_SYSCLK_MCLK2; -+ else if (pdata->mclk1) -+ clk_id = WM8994_SYSCLK_MCLK1; - break; - - default: -@@ -3995,6 +4056,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) - { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct wm8994 *control = dev_get_drvdata(component->dev->parent); -+ struct wm8994_pdata *pdata = &control->pdata; - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - unsigned int reg; - int ret, i; -@@ -4278,6 +4340,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) - ARRAY_SIZE(wm8994_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, - ARRAY_SIZE(wm8994_specific_dapm_widgets)); -+ if (pdata->mclk1) -+ snd_soc_dapm_new_controls(dapm, wm8994_mclk1_dapm_widgets, -+ ARRAY_SIZE(wm8994_mclk1_dapm_widgets)); -+ -+ if (pdata->mclk2) -+ snd_soc_dapm_new_controls(dapm, wm8994_mclk2_dapm_widgets, -+ ARRAY_SIZE(wm8994_mclk2_dapm_widgets)); -+ - if (control->revision < 4) { - snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, - ARRAY_SIZE(wm8994_lateclk_revd_widgets)); -diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig -index 9b26813..c66ffa7 100644 ---- a/sound/soc/stm/Kconfig -+++ b/sound/soc/stm/Kconfig -@@ -3,6 +3,7 @@ menu "STMicroelectronics STM32 SOC audio support" - config SND_SOC_STM32_SAI - tristate "STM32 SAI interface (Serial Audio Interface) support" - depends on (ARCH_STM32 && OF) || COMPILE_TEST -+ depends on COMMON_CLK - depends on SND_SOC - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO -diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c -index 24948b95..33de130 100644 ---- a/sound/soc/stm/stm32_adfsdm.c -+++ b/sound/soc/stm/stm32_adfsdm.c -@@ -18,6 +18,7 @@ - #include - - #include -+#include - #include - - #define STM32_ADFSDM_DRV_NAME "stm32-adfsdm" -@@ -44,8 +45,8 @@ struct stm32_adfsdm_priv { - - static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | -- SNDRV_PCM_INFO_PAUSE, -- .formats = SNDRV_PCM_FMTBIT_S32_LE, -+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, - - .rate_min = 8000, - .rate_max = 32000, -@@ -141,7 +142,8 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = { - .capture = { - .channels_min = 1, - .channels_max = 1, -- .formats = SNDRV_PCM_FMTBIT_S32_LE, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_32000), - }, -@@ -152,30 +154,58 @@ static const struct snd_soc_component_driver stm32_adfsdm_dai_component = { - .name = "stm32_dfsdm_audio", - }; - -+void stm32_memcpy_32to16(void *dest, const void *src, size_t n) -+{ -+ unsigned int i = 0; -+ u16 *d = (u16 *)dest, *s = (u16 *)src; -+ -+ s++; -+ for (i = n >> 1; i > 0; i--) { -+ *d++ = *s++; -+ s++; -+ } -+} -+ - static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private) - { - struct stm32_adfsdm_priv *priv = private; - struct snd_soc_pcm_runtime *rtd = priv->substream->private_data; - u8 *pcm_buff = priv->pcm_buff; - u8 *src_buff = (u8 *)data; -- unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream); -- unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream); - unsigned int old_pos = priv->pos; -- unsigned int cur_size = size; -+ size_t buff_size = snd_pcm_lib_buffer_bytes(priv->substream); -+ size_t period_size = snd_pcm_lib_period_bytes(priv->substream); -+ size_t cur_size, src_size = size; -+ snd_pcm_format_t format = priv->substream->runtime->format; -+ -+ if (format == SNDRV_PCM_FORMAT_S16_LE) -+ src_size >>= 1; -+ cur_size = src_size; - - dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n", -- __func__, &pcm_buff[priv->pos], priv->pos, size); -+ __func__, &pcm_buff[priv->pos], priv->pos, src_size); - -- if ((priv->pos + size) > buff_size) { -- memcpy(&pcm_buff[priv->pos], src_buff, buff_size - priv->pos); -+ if ((priv->pos + src_size) > buff_size) { -+ if (format == SNDRV_PCM_FORMAT_S16_LE) -+ stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff, -+ buff_size - priv->pos); -+ else -+ memcpy(&pcm_buff[priv->pos], src_buff, -+ buff_size - priv->pos); - cur_size -= buff_size - priv->pos; - priv->pos = 0; - } - -- memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size); -+ if (format == SNDRV_PCM_FORMAT_S16_LE) -+ stm32_memcpy_32to16(&pcm_buff[priv->pos], -+ &src_buff[src_size - cur_size], cur_size); -+ else -+ memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size], -+ cur_size); -+ - priv->pos = (priv->pos + cur_size) % buff_size; - -- if (cur_size != size || (old_pos && (old_pos % period_size < size))) -+ if (cur_size != src_size || (old_pos && (old_pos % period_size < size))) - snd_pcm_period_elapsed(priv->substream); - - return 0; -diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c -index aa2b119..490352c 100644 ---- a/sound/soc/stm/stm32_i2s.c -+++ b/sound/soc/stm/stm32_i2s.c -@@ -16,6 +16,7 @@ - * details. - */ - -+#include - #include - #include - #include -@@ -37,6 +38,10 @@ - #define STM32_I2S_TXDR_REG 0X20 - #define STM32_I2S_RXDR_REG 0x30 - #define STM32_I2S_CGFR_REG 0X50 -+#define STM32_I2S_HWCFGR_REG 0x3F0 -+#define STM32_I2S_VERR_REG 0x3F4 -+#define STM32_I2S_IPIDR_REG 0x3F8 -+#define STM32_I2S_SIDR_REG 0x3FC - - /* Bit definition for SPI2S_CR1 register */ - #define I2S_CR1_SPE BIT(0) -@@ -143,6 +148,23 @@ - #define I2S_CGFR_ODD BIT(I2S_CGFR_ODD_SHIFT) - #define I2S_CGFR_MCKOE BIT(25) - -+/* Registers below apply to I2S version 1.1 and more */ -+ -+/* Bit definition for SPI_HWCFGR register */ -+#define I2S_HWCFGR_I2S_SUPPORT_MASK GENMASK(15, 12) -+ -+/* Bit definition for SPI_VERR register */ -+#define I2S_VERR_MIN_MASK GENMASK(3, 0) -+#define I2S_VERR_MAJ_MASK GENMASK(7, 4) -+ -+/* Bit definition for SPI_IPIDR register */ -+#define I2S_IPIDR_ID_MASK GENMASK(31, 0) -+ -+/* Bit definition for SPI_SIDR register */ -+#define I2S_SIDR_ID_MASK GENMASK(31, 0) -+ -+#define I2S_IPIDR_NUMBER 0x00130022 -+ - enum i2s_master_mode { - I2S_MS_NOT_SET, - I2S_MS_MASTER, -@@ -179,7 +201,6 @@ enum i2s_datlen { - I2S_I2SMOD_DATLEN_32, - }; - --#define STM32_I2S_DAI_NAME_SIZE 20 - #define STM32_I2S_FIFO_SIZE 16 - - #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) -@@ -200,7 +221,7 @@ enum i2s_datlen { - * @base: mmio register base virtual address - * @phys_addr: I2S registers physical base address - * @lock_fd: lock to manage race conditions in full duplex mode -- * @dais_name: DAI name -+ * @irq_lock_t: prevent race condition with IRQ - * @mclk_rate: master clock frequency (Hz) - * @fmt: DAI protocol - * @refcount: keep count of opened streams on I2S -@@ -221,7 +242,7 @@ struct stm32_i2s_data { - void __iomem *base; - dma_addr_t phys_addr; - spinlock_t lock_fd; /* Manage race conditions for full duplex */ -- char dais_name[STM32_I2S_DAI_NAME_SIZE]; -+ spinlock_t irq_lock; /* used to prevent race condition with IRQ */ - unsigned int mclk_rate; - unsigned int fmt; - int refcount; -@@ -232,8 +253,8 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) - { - struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid; - struct platform_device *pdev = i2s->pdev; -- u32 sr, ier; - unsigned long flags; -+ u32 sr, ier; - int err = 0; - - regmap_read(i2s->regmap, STM32_I2S_SR_REG, &sr); -@@ -262,8 +283,10 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) - if (flags & I2S_SR_TIFRE) - dev_dbg(&pdev->dev, "Frame error\n"); - -- if (err) -+ spin_lock(&i2s->irq_lock); -+ if (err && i2s->substream) - snd_pcm_stop_xrun(i2s->substream); -+ spin_unlock(&i2s->irq_lock); - - return IRQ_HANDLED; - } -@@ -276,9 +299,12 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) - case STM32_I2S_CFG2_REG: - case STM32_I2S_IER_REG: - case STM32_I2S_SR_REG: -- case STM32_I2S_TXDR_REG: - case STM32_I2S_RXDR_REG: - case STM32_I2S_CGFR_REG: -+ case STM32_I2S_HWCFGR_REG: -+ case STM32_I2S_VERR_REG: -+ case STM32_I2S_IPIDR_REG: -+ case STM32_I2S_SIDR_REG: - return true; - default: - return false; -@@ -288,7 +314,7 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) - static bool stm32_i2s_volatile_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -- case STM32_I2S_TXDR_REG: -+ case STM32_I2S_SR_REG: - case STM32_I2S_RXDR_REG: - return true; - default: -@@ -491,12 +517,6 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, - unsigned int fthlv; - int ret; - -- if ((params_channels(params) == 1) && -- ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)) { -- dev_err(cpu_dai->dev, "Mono mode supported only by DSP_A\n"); -- return -EINVAL; -- } -- - switch (format) { - case 16: - cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16); -@@ -539,12 +559,22 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) - { - struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); -+ unsigned long flags; -+ int ret; - -+ spin_lock_irqsave(&i2s->irq_lock, flags); - i2s->substream = substream; -+ spin_unlock_irqrestore(&i2s->irq_lock, flags); - -- spin_lock(&i2s->lock_fd); -- i2s->refcount++; -- spin_unlock(&i2s->lock_fd); -+ if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A) -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_CHANNELS, 2); -+ -+ ret = clk_prepare_enable(i2s->i2sclk); -+ if (ret < 0) { -+ dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); -+ return ret; -+ } - - return regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, I2S_IFCR_MASK); -@@ -582,7 +612,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /* Enable i2s */ -- dev_dbg(cpu_dai->dev, "start I2S\n"); -+ dev_dbg(cpu_dai->dev, "start I2S %s\n", -+ playback_flg ? "playback" : "capture"); - - cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; - regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -@@ -595,8 +626,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - return ret; - } - -- ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, -- I2S_CR1_CSTART, I2S_CR1_CSTART); -+ ret = regmap_write_bits(i2s->regmap, STM32_I2S_CR1_REG, -+ I2S_CR1_CSTART, I2S_CR1_CSTART); - if (ret < 0) { - dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); - return ret; -@@ -605,18 +636,19 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, I2S_IFCR_MASK); - -+ spin_lock(&i2s->lock_fd); -+ i2s->refcount++; - if (playback_flg) { - ier = I2S_IER_UDRIE; - } else { - ier = I2S_IER_OVRIE; - -- spin_lock(&i2s->lock_fd); -- if (i2s->refcount == 1) -- /* dummy write to trigger capture */ -+ if (STM32_I2S_IS_MASTER(i2s) && (i2s->refcount == 1)) -+ /* dummy write to gate bus clocks */ - regmap_write(i2s->regmap, - STM32_I2S_TXDR_REG, 0); -- spin_unlock(&i2s->lock_fd); - } -+ spin_unlock(&i2s->lock_fd); - - if (STM32_I2S_IS_SLAVE(i2s)) - ier |= I2S_IER_TIFREIE; -@@ -626,6 +658,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ dev_dbg(cpu_dai->dev, "stop I2S %s\n", -+ playback_flg ? "playback" : "capture"); -+ - if (playback_flg) - regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, - I2S_IER_UDRIE, -@@ -641,16 +676,15 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - spin_unlock(&i2s->lock_fd); - break; - } -- spin_unlock(&i2s->lock_fd); -- -- dev_dbg(cpu_dai->dev, "stop I2S\n"); - - ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, - I2S_CR1_SPE, 0); - if (ret < 0) { - dev_err(cpu_dai->dev, "Error %d disabling I2S\n", ret); -+ spin_unlock(&i2s->lock_fd); - return ret; - } -+ spin_unlock(&i2s->lock_fd); - - cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; - regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -@@ -667,11 +701,16 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) - { - struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); -- -- i2s->substream = NULL; -+ unsigned long flags; - - regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, - I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); -+ -+ clk_disable_unprepare(i2s->i2sclk); -+ -+ spin_lock_irqsave(&i2s->irq_lock, flags); -+ i2s->substream = NULL; -+ spin_unlock_irqrestore(&i2s->irq_lock, flags); - } - - static int stm32_i2s_dai_probe(struct snd_soc_dai *cpu_dai) -@@ -697,11 +736,13 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, -- .max_register = STM32_I2S_CGFR_REG, -+ .max_register = STM32_I2S_SIDR_REG, - .readable_reg = stm32_i2s_readable_reg, - .volatile_reg = stm32_i2s_volatile_reg, - .writeable_reg = stm32_i2s_writeable_reg, -+ .num_reg_defaults_raw = STM32_I2S_SIDR_REG / sizeof(u32) + 1, - .fast_io = true, -+ .cache_type = REGCACHE_FLAT, - }; - - static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { -@@ -716,7 +757,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { - static const struct snd_pcm_hardware stm32_i2s_pcm_hw = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, - .buffer_bytes_max = 8 * PAGE_SIZE, -- .period_bytes_max = 2048, -+ .period_bytes_min = 1024, /* 5ms at 48kHz */ -+ .period_bytes_max = PAGE_SIZE, - .periods_min = 2, - .periods_max = 8, - }; -@@ -752,12 +794,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, - if (!dai_ptr) - return -ENOMEM; - -- snprintf(i2s->dais_name, STM32_I2S_DAI_NAME_SIZE, -- "%s", dev_name(&pdev->dev)); -- - dai_ptr->probe = stm32_i2s_dai_probe; - dai_ptr->ops = &stm32_i2s_pcm_dai_ops; -- dai_ptr->name = i2s->dais_name; - dai_ptr->id = 1; - stm32_i2s_dai_init(&dai_ptr->playback, "playback"); - stm32_i2s_dai_init(&dai_ptr->capture, "capture"); -@@ -827,8 +865,9 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, - /* Get irqs */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { -- dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); -- return -ENOENT; -+ if (irq != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); -+ return irq; - } - - ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT, -@@ -852,6 +891,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, - static int stm32_i2s_probe(struct platform_device *pdev) - { - struct stm32_i2s_data *i2s; -+ u32 val; - int ret; - - i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); -@@ -865,76 +905,94 @@ static int stm32_i2s_probe(struct platform_device *pdev) - i2s->pdev = pdev; - i2s->ms_flg = I2S_MS_NOT_SET; - spin_lock_init(&i2s->lock_fd); -+ spin_lock_init(&i2s->irq_lock); - platform_set_drvdata(pdev, i2s); - - ret = stm32_i2s_dais_init(pdev, i2s); - if (ret) - return ret; - -- i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->base, -- i2s->regmap_conf); -+ i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", -+ i2s->base, i2s->regmap_conf); - if (IS_ERR(i2s->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); - return PTR_ERR(i2s->regmap); - } - -- ret = clk_prepare_enable(i2s->pclk); -- if (ret) { -- dev_err(&pdev->dev, "Enable pclk failed: %d\n", ret); -- return ret; -- } -- -- ret = clk_prepare_enable(i2s->i2sclk); -- if (ret) { -- dev_err(&pdev->dev, "Enable i2sclk failed: %d\n", ret); -- goto err_pclk_disable; -- } -- - ret = devm_snd_soc_register_component(&pdev->dev, &stm32_i2s_component, - i2s->dai_drv, 1); - if (ret) -- goto err_clocks_disable; -+ return ret; - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, - &stm32_i2s_pcm_config, 0); - if (ret) -- goto err_clocks_disable; -+ return ret; - - /* Set SPI/I2S in i2s mode */ - ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, - I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); - if (ret) -- goto err_clocks_disable; -+ return ret; - -- return ret; -+ ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, &val); -+ if (ret) -+ return ret; - --err_clocks_disable: -- clk_disable_unprepare(i2s->i2sclk); --err_pclk_disable: -- clk_disable_unprepare(i2s->pclk); -+ if (val == I2S_IPIDR_NUMBER) { -+ ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, &val); -+ if (ret) -+ return ret; -+ -+ if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) { -+ dev_err(&pdev->dev, -+ "Device does not support i2s mode\n"); -+ return ret; -+ } -+ -+ ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, &val); -+ -+ dev_dbg(&pdev->dev, "I2S version: %lu.%lu registered\n", -+ FIELD_GET(I2S_VERR_MAJ_MASK, val), -+ FIELD_GET(I2S_VERR_MIN_MASK, val)); -+ } - - return ret; - } - --static int stm32_i2s_remove(struct platform_device *pdev) -+MODULE_DEVICE_TABLE(of, stm32_i2s_ids); -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_i2s_suspend(struct device *dev) - { -- struct stm32_i2s_data *i2s = platform_get_drvdata(pdev); -+ struct stm32_i2s_data *i2s = dev_get_drvdata(dev); - -- clk_disable_unprepare(i2s->i2sclk); -- clk_disable_unprepare(i2s->pclk); -+ regcache_cache_only(i2s->regmap, true); -+ regcache_mark_dirty(i2s->regmap); - - return 0; - } - --MODULE_DEVICE_TABLE(of, stm32_i2s_ids); -+static int stm32_i2s_resume(struct device *dev) -+{ -+ struct stm32_i2s_data *i2s = dev_get_drvdata(dev); -+ -+ regcache_cache_only(i2s->regmap, false); -+ return regcache_sync(i2s->regmap); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static const struct dev_pm_ops stm32_i2s_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume) -+}; - - static struct platform_driver stm32_i2s_driver = { - .driver = { - .name = "st,stm32-i2s", - .of_match_table = stm32_i2s_ids, -+ .pm = &stm32_i2s_pm_ops, - }, - .probe = stm32_i2s_probe, -- .remove = stm32_i2s_remove, - }; - - module_platform_driver(stm32_i2s_driver); -diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c -index 540c4a0..d6763a1 100644 ---- a/sound/soc/stm/stm32_sai.c -+++ b/sound/soc/stm/stm32_sai.c -@@ -21,6 +21,8 @@ - #include - #include - #include -+#include -+#include - #include - - #include -@@ -29,13 +31,20 @@ - #include "stm32_sai.h" - - static const struct stm32_sai_conf stm32_sai_conf_f4 = { -- .version = SAI_STM32F4, -- .has_spdif = false, -+ .version = STM_SAI_STM32F4, -+ .fifo_size = 8, -+ .has_spdif_pdm = false, - }; - -+/* -+ * Default settings for stm32 H7 socs and next. -+ * These default settings will be overridden if the soc provides -+ * support of hardware configuration registers. -+ */ - static const struct stm32_sai_conf stm32_sai_conf_h7 = { -- .version = SAI_STM32H7, -- .has_spdif = true, -+ .version = STM_SAI_STM32H7, -+ .fifo_size = 8, -+ .has_spdif_pdm = true, - }; - - static const struct of_device_id stm32_sai_ids[] = { -@@ -44,20 +53,39 @@ static const struct of_device_id stm32_sai_ids[] = { - {} - }; - --static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) -+static int stm32_sai_pclk_disable(struct device *dev) - { -+ struct stm32_sai_data *sai = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(sai->pclk); -+ -+ return 0; -+} -+ -+static int stm32_sai_pclk_enable(struct device *dev) -+{ -+ struct stm32_sai_data *sai = dev_get_drvdata(dev); - int ret; - -- /* Enable peripheral clock to allow GCR register access */ - ret = clk_prepare_enable(sai->pclk); -- if (ret) { -+ if (ret) - dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret); -+ -+ return ret; -+} -+ -+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) -+{ -+ int ret; -+ -+ /* Enable peripheral clock to allow GCR register access */ -+ ret = stm32_sai_pclk_enable(&sai->pdev->dev); -+ if (ret) - return ret; -- } - - writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base); - -- clk_disable_unprepare(sai->pclk); -+ stm32_sai_pclk_disable(&sai->pdev->dev); - - return 0; - } -@@ -68,11 +96,9 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) - int ret; - - /* Enable peripheral clock to allow GCR register access */ -- ret = clk_prepare_enable(sai->pclk); -- if (ret) { -- dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret); -+ ret = stm32_sai_pclk_enable(&sai->pdev->dev); -+ if (ret) - return ret; -- } - - dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n", - sai->pdev->dev.of_node->name, -@@ -83,13 +109,13 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) - dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n", - sai->pdev->dev.of_node->name, - prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); -- clk_disable_unprepare(sai->pclk); -+ stm32_sai_pclk_disable(&sai->pdev->dev); - return -EINVAL; - } - - writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base); - -- clk_disable_unprepare(sai->pclk); -+ stm32_sai_pclk_disable(&sai->pdev->dev); - - return 0; - } -@@ -113,19 +139,20 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, - dev_err(&sai_client->pdev->dev, - "SAI sync provider data not found\n"); - ret = -EINVAL; -- goto out_put_dev; -+ goto error; - } - - /* Configure sync client */ - ret = stm32_sai_sync_conf_client(sai_client, synci); - if (ret < 0) -- goto out_put_dev; -+ goto error; - - /* Configure sync provider */ - ret = stm32_sai_sync_conf_provider(sai_provider, synco); - --out_put_dev: -+error: - put_device(&pdev->dev); -+ of_node_put(np_provider); - return ret; - } - -@@ -135,6 +162,8 @@ static int stm32_sai_probe(struct platform_device *pdev) - struct reset_control *rst; - struct resource *res; - const struct of_device_id *of_id; -+ u32 val; -+ int ret; - - sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); - if (!sai) -@@ -147,7 +176,8 @@ static int stm32_sai_probe(struct platform_device *pdev) - - of_id = of_match_device(stm32_sai_ids, &pdev->dev); - if (of_id) -- sai->conf = (struct stm32_sai_conf *)of_id->data; -+ memcpy(&sai->conf, (const struct stm32_sai_conf *)of_id->data, -+ sizeof(struct stm32_sai_conf)); - else - return -EINVAL; - -@@ -186,6 +216,30 @@ static int stm32_sai_probe(struct platform_device *pdev) - reset_control_deassert(rst); - } - -+ /* Enable peripheral clock to allow register access */ -+ ret = clk_prepare_enable(sai->pclk); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); -+ return ret; -+ } -+ -+ val = FIELD_GET(SAI_IDR_ID_MASK, -+ readl_relaxed(sai->base + STM_SAI_IDR)); -+ if (val == SAI_IPIDR_NUMBER) { -+ val = readl_relaxed(sai->base + STM_SAI_HWCFGR); -+ sai->conf.fifo_size = FIELD_GET(SAI_HWCFGR_FIFO_SIZE, val); -+ sai->conf.has_spdif_pdm = !!FIELD_GET(SAI_HWCFGR_SPDIF_PDM, -+ val); -+ -+ val = readl_relaxed(sai->base + STM_SAI_VERR); -+ sai->conf.version = val; -+ -+ dev_dbg(&pdev->dev, "SAI version: %lu.%lu registered\n", -+ FIELD_GET(SAI_VERR_MAJ_MASK, val), -+ FIELD_GET(SAI_VERR_MIN_MASK, val)); -+ } -+ clk_disable_unprepare(sai->pclk); -+ - sai->pdev = pdev; - sai->set_sync = &stm32_sai_set_sync; - platform_set_drvdata(pdev, sai); -@@ -193,12 +247,54 @@ static int stm32_sai_probe(struct platform_device *pdev) - return devm_of_platform_populate(&pdev->dev); - } - -+#ifdef CONFIG_PM_SLEEP -+/* -+ * When pins are shared by two sai sub instances, pins have to be defined -+ * in sai parent node. In this case, pins state is not managed by alsa fw. -+ * These pins are managed in suspend/resume callbacks. -+ */ -+static int stm32_sai_suspend(struct device *dev) -+{ -+ struct stm32_sai_data *sai = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = stm32_sai_pclk_enable(dev); -+ if (ret) -+ return ret; -+ -+ sai->gcr = readl_relaxed(sai->base); -+ stm32_sai_pclk_disable(dev); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static int stm32_sai_resume(struct device *dev) -+{ -+ struct stm32_sai_data *sai = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = stm32_sai_pclk_enable(dev); -+ if (ret) -+ return ret; -+ -+ writel_relaxed(sai->gcr, sai->base); -+ stm32_sai_pclk_disable(dev); -+ -+ return pinctrl_pm_select_default_state(dev); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static const struct dev_pm_ops stm32_sai_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume) -+}; -+ - MODULE_DEVICE_TABLE(of, stm32_sai_ids); - - static struct platform_driver stm32_sai_driver = { - .driver = { - .name = "st,stm32-sai", - .of_match_table = stm32_sai_ids, -+ .pm = &stm32_sai_pm_ops, - }, - .probe = stm32_sai_probe, - }; -diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h -index f254221..158c73f 100644 ---- a/sound/soc/stm/stm32_sai.h -+++ b/sound/soc/stm/stm32_sai.h -@@ -37,6 +37,12 @@ - #define STM_SAI_PDMCR_REGX 0x40 - #define STM_SAI_PDMLY_REGX 0x44 - -+/* Hardware configuration registers */ -+#define STM_SAI_HWCFGR 0x3F0 -+#define STM_SAI_VERR 0x3F4 -+#define STM_SAI_IDR 0x3F8 -+#define STM_SAI_SIDR 0x3FC -+ - /******************** Bit definition for SAI_GCR register *******************/ - #define SAI_GCR_SYNCIN_SHIFT 0 - #define SAI_GCR_SYNCIN_WDTH 2 -@@ -82,7 +88,7 @@ - #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) - - #define SAI_XCR1_MCKDIV_SHIFT 20 --#define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == SAI_STM32F4) ? 4 : 6) -+#define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == STM_SAI_STM32F4) ? 4 : 6) - #define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\ - SAI_XCR1_MCKDIV_SHIFT) - #define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT) -@@ -91,6 +97,9 @@ - #define SAI_XCR1_OSR_SHIFT 26 - #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) - -+#define SAI_XCR1_MCKEN_SHIFT 27 -+#define SAI_XCR1_MCKEN BIT(SAI_XCR1_MCKEN_SHIFT) -+ - /******************* Bit definition for SAI_XCR2 register *******************/ - #define SAI_XCR2_FTH_SHIFT 0 - #define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT) -@@ -231,8 +240,33 @@ - #define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT) - #define SAI_PDMDLY_4R_WIDTH 3 - --#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4) --#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7) -+/* Registers below apply to SAI version 2.1 and more */ -+ -+/* Bit definition for SAI_HWCFGR register */ -+#define SAI_HWCFGR_FIFO_SIZE GENMASK(7, 0) -+#define SAI_HWCFGR_SPDIF_PDM GENMASK(11, 8) -+#define SAI_HWCFGR_REGOUT GENMASK(19, 12) -+ -+/* Bit definition for SAI_VERR register */ -+#define SAI_VERR_MIN_MASK GENMASK(3, 0) -+#define SAI_VERR_MAJ_MASK GENMASK(7, 4) -+ -+/* Bit definition for SAI_IDR register */ -+#define SAI_IDR_ID_MASK GENMASK(31, 0) -+ -+/* Bit definition for SAI_SIDR register */ -+#define SAI_SIDR_ID_MASK GENMASK(31, 0) -+ -+#define SAI_IPIDR_NUMBER 0x00130031 -+ -+/* SAI version numbers are 1.x for F4. Major version number set to 1 for F4 */ -+#define STM_SAI_STM32F4 BIT(4) -+/* Dummy version number for H7 socs and next */ -+#define STM_SAI_STM32H7 0x0 -+ -+#define STM_SAI_IS_F4(ip) ((ip)->conf.version == STM_SAI_STM32F4) -+#define STM_SAI_HAS_SPDIF_PDM(ip)\ -+ ((ip)->pdata->conf.has_spdif_pdm) - - enum stm32_sai_syncout { - STM_SAI_SYNC_OUT_NONE, -@@ -240,19 +274,16 @@ enum stm32_sai_syncout { - STM_SAI_SYNC_OUT_B, - }; - --enum stm32_sai_version { -- SAI_STM32F4, -- SAI_STM32H7 --}; -- - /** - * struct stm32_sai_conf - SAI configuration - * @version: SAI version -- * @has_spdif: SAI S/PDIF support flag -+ * @fifo_size: SAI fifo size as words number -+ * @has_spdif_pdm: SAI S/PDIF and PDM features support flag - */ - struct stm32_sai_conf { -- int version; -- bool has_spdif; -+ u32 version; -+ u32 fifo_size; -+ bool has_spdif_pdm; - }; - - /** -@@ -262,9 +293,10 @@ struct stm32_sai_conf { - * @pclk: SAI bus clock - * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz - * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz -- * @version: SOC version -+ * @conf: SAI hardware capabitilites - * @irq: SAI interrupt line - * @set_sync: pointer to synchro mode configuration callback -+ * @gcr: SAI Global Configuration Register - */ - struct stm32_sai_data { - struct platform_device *pdev; -@@ -272,8 +304,9 @@ struct stm32_sai_data { - struct clk *pclk; - struct clk *clk_x8k; - struct clk *clk_x11k; -- struct stm32_sai_conf *conf; -+ struct stm32_sai_conf conf; - int irq; - int (*set_sync)(struct stm32_sai_data *sai, - struct device_node *np_provider, int synco, int synci); -+ u32 gcr; - }; -diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 6c2e69e..8225665 100644 ---- a/sound/soc/stm/stm32_sai_sub.c -+++ b/sound/soc/stm/stm32_sai_sub.c -@@ -17,6 +17,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -44,7 +45,6 @@ - #define SAI_DATASIZE_24 0x6 - #define SAI_DATASIZE_32 0x7 - --#define STM_SAI_FIFO_SIZE 8 - #define STM_SAI_DAI_NAME_SIZE 15 - - #define STM_SAI_IS_PLAYBACK(ip) ((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK) -@@ -62,12 +62,15 @@ - #define SAI_SYNC_EXTERNAL 0x2 - - #define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif) --#define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf->has_spdif) -+#define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf.has_spdif_pdm) -+#define STM_SAI_HAS_PDM(x) ((x)->pdata->conf.has_spdif_pdm) - #define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) - - #define SAI_IEC60958_BLOCK_FRAMES 192 - #define SAI_IEC60958_STATUS_BYTES 24 - -+#define SAI_MCLK_NAME_LEN 32 -+ - /** - * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) - * @pdev: device data pointer -@@ -80,6 +83,7 @@ - * @pdata: SAI block parent data pointer - * @np_sync_provider: synchronization provider node - * @sai_ck: kernel clock feeding the SAI clock generator -+ * @sai_mclk: master clock from SAI mclk provider - * @phys_addr: SAI registers physical base address - * @mclk_rate: SAI block master clock frequency (Hz). set at init - * @id: SAI sub block id corresponding to sub-block A or B -@@ -98,6 +102,7 @@ - * @spdif_frm_cnt: S/PDIF playback frame counter - * @iec958: iec958 data - * @ctrl_lock: control lock -+ * @spinlock_t: prevent race condition with IRQ - */ - struct stm32_sai_sub_data { - struct platform_device *pdev; -@@ -110,6 +115,7 @@ struct stm32_sai_sub_data { - struct stm32_sai_data *pdata; - struct device_node *np_sync_provider; - struct clk *sai_ck; -+ struct clk *sai_mclk; - dma_addr_t phys_addr; - unsigned int mclk_rate; - unsigned int id; -@@ -128,6 +134,7 @@ struct stm32_sai_sub_data { - unsigned int spdif_frm_cnt; - struct snd_aes_iec958 iec958; - struct mutex ctrl_lock; /* protect resources accessed by controls */ -+ spinlock_t irq_lock; /* used to prevent race condition with IRQ */ - }; - - enum stm32_sai_fifo_th { -@@ -151,6 +158,10 @@ static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg) - case STM_SAI_DR_REGX: - case STM_SAI_PDMCR_REGX: - case STM_SAI_PDMLY_REGX: -+ case STM_SAI_HWCFGR: -+ case STM_SAI_VERR: -+ case STM_SAI_IDR: -+ case STM_SAI_SIDR: - return true; - default: - return false; -@@ -161,6 +172,7 @@ static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg) - { - switch (reg) { - case STM_SAI_DR_REGX: -+ case STM_SAI_SR_REGX: - return true; - default: - return false; -@@ -175,7 +187,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) - case STM_SAI_FRCR_REGX: - case STM_SAI_SLOTR_REGX: - case STM_SAI_IMR_REGX: -- case STM_SAI_SR_REGX: - case STM_SAI_CLRFR_REGX: - case STM_SAI_DR_REGX: - case STM_SAI_PDMCR_REGX: -@@ -186,6 +197,56 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) - } - } - -+static int stm32_sai_sub_reg_up(struct stm32_sai_sub_data *sai, -+ unsigned int reg, unsigned int mask, -+ unsigned int val) -+{ -+ int ret; -+ -+ ret = clk_enable(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ ret = regmap_update_bits(sai->regmap, reg, mask, val); -+ -+ clk_disable(sai->pdata->pclk); -+ -+ return ret; -+} -+ -+static int stm32_sai_sub_reg_wr(struct stm32_sai_sub_data *sai, -+ unsigned int reg, unsigned int mask, -+ unsigned int val) -+{ -+ int ret; -+ -+ ret = clk_enable(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ ret = regmap_write_bits(sai->regmap, reg, mask, val); -+ -+ clk_disable(sai->pdata->pclk); -+ -+ return ret; -+} -+ -+static int stm32_sai_sub_reg_rd(struct stm32_sai_sub_data *sai, -+ unsigned int reg, unsigned int *val) -+{ -+ int ret; -+ -+ ret = clk_enable(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ ret = regmap_read(sai->regmap, reg, val); -+ -+ clk_disable(sai->pdata->pclk); -+ -+ return ret; -+} -+ - static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { - .reg_bits = 32, - .reg_stride = 4, -@@ -195,6 +256,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { - .volatile_reg = stm32_sai_sub_volatile_reg, - .writeable_reg = stm32_sai_sub_writeable_reg, - .fast_io = true, -+ .cache_type = REGCACHE_FLAT, - }; - - static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { -@@ -206,6 +268,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { - .volatile_reg = stm32_sai_sub_volatile_reg, - .writeable_reg = stm32_sai_sub_writeable_reg, - .fast_io = true, -+ .cache_type = REGCACHE_FLAT, - }; - - static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, -@@ -251,6 +314,194 @@ static const struct snd_kcontrol_new iec958_ctls = { - .put = snd_pcm_iec958_put, - }; - -+struct stm32_sai_mclk_data { -+ struct clk_hw hw; -+ unsigned long freq; -+ struct stm32_sai_sub_data *sai_data; -+}; -+ -+#define to_mclk_data(_hw) container_of(_hw, struct stm32_sai_mclk_data, hw) -+#define STM32_SAI_MAX_CLKS 1 -+ -+static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai, -+ unsigned long input_rate, -+ unsigned long output_rate) -+{ -+ int version = sai->pdata->conf.version; -+ int div; -+ -+ div = DIV_ROUND_CLOSEST(input_rate, output_rate); -+ if (div > SAI_XCR1_MCKDIV_MAX(version)) { -+ dev_err(&sai->pdev->dev, "Divider %d out of range\n", div); -+ return -EINVAL; -+ } -+ dev_dbg(&sai->pdev->dev, "SAI divider %d\n", div); -+ -+ if (input_rate % div) -+ dev_dbg(&sai->pdev->dev, -+ "Rate not accurate. requested (%ld), actual (%ld)\n", -+ output_rate, input_rate / div); -+ -+ return div; -+} -+ -+static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, -+ unsigned int div) -+{ -+ int version = sai->pdata->conf.version; -+ int ret, cr1, mask; -+ -+ if (div > SAI_XCR1_MCKDIV_MAX(version)) { -+ dev_err(&sai->pdev->dev, "Divider %d out of range\n", div); -+ return -EINVAL; -+ } -+ -+ mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); -+ cr1 = SAI_XCR1_MCKDIV_SET(div); -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, mask, cr1); -+ if (ret < 0) -+ dev_err(&sai->pdev->dev, "Failed to update CR1 register\n"); -+ -+ return ret; -+} -+ -+static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, -+ unsigned int rate) -+{ -+ struct platform_device *pdev = sai->pdev; -+ struct clk *parent_clk = sai->pdata->clk_x8k; -+ int ret; -+ -+ if (!(rate % 11025)) -+ parent_clk = sai->pdata->clk_x11k; -+ -+ ret = clk_set_parent(sai->sai_ck, parent_clk); -+ if (ret) -+ dev_err(&pdev->dev, " Error %d setting sai_ck parent clock. %s", -+ ret, ret == -EBUSY ? -+ "Active stream rates conflict\n" : "\n"); -+ -+ return ret; -+} -+ -+static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); -+ struct stm32_sai_sub_data *sai = mclk->sai_data; -+ int div; -+ -+ div = stm32_sai_get_clk_div(sai, *prate, rate); -+ if (div < 0) -+ return div; -+ -+ mclk->freq = *prate / div; -+ -+ return mclk->freq; -+} -+ -+static unsigned long stm32_sai_mclk_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); -+ -+ return mclk->freq; -+} -+ -+static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); -+ struct stm32_sai_sub_data *sai = mclk->sai_data; -+ int div, ret; -+ -+ div = stm32_sai_get_clk_div(sai, parent_rate, rate); -+ if (div < 0) -+ return div; -+ -+ ret = stm32_sai_set_clk_div(sai, div); -+ if (ret) -+ return ret; -+ -+ mclk->freq = rate; -+ -+ return 0; -+} -+ -+static int stm32_sai_mclk_enable(struct clk_hw *hw) -+{ -+ struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); -+ struct stm32_sai_sub_data *sai = mclk->sai_data; -+ -+ dev_dbg(&sai->pdev->dev, "Enable master clock\n"); -+ -+ return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_MCKEN, SAI_XCR1_MCKEN); -+} -+ -+static void stm32_sai_mclk_disable(struct clk_hw *hw) -+{ -+ struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); -+ struct stm32_sai_sub_data *sai = mclk->sai_data; -+ -+ dev_dbg(&sai->pdev->dev, "Disable master clock\n"); -+ -+ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0); -+} -+ -+static const struct clk_ops mclk_ops = { -+ .enable = stm32_sai_mclk_enable, -+ .disable = stm32_sai_mclk_disable, -+ .recalc_rate = stm32_sai_mclk_recalc_rate, -+ .round_rate = stm32_sai_mclk_round_rate, -+ .set_rate = stm32_sai_mclk_set_rate, -+}; -+ -+static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) -+{ -+ struct clk_hw *hw; -+ struct stm32_sai_mclk_data *mclk; -+ struct device *dev = &sai->pdev->dev; -+ const char *pname = __clk_get_name(sai->sai_ck); -+ char *mclk_name, *p, *s = (char *)pname; -+ int ret, i = 0; -+ -+ mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL); -+ if (!mclk) -+ return -ENOMEM; -+ -+ mclk_name = devm_kcalloc(dev, sizeof(char), -+ SAI_MCLK_NAME_LEN, GFP_KERNEL); -+ if (!mclk_name) -+ return -ENOMEM; -+ -+ /* -+ * Forge mclk clock name from parent clock name and suffix. -+ * String after "_" char is stripped in parent name. -+ */ -+ p = mclk_name; -+ while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 7))) { -+ *p++ = *s++; -+ i++; -+ } -+ STM_SAI_IS_SUB_A(sai) ? strcat(p, "a_mclk") : strcat(p, "b_mclk"); -+ -+ mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0); -+ mclk->sai_data = sai; -+ hw = &mclk->hw; -+ -+ dev_dbg(dev, "Register master clock %s\n", mclk_name); -+ ret = devm_clk_hw_register(&sai->pdev->dev, hw); -+ if (ret) { -+ dev_err(dev, "mclk register returned %d\n", ret); -+ return ret; -+ } -+ sai->sai_mclk = hw->clk; -+ -+ /* register mclk provider */ -+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); -+} -+ - static irqreturn_t stm32_sai_isr(int irq, void *devid) - { - struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; -@@ -258,15 +509,15 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) - unsigned int sr, imr, flags; - snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; - -- regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr); -- regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr); -+ stm32_sai_sub_reg_rd(sai, STM_SAI_IMR_REGX, &imr); -+ stm32_sai_sub_reg_rd(sai, STM_SAI_SR_REGX, &sr); - - flags = sr & imr; - if (!flags) - return IRQ_NONE; - -- regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, -- SAI_XCLRFR_MASK); -+ stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, -+ SAI_XCLRFR_MASK); - - if (!sai->substream) { - dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr); -@@ -300,8 +551,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) - status = SNDRV_PCM_STATE_XRUN; - } - -- if (status != SNDRV_PCM_STATE_RUNNING) -+ spin_lock(&sai->irq_lock); -+ if (status != SNDRV_PCM_STATE_RUNNING && sai->substream) - snd_pcm_stop_xrun(sai->substream); -+ spin_unlock(&sai->irq_lock); - - return IRQ_HANDLED; - } -@@ -312,15 +565,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, - struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); - int ret; - -- if ((dir == SND_SOC_CLOCK_OUT) && sai->master) { -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -- SAI_XCR1_NODIV, -- (unsigned int)~SAI_XCR1_NODIV); -+ if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_NODIV, -+ (unsigned int)~SAI_XCR1_NODIV); - if (ret < 0) - return ret; - -- sai->mclk_rate = freq; -+ /* If master clock is used, set parent clock now */ -+ ret = stm32_sai_set_parent_clock(sai, freq); -+ if (ret) -+ return ret; -+ -+ ret = clk_set_rate_exclusive(sai->sai_mclk, freq); -+ if (ret) { -+ dev_err(cpu_dai->dev, -+ ret == -EBUSY ? -+ "Active streams have incompatible rates" : -+ "Could not set mclk rate\n"); -+ return ret; -+ } -+ - dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); -+ sai->mclk_rate = freq; - } - - return 0; -@@ -369,7 +636,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, - - slotr_mask |= SAI_XSLOTR_SLOTEN_MASK; - -- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr); -+ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, slotr_mask, slotr); - - sai->slot_width = slot_width; - sai->slots = slots; -@@ -451,7 +718,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) - cr1_mask |= SAI_XCR1_CKSTR; - frcr_mask |= SAI_XFRCR_FSPOL; - -- regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); -+ stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr); - - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -@@ -479,7 +746,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) - cr1_mask |= SAI_XCR1_SLAVE; - - conf_update: -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); - if (ret < 0) { - dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); - return ret; -@@ -495,8 +762,11 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, - { - struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); - int imr, cr2, ret; -+ unsigned long flags; - -+ spin_lock_irqsave(&sai->irq_lock, flags); - sai->substream = substream; -+ spin_unlock_irqrestore(&sai->irq_lock, flags); - - if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { - snd_pcm_hw_constraint_mask64(substream->runtime, -@@ -513,13 +783,12 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, - } - - /* Enable ITs */ -- -- regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, -- SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); -+ stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, -+ SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); - - imr = SAI_XIMR_OVRUDRIE; - if (STM_SAI_IS_CAPTURE(sai)) { -- regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2); -+ stm32_sai_sub_reg_rd(sai, STM_SAI_CR2_REGX, &cr2); - if (cr2 & SAI_XCR2_MUTECNT_MASK) - imr |= SAI_XIMR_MUTEDETIE; - } -@@ -529,8 +798,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, - else - imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE; - -- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, -- SAI_XIMR_MASK, imr); -+ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, -+ SAI_XIMR_MASK, imr); - - return 0; - } -@@ -547,10 +816,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, - * SAI fifo threshold is set to half fifo, to keep enough space - * for DMA incoming bursts. - */ -- regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX, -- SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, -- SAI_XCR2_FFLUSH | -- SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); -+ stm32_sai_sub_reg_wr(sai, STM_SAI_CR2_REGX, -+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, -+ SAI_XCR2_FFLUSH | -+ SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); - - /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ - if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { -@@ -579,7 +848,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, - if ((sai->slots == 2) && (params_channels(params) == 1)) - cr1 |= SAI_XCR1_MONO; - -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); - if (ret < 0) { - dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); - return ret; -@@ -593,7 +862,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) - struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); - int slotr, slot_sz; - -- regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr); -+ stm32_sai_sub_reg_rd(sai, STM_SAI_SLOTR_REGX, &slotr); - - /* - * If SLOTSZ is set to auto in SLOTR, align slot width on data size -@@ -615,16 +884,16 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) - sai->slots = 2; - - /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/ -- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, -- SAI_XSLOTR_NBSLOT_MASK, -- SAI_XSLOTR_NBSLOT_SET((sai->slots - 1))); -+ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, -+ SAI_XSLOTR_NBSLOT_MASK, -+ SAI_XSLOTR_NBSLOT_SET((sai->slots - 1))); - - /* Set default slots mask if not already set from DT */ - if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) { - sai->slot_mask = (1 << sai->slots) - 1; -- regmap_update_bits(sai->regmap, -- STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK, -- SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); -+ stm32_sai_sub_reg_up(sai, -+ STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK, -+ SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); - } - - dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n", -@@ -654,14 +923,14 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) - dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n", - sai->fs_length, fs_active); - -- regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); -+ stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr); - - if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) { - offset = sai->slot_width - sai->data_size; - -- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, -- SAI_XSLOTR_FBOFF_MASK, -- SAI_XSLOTR_FBOFF_SET(offset)); -+ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, -+ SAI_XSLOTR_FBOFF_MASK, -+ SAI_XSLOTR_FBOFF_SET(offset)); - } - } - -@@ -722,31 +991,35 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, - struct snd_pcm_hw_params *params) - { - struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); -- int cr1, mask, div = 0; -- int sai_clk_rate, mclk_ratio, den, ret; -- int version = sai->pdata->conf->version; -+ int div = 0; -+ int sai_clk_rate, mclk_ratio, den; - unsigned int rate = params_rate(params); -+ int ret, cr1 = 0; - -- if (!sai->mclk_rate) { -- dev_err(cpu_dai->dev, "Mclk rate is null\n"); -- return -EINVAL; -+ if (!sai->sai_mclk) { -+ ret = stm32_sai_set_parent_clock(sai, rate); -+ if (ret) -+ return ret; - } -- -- if (!(rate % 11025)) -- clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); -- else -- clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); - sai_clk_rate = clk_get_rate(sai->sai_ck); - - if (STM_SAI_IS_F4(sai->pdata)) { -- /* -- * mclk_rate = 256 * fs -- * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate -- * MCKDIV = sai_ck / (2 * mclk_rate) otherwise -+ /* mclk on (NODIV=0) -+ * mclk_rate = 256 * fs -+ * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate -+ * MCKDIV = sai_ck / (2 * mclk_rate) otherwise -+ * mclk off (NODIV=1) -+ * MCKDIV ignored. sck = sai_ck - */ -- if (2 * sai_clk_rate >= 3 * sai->mclk_rate) -- div = DIV_ROUND_CLOSEST(sai_clk_rate, -- 2 * sai->mclk_rate); -+ if (!sai->mclk_rate) -+ return 0; -+ -+ if (2 * sai_clk_rate >= 3 * sai->mclk_rate) { -+ div = stm32_sai_get_clk_div(sai, sai_clk_rate, -+ 2 * sai->mclk_rate); -+ if (div < 0) -+ return div; -+ } - } else { - /* - * TDM mode : -@@ -758,13 +1031,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, - * Note: NOMCK/NODIV correspond to same bit. - */ - if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { -- div = DIV_ROUND_CLOSEST(sai_clk_rate, -- (params_rate(params) * 128)); -+ div = stm32_sai_get_clk_div(sai, sai_clk_rate, -+ rate * 128); -+ if (div < 0) -+ return div; - } else { - if (sai->mclk_rate) { - mclk_ratio = sai->mclk_rate / rate; - if (mclk_ratio == 512) { -- mask = SAI_XCR1_OSR; - cr1 = SAI_XCR1_OSR; - } else if (mclk_ratio != 256) { - dev_err(cpu_dai->dev, -@@ -772,31 +1046,27 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, - mclk_ratio); - return -EINVAL; - } -- div = DIV_ROUND_CLOSEST(sai_clk_rate, -- sai->mclk_rate); -+ -+ stm32_sai_sub_reg_up(sai, -+ STM_SAI_CR1_REGX, -+ SAI_XCR1_OSR, cr1); -+ -+ div = stm32_sai_get_clk_div(sai, sai_clk_rate, -+ sai->mclk_rate); -+ if (div < 0) -+ return div; - } else { - /* mclk-fs not set, master clock not active */ - den = sai->fs_length * params_rate(params); -- div = DIV_ROUND_CLOSEST(sai_clk_rate, den); -+ div = stm32_sai_get_clk_div(sai, sai_clk_rate, -+ den); -+ if (div < 0) -+ return div; - } - } - } - -- if (div > SAI_XCR1_MCKDIV_MAX(version)) { -- dev_err(cpu_dai->dev, "Divider %d out of range\n", div); -- return -EINVAL; -- } -- dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div); -- -- mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); -- cr1 = SAI_XCR1_MCKDIV_SET(div); -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); -- if (ret < 0) { -- dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); -- return ret; -- } -- -- return 0; -+ return stm32_sai_set_clk_div(sai, div); - } - - static int stm32_sai_hw_params(struct snd_pcm_substream *substream, -@@ -841,12 +1111,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n"); - -- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -- SAI_XCR1_DMAEN, SAI_XCR1_DMAEN); -+ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_DMAEN, SAI_XCR1_DMAEN); - - /* Enable SAI */ -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -- SAI_XCR1_SAIEN, SAI_XCR1_SAIEN); -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_SAIEN, SAI_XCR1_SAIEN); - if (ret < 0) - dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); - break; -@@ -855,16 +1125,16 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_STOP: - dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); - -- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, -- SAI_XIMR_MASK, 0); -+ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, -+ SAI_XIMR_MASK, 0); - -- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -- SAI_XCR1_SAIEN, -- (unsigned int)~SAI_XCR1_SAIEN); -+ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_SAIEN, -+ (unsigned int)~SAI_XCR1_SAIEN); - -- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -- SAI_XCR1_DMAEN, -- (unsigned int)~SAI_XCR1_DMAEN); -+ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, -+ SAI_XCR1_DMAEN, -+ (unsigned int)~SAI_XCR1_DMAEN); - if (ret < 0) - dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); - -@@ -882,14 +1152,24 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) - { - struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); -+ unsigned long flags; -+ -+ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); - -- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); -+ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, -+ SAI_XCR1_NODIV); - -- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, -- SAI_XCR1_NODIV); -+ /* Release mclk rate only if rate was actually set */ -+ if (sai->mclk_rate) { -+ clk_rate_exclusive_put(sai->sai_mclk); -+ sai->mclk_rate = 0; -+ } - - clk_disable_unprepare(sai->sai_ck); -+ -+ spin_lock_irqsave(&sai->irq_lock, flags); - sai->substream = NULL; -+ spin_unlock_irqrestore(&sai->irq_lock, flags); - } - - static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, -@@ -910,7 +1190,9 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, - static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) - { - struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); -- int cr1 = 0, cr1_mask; -+ int cr1 = 0, cr1_mask, ret; -+ -+ sai->cpu_dai = cpu_dai; - - sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); - /* -@@ -919,6 +1201,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) - * constraints). - */ - sai->dma_params.maxburst = 4; -+ if (sai->pdata->conf.fifo_size < 8) -+ sai->dma_params.maxburst = 1; - /* Buswidth will be set by framework at runtime */ - sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; - -@@ -938,14 +1222,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) - /* Configure synchronization */ - if (sai->sync == SAI_SYNC_EXTERNAL) { - /* Configure synchro client and provider */ -- sai->pdata->set_sync(sai->pdata, sai->np_sync_provider, -- sai->synco, sai->synci); -+ ret = sai->pdata->set_sync(sai->pdata, sai->np_sync_provider, -+ sai->synco, sai->synci); -+ if (ret) -+ return ret; - } - - cr1_mask |= SAI_XCR1_SYNCEN_MASK; - cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); - -- return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); -+ return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); - } - - static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { -@@ -1099,11 +1385,16 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, - - sai->regmap_config = &stm32_sai_sub_regmap_config_f4; - /* Note: PDM registers not available for H7 sub-block B */ -- if (STM_SAI_IS_H7(sai->pdata) && STM_SAI_IS_SUB_A(sai)) -+ if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai)) - sai->regmap_config = &stm32_sai_sub_regmap_config_h7; - -- sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", -- base, sai->regmap_config); -+ /* -+ * Do not manage peripheral clock through regmap framework as this -+ * can lead to circular locking issue with sai master clock provider. -+ * Manage peripheral clock directly in driver instead. -+ */ -+ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, -+ sai->regmap_config); - if (IS_ERR(sai->regmap)) { - dev_err(&pdev->dev, "Failed to initialize MMIO\n"); - return PTR_ERR(sai->regmap); -@@ -1201,6 +1492,27 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, - return PTR_ERR(sai->sai_ck); - } - -+ ret = clk_prepare(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ if (STM_SAI_IS_F4(sai->pdata)) -+ return 0; -+ -+ /* Register mclk provider if requested */ -+ if (of_find_property(np, "#clock-cells", NULL)) { -+ ret = stm32_sai_add_mclk_provider(sai); -+ if (ret < 0) -+ return ret; -+ } else { -+ sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK"); -+ if (IS_ERR(sai->sai_mclk)) { -+ if (PTR_ERR(sai->sai_mclk) != -ENOENT) -+ return PTR_ERR(sai->sai_mclk); -+ sai->sai_mclk = NULL; -+ } -+ } -+ - return 0; - } - -@@ -1245,6 +1557,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) - - sai->pdev = pdev; - mutex_init(&sai->ctrl_lock); -+ spin_lock_init(&sai->irq_lock); - platform_set_drvdata(pdev, sai); - - sai->pdata = dev_get_drvdata(pdev->dev.parent); -@@ -1285,12 +1598,63 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) - return 0; - } - -+static int stm32_sai_sub_remove(struct platform_device *pdev) -+{ -+ struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev); -+ -+ clk_unprepare(sai->pdata->pclk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stm32_sai_sub_suspend(struct device *dev) -+{ -+ struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_enable(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ regcache_cache_only(sai->regmap, true); -+ regcache_mark_dirty(sai->regmap); -+ -+ clk_disable(sai->pdata->pclk); -+ -+ return 0; -+} -+ -+static int stm32_sai_sub_resume(struct device *dev) -+{ -+ struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_enable(sai->pdata->pclk); -+ if (ret < 0) -+ return ret; -+ -+ regcache_cache_only(sai->regmap, false); -+ ret = regcache_sync(sai->regmap); -+ -+ clk_disable(sai->pdata->pclk); -+ -+ return ret; -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static const struct dev_pm_ops stm32_sai_sub_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume) -+}; -+ - static struct platform_driver stm32_sai_sub_driver = { - .driver = { - .name = "st,stm32-sai-sub", - .of_match_table = stm32_sai_sub_ids, -+ .pm = &stm32_sai_sub_pm_ops, - }, - .probe = stm32_sai_sub_probe, -+ .remove = stm32_sai_sub_remove, - }; - - module_platform_driver(stm32_sai_sub_driver); -diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c -index 373df4f..5a5094e 100644 ---- a/sound/soc/stm/stm32_spdifrx.c -+++ b/sound/soc/stm/stm32_spdifrx.c -@@ -16,6 +16,7 @@ - * details. - */ - -+#include - #include - #include - #include -@@ -35,6 +36,9 @@ - #define STM32_SPDIFRX_DR 0x10 - #define STM32_SPDIFRX_CSR 0x14 - #define STM32_SPDIFRX_DIR 0x18 -+#define STM32_SPDIFRX_VERR 0x3F4 -+#define STM32_SPDIFRX_IDR 0x3F8 -+#define STM32_SPDIFRX_SIDR 0x3FC - - /* Bit definition for SPDIF_CR register */ - #define SPDIFRX_CR_SPDIFEN_SHIFT 0 -@@ -168,6 +172,18 @@ - #define SPDIFRX_SPDIFEN_SYNC 0x1 - #define SPDIFRX_SPDIFEN_ENABLE 0x3 - -+/* Bit definition for SPDIFRX_VERR register */ -+#define SPDIFRX_VERR_MIN_MASK GENMASK(3, 0) -+#define SPDIFRX_VERR_MAJ_MASK GENMASK(7, 4) -+ -+/* Bit definition for SPDIFRX_IDR register */ -+#define SPDIFRX_IDR_ID_MASK GENMASK(31, 0) -+ -+/* Bit definition for SPDIFRX_SIDR register */ -+#define SPDIFRX_SIDR_SID_MASK GENMASK(31, 0) -+ -+#define SPDIFRX_IPIDR_NUMBER 0x00130041 -+ - #define SPDIFRX_IN1 0x1 - #define SPDIFRX_IN2 0x2 - #define SPDIFRX_IN3 0x3 -@@ -213,6 +229,7 @@ - * @slave_config: dma slave channel runtime config pointer - * @phys_addr: SPDIFRX registers physical base address - * @lock: synchronization enabling lock -+ * @irq_lock: prevent race condition with IRQ on stream state - * @cs: channel status buffer - * @ub: user data buffer - * @irq: SPDIFRX interrupt line -@@ -233,6 +250,7 @@ struct stm32_spdifrx_data { - struct dma_slave_config slave_config; - dma_addr_t phys_addr; - spinlock_t lock; /* Sync enabling lock */ -+ spinlock_t irq_lock; /* Prevent race condition on stream state */ - unsigned char cs[SPDIFRX_CS_BYTES_NB]; - unsigned char ub[SPDIFRX_UB_BYTES_NB]; - int irq; -@@ -313,6 +331,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) - static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) - { - int cr, cr_mask, imr, ret; -+ unsigned long flags; - - /* Enable IRQs */ - imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; -@@ -320,7 +339,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) - if (ret) - return ret; - -- spin_lock(&spdifrx->lock); -+ spin_lock_irqsave(&spdifrx->lock, flags); - - spdifrx->refcount++; - -@@ -344,6 +363,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) - SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; - cr_mask = cr; - -+ cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); -+ cr_mask |= SPDIFRX_CR_NBTR_MASK; - cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); - cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; - ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, -@@ -353,7 +374,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) - "Failed to start synchronization\n"); - } - -- spin_unlock(&spdifrx->lock); -+ spin_unlock_irqrestore(&spdifrx->lock, flags); - - return ret; - } -@@ -361,11 +382,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) - static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) - { - int cr, cr_mask, reg; -+ unsigned long flags; - -- spin_lock(&spdifrx->lock); -+ spin_lock_irqsave(&spdifrx->lock, flags); - - if (--spdifrx->refcount) { -- spin_unlock(&spdifrx->lock); -+ spin_unlock_irqrestore(&spdifrx->lock, flags); - return; - } - -@@ -384,7 +406,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) - regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); - regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); - -- spin_unlock(&spdifrx->lock); -+ spin_unlock_irqrestore(&spdifrx->lock, flags); - } - - static int stm32_spdifrx_dma_ctrl_register(struct device *dev, -@@ -493,7 +515,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) - if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, - msecs_to_jiffies(100)) - <= 0) { -- dev_err(&spdifrx->pdev->dev, "Failed to get control data\n"); -+ dev_dbg(&spdifrx->pdev->dev, "Failed to get control data\n"); - ret = -EAGAIN; - } - -@@ -603,6 +625,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) - case STM32_SPDIFRX_DR: - case STM32_SPDIFRX_CSR: - case STM32_SPDIFRX_DIR: -+ case STM32_SPDIFRX_VERR: -+ case STM32_SPDIFRX_IDR: -+ case STM32_SPDIFRX_SIDR: - return true; - default: - return false; -@@ -611,10 +636,15 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) - - static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) - { -- if (reg == STM32_SPDIFRX_DR) -+ switch (reg) { -+ case STM32_SPDIFRX_DR: -+ case STM32_SPDIFRX_CSR: -+ case STM32_SPDIFRX_SR: -+ case STM32_SPDIFRX_DIR: - return true; -- -- return false; -+ default: -+ return false; -+ } - } - - static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) -@@ -633,20 +663,21 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, -- .max_register = STM32_SPDIFRX_DIR, -+ .max_register = STM32_SPDIFRX_SIDR, - .readable_reg = stm32_spdifrx_readable_reg, - .volatile_reg = stm32_spdifrx_volatile_reg, - .writeable_reg = stm32_spdifrx_writeable_reg, -+ .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1, - .fast_io = true, -+ .cache_type = REGCACHE_FLAT, - }; - - static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) - { - struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; -- struct snd_pcm_substream *substream = spdifrx->substream; - struct platform_device *pdev = spdifrx->pdev; - unsigned int cr, mask, sr, imr; -- unsigned int flags; -+ unsigned int flags, sync_state; - int err = 0, err_xrun = 0; - - regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); -@@ -706,19 +737,36 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) - } - - if (err) { -- /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ -+ regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); -+ sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && -+ SPDIFRX_SPDIFEN_SYNC; -+ -+ /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ - cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); - regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, - SPDIFRX_CR_SPDIFEN_MASK, cr); - -- if (substream) -- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); -+ /* If SPDIFRX was in STATE_SYNC, retry synchro */ -+ if (sync_state) { -+ cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); -+ regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, -+ SPDIFRX_CR_SPDIFEN_MASK, cr); -+ return IRQ_HANDLED; -+ } -+ -+ spin_lock(&spdifrx->irq_lock); -+ if (spdifrx->substream) -+ snd_pcm_stop(spdifrx->substream, -+ SNDRV_PCM_STATE_DISCONNECTED); -+ spin_unlock(&spdifrx->irq_lock); - - return IRQ_HANDLED; - } - -- if (err_xrun && substream) -- snd_pcm_stop_xrun(substream); -+ spin_lock(&spdifrx->irq_lock); -+ if (err_xrun && spdifrx->substream) -+ snd_pcm_stop_xrun(spdifrx->substream); -+ spin_unlock(&spdifrx->irq_lock); - - return IRQ_HANDLED; - } -@@ -727,9 +775,12 @@ static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) - { - struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); -+ unsigned long flags; - int ret; - -+ spin_lock_irqsave(&spdifrx->irq_lock, flags); - spdifrx->substream = substream; -+ spin_unlock_irqrestore(&spdifrx->irq_lock, flags); - - ret = clk_prepare_enable(spdifrx->kclk); - if (ret) -@@ -805,8 +856,12 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) - { - struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); -+ unsigned long flags; - -+ spin_lock_irqsave(&spdifrx->irq_lock, flags); - spdifrx->substream = NULL; -+ spin_unlock_irqrestore(&spdifrx->irq_lock, flags); -+ - clk_disable_unprepare(spdifrx->kclk); - } - -@@ -835,7 +890,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { - static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, - .buffer_bytes_max = 8 * PAGE_SIZE, -- .period_bytes_max = 2048, /* MDMA constraint */ -+ .period_bytes_min = 1024, /* 5ms at 48kHz */ -+ .period_bytes_max = PAGE_SIZE, - .periods_min = 2, - .periods_max = 8, - }; -@@ -901,6 +957,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - struct stm32_spdifrx_data *spdifrx; - struct reset_control *rst; - const struct snd_dmaengine_pcm_config *pcm_config = NULL; -+ u32 ver, idr; - int ret; - - spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); -@@ -910,6 +967,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - spdifrx->pdev = pdev; - init_completion(&spdifrx->cs_completion); - spin_lock_init(&spdifrx->lock); -+ spin_lock_init(&spdifrx->irq_lock); - - platform_set_drvdata(pdev, spdifrx); - -@@ -957,7 +1015,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - goto error; - } - -- return 0; -+ ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); -+ if (ret) -+ goto error; -+ -+ if (idr == SPDIFRX_IPIDR_NUMBER) { -+ ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); -+ -+ dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", -+ FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), -+ FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); -+ } -+ -+ return ret; - - error: - if (!IS_ERR(spdifrx->ctrl_chan)) -@@ -983,10 +1053,34 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) - - MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); - -+#ifdef CONFIG_PM_SLEEP -+static int stm32_spdifrx_suspend(struct device *dev) -+{ -+ struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); -+ -+ regcache_cache_only(spdifrx->regmap, true); -+ regcache_mark_dirty(spdifrx->regmap); -+ return 0; -+} -+ -+static int stm32_spdifrx_resume(struct device *dev) -+{ -+ struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); -+ -+ regcache_cache_only(spdifrx->regmap, false); -+ return regcache_sync(spdifrx->regmap); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static const struct dev_pm_ops stm32_spdifrx_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume) -+}; -+ - static struct platform_driver stm32_spdifrx_driver = { - .driver = { - .name = "st,stm32-spdifrx", - .of_match_table = stm32_spdifrx_ids, -+ .pm = &stm32_spdifrx_pm_ops, - }, - .probe = stm32_spdifrx_probe, - .remove = stm32_spdifrx_remove, --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch deleted file mode 100644 index d39b544..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 9166e19abab21450a32288379f5fb55f44e7a340 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:49 +0100 -Subject: [PATCH 29/31] ARM stm32mp1 r2.4 MISC - ---- - Documentation/remoteproc.txt | 23 ++++++++++++++++++++ - arch/arm/Kconfig.debug | 49 ++++++++++++++++++++++++++++++++++++++++-- - arch/arm/include/debug/stm32.S | 43 ++++++++++++++++++++++++++++++++++++ - include/linux/amba/mmci.h | 11 ++-------- - include/media/v4l2-fwnode.h | 2 ++ - kernel/power/suspend.c | 1 - - 6 files changed, 117 insertions(+), 12 deletions(-) - create mode 100644 arch/arm/include/debug/stm32.S - -diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt -index 77fb03a..bec2177 100644 ---- a/Documentation/remoteproc.txt -+++ b/Documentation/remoteproc.txt -@@ -353,3 +353,26 @@ Of course, RSC_VDEV resource entries are only good enough for static - allocation of virtio devices. Dynamic allocations will also be made possible - using the rpmsg bus (similar to how we already do dynamic allocations of - rpmsg channels; read more about it in rpmsg.txt). -+ -+8. System Resource Manager (SRM) -+ -+Since some resources are shared (directly or not) between the processors, a -+processor cannot manage such resources without potentially impacting the other -+processors : as an example, if a processor changes the frequency of a clock, the -+frequency of another clock managed by another processor may be updated too. -+ -+The System Resource Manager prevents such resource conflicts between the -+processors : it reserves and initializes the system resources of the peripherals -+assigned to a remote processor. -+ -+As of today the following resources are controlled by the SRM: -+- clocks -+- gpios (pinctrl) -+- regulators (power supplies) -+ -+The SRM is implemented as an 'rproc_subdev' and registered to remoteproc_core. -+Unlike the virtio device (vdev), the SRM subdev is probed *before* the rproc -+boots, ensuring the availability of the resources before the remoteproc starts. -+ -+The resources handled by the SRM are defined in the DeviceTree: please read -+Documentation/devicetree/bindings/remoteproc/rproc-srm.txt for details. -diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index bee0ba1..b402db6 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -1191,6 +1191,42 @@ choice - - If unsure, say N. - -+ config STM32F4_DEBUG_UART -+ bool "Use STM32F4 UART for low-level debug" -+ depends on ARCH_STM32 && ARM_SINGLE_ARMV7M -+ select DEBUG_STM32_UART -+ help -+ Say Y here if you want kernel low-level debugging support -+ on STM32F4 based platforms, which default UART is wired on -+ USART1, but another UART instance can be selected by modifying -+ CONFIG_DEBUG_UART_PHYS. -+ -+ If unsure, say N. -+ -+ config STM32F7_DEBUG_UART -+ bool "Use STM32F7 UART for low-level debug" -+ depends on ARCH_STM32 && ARM_SINGLE_ARMV7M -+ select DEBUG_STM32_UART -+ help -+ Say Y here if you want kernel low-level debugging support -+ on STM32F7 based platforms, which default UART is wired on -+ USART1, but another UART instance can be selected by modifying -+ CONFIG_DEBUG_UART_PHYS. -+ -+ If unsure, say N. -+ -+ config STM32MP1_DEBUG_UART -+ bool "Use STM32MP1 UART for low-level debug" -+ depends on ARCH_STM32 && ARCH_MULTI_V7 -+ select DEBUG_STM32_UART -+ help -+ Say Y here if you want kernel low-level debugging support -+ on STM32MP1 based platforms, wich default UART is wired on -+ UART4, but another UART instance can be selected by modifying -+ CONFIG_DEBUG_UART_PHYS and CONFIG_DEBUG_UART_VIRT. -+ -+ If unsure, say N. -+ - config TEGRA_DEBUG_UART_AUTO_ODMDATA - bool "Kernel low-level debugging messages via Tegra UART via ODMDATA" - depends on ARCH_TEGRA -@@ -1475,6 +1511,10 @@ config DEBUG_STI_UART - bool - depends on ARCH_STI - -+config DEBUG_STM32_UART -+ bool -+ depends on ARCH_STM32 -+ - config DEBUG_SIRFSOC_UART - bool - depends on ARCH_SIRF -@@ -1524,6 +1564,7 @@ config DEBUG_LL_INCLUDE - default "debug/s5pv210.S" if DEBUG_S5PV210_UART - default "debug/sirf.S" if DEBUG_SIRFSOC_UART - default "debug/sti.S" if DEBUG_STI_UART -+ default "debug/stm32.S" if DEBUG_STM32_UART - default "debug/tegra.S" if DEBUG_TEGRA_UART - default "debug/ux500.S" if DEBUG_UX500_UART - default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT -@@ -1587,6 +1628,8 @@ config DEBUG_UART_PHYS - default 0x3e000000 if DEBUG_BCM_KONA_UART - default 0x3f201000 if DEBUG_BCM2836 - default 0x4000e400 if DEBUG_LL_UART_EFM32 -+ default 0x40010000 if STM32MP1_DEBUG_UART -+ default 0x40011000 if STM32F4_DEBUG_UART || STM32F7_DEBUG_UART - default 0x40028000 if DEBUG_AT91_SAMV7_USART1 - default 0x40081000 if DEBUG_LPC18XX_UART0 - default 0x40090000 if DEBUG_LPC32XX -@@ -1681,10 +1724,12 @@ config DEBUG_UART_PHYS - DEBUG_S3C64XX_UART || \ - DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ - DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ -- DEBUG_AT91_UART -+ DEBUG_AT91_UART || STM32F4_DEBUG_UART || \ -+ STM32F7_DEBUG_UART || STM32MP1_DEBUG_UART - - config DEBUG_UART_VIRT - hex "Virtual base address of debug UART" -+ default 0xfe010000 if STM32MP1_DEBUG_UART - default 0xc881f000 if DEBUG_RV1108_UART2 - default 0xc8821000 if DEBUG_RV1108_UART1 - default 0xc8912000 if DEBUG_RV1108_UART0 -@@ -1797,7 +1842,7 @@ config DEBUG_UART_VIRT - DEBUG_S3C64XX_UART || \ - DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ - DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ -- DEBUG_AT91_UART -+ DEBUG_AT91_UART || STM32MP1_DEBUG_UART - - config DEBUG_UART_8250_SHIFT - int "Register offset shift for the 8250 debug UART" -diff --git a/arch/arm/include/debug/stm32.S b/arch/arm/include/debug/stm32.S -new file mode 100644 -index 0000000..3353a81 ---- /dev/null -+++ b/arch/arm/include/debug/stm32.S -@@ -0,0 +1,43 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) STMicroelectronics SA 2017 - All Rights Reserved -+ * Author: Gerald Baeza for STMicroelectronics. -+ */ -+ -+#ifdef CONFIG_STM32F4_DEBUG_UART -+#define STM32_USART_SR_OFF 0x00 -+#define STM32_USART_TDR_OFF 0x04 -+#endif -+ -+#if defined(CONFIG_STM32F7_DEBUG_UART) || defined(CONFIG_STM32MP1_DEBUG_UART) -+#define STM32_USART_SR_OFF 0x1C -+#define STM32_USART_TDR_OFF 0x28 -+#endif -+ -+#define STM32_USART_TC (1 << 6) /* Tx complete */ -+#define STM32_USART_TXE (1 << 7) /* Tx data reg empty */ -+ -+.macro addruart, rp, rv, tmp -+ ldr \rp, =CONFIG_DEBUG_UART_PHYS @ physical base -+#if defined(CONFIG_MMU) -+ ldr \rv, =CONFIG_DEBUG_UART_VIRT @ virt base -+#else -+ ldr \rv, =CONFIG_DEBUG_UART_PHYS @ same as physical base -+#endif -+.endm -+ -+.macro senduart,rd,rx -+ strb \rd, [\rx, #STM32_USART_TDR_OFF] -+.endm -+ -+.macro waituart,rd,rx -+1001: ldr \rd, [\rx, #(STM32_USART_SR_OFF)] @ Read Status Register -+ tst \rd, #STM32_USART_TXE @ TXE = 1 = tx empty -+ beq 1001b -+.endm -+ -+.macro busyuart,rd,rx -+1001: ldr \rd, [\rx, #(STM32_USART_SR_OFF)] @ Read Status Register -+ tst \rd, #STM32_USART_TC @ TC = 1 = tx complete -+ beq 1001b -+.endm -diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h -index da8357b..c92ebc3 100644 ---- a/include/linux/amba/mmci.h -+++ b/include/linux/amba/mmci.h -@@ -18,20 +18,13 @@ - * mask into a value to be binary (or set some other custom bits - * in MMCIPWR) or:ed and written into the MMCIPWR register of the - * block. May also control external power based on the power_mode. -- * @status: if no GPIO read function was given to the block in -- * gpio_wp (below) this function will be called to determine -- * whether a card is present in the MMC slot or not -- * @gpio_wp: read this GPIO pin to see if the card is write protected -- * @gpio_cd: read this GPIO pin to detect card insertion -- * @cd_invert: true if the gpio_cd pin value is active low -+ * @status: if no GPIO line was given to the block in this function will -+ * be called to determine whether a card is present in the MMC slot or not - */ - struct mmci_platform_data { - unsigned int ocr_mask; - int (*ios_handler)(struct device *, struct mmc_ios *); - unsigned int (*status)(struct device *); -- int gpio_wp; -- int gpio_cd; -- bool cd_invert; - }; - - #endif -diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h -index 9cccab6..946b48d 100644 ---- a/include/media/v4l2-fwnode.h -+++ b/include/media/v4l2-fwnode.h -@@ -52,11 +52,13 @@ struct v4l2_fwnode_bus_mipi_csi2 { - * @flags: media bus (V4L2_MBUS_*) flags - * @bus_width: bus width in bits - * @data_shift: data shift in bits -+ * @max_pclk_frequency: maximum pixel clock in hertz - */ - struct v4l2_fwnode_bus_parallel { - unsigned int flags; - unsigned char bus_width; - unsigned char data_shift; -+ unsigned int pclk_max_frequency; - }; - - /** -diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index 0bd595a..64f6aec 100644 ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -36,7 +36,6 @@ - #include "power.h" - - const char * const pm_labels[] = { -- [PM_SUSPEND_TO_IDLE] = "freeze", - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", - }; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch deleted file mode 100644 index eff795c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch +++ /dev/null @@ -1,9021 +0,0 @@ -From b7da07cd38a5e6c19c7a45c422d0da01b6069e8c Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:53 +0100 -Subject: [PATCH 30/31] ARM stm32mp1 r3 DEVICETREE - ---- - .../bindings/connector/usb-connector.txt | 2 + - .../devicetree/bindings/cpufreq/stm32-cpufreq.txt | 61 + - .../devicetree/bindings/display/bridge/sii902x.txt | 9 + - .../devicetree/bindings/dma/stm32-dma.txt | 36 +- - .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- - .../devicetree/bindings/dma/stm32-mdma.txt | 66 +- - Documentation/devicetree/bindings/gpio/gpio.txt | 12 + - .../bindings/hwlock/st,stm32-hwspinlock.txt | 23 + - .../devicetree/bindings/i2c/i2c-stm32.txt | 88 +- - .../bindings/iio/adc/sigma-delta-modulator.txt | 3 + - .../devicetree/bindings/iio/adc/st,stm32-adc.txt | 98 +- - .../bindings/iio/counter/stm32-lptimer-cnt.txt | 8 +- - .../bindings/iio/timer/stm32-timer-trigger.txt | 9 + - .../devicetree/bindings/input/st,stpmic1-onkey.txt | 28 + - .../interrupt-controller/st,stm32-exti.txt | 34 +- - .../devicetree/bindings/media/video-interfaces.txt | 2 + - .../devicetree/bindings/mfd/st,stm32mp1-pwr.txt | 57 + - .../devicetree/bindings/mfd/st,stpmic1.txt | 61 + - Documentation/devicetree/bindings/mfd/stmfx.txt | 28 + - Documentation/devicetree/bindings/mfd/syscon.txt | 1 + - Documentation/devicetree/bindings/mmc/mmci.txt | 13 + - .../devicetree/bindings/mtd/stm32-fmc2-nand.txt | 59 + - .../devicetree/bindings/net/stm32-dwmac.txt | 10 +- - .../devicetree/bindings/nvmem/st,stm32-romem.txt | 31 + - .../devicetree/bindings/perf/stm32-ddr-pmu.txt | 18 + - .../devicetree/bindings/phy/phy-stm32-usbphyc.txt | 65 +- - .../devicetree/bindings/pinctrl/pinctrl-stmfx.txt | 116 ++ - .../bindings/pinctrl/st,stm32-pinctrl.txt | 12 + - .../devicetree/bindings/pwm/pwm-stm32-lp.txt | 9 +- - .../devicetree/bindings/pwm/pwm-stm32.txt | 11 +- - .../bindings/regulator/st,stm32mp1-pwr-reg.txt | 42 + - .../bindings/regulator/st,stpmic1-regulator.txt | 69 ++ - .../devicetree/bindings/remoteproc/rproc-srm.txt | 58 + - .../devicetree/bindings/remoteproc/stm32-rproc.txt | 85 ++ - .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- - .../devicetree/bindings/serial/st,stm32-usart.txt | 41 +- - .../devicetree/bindings/soc/stm32/stm32_hdp.txt | 39 + - .../devicetree/bindings/spi/spi-stm32-qspi.txt | 47 + - .../devicetree/bindings/thermal/stm32-thermal.txt | 56 + - Documentation/devicetree/bindings/usb/dwc2.txt | 13 + - .../devicetree/bindings/usb/st,typec-stusb.txt | 40 + - Documentation/devicetree/bindings/usb/usb-ehci.txt | 5 + - .../bindings/watchdog/st,stpmic1-wdt.txt | 11 + - arch/arm/boot/dts/Makefile | 8 +- - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 1188 +++++++++++++++++++- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 767 +++++++++++++ - arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts | 14 + - arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts | 129 +++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 147 +++ - arch/arm/boot/dts/stm32mp157c-ed1.dts | 385 ++++++- - arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts | 33 + - arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts | 146 +++ - arch/arm/boot/dts/stm32mp157c-ev1.dts | 566 +++++++++- - arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 961 ++++++++++++++++ - arch/arm/boot/dts/stm32mp157c.dtsi | 1071 +++++++++++++++++- - arch/arm/boot/dts/stm32mp157caa-pinctrl.dtsi | 90 ++ - arch/arm/boot/dts/stm32mp157cab-pinctrl.dtsi | 62 + - arch/arm/boot/dts/stm32mp157cac-pinctrl.dtsi | 78 ++ - arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi | 62 + - 59 files changed, 6970 insertions(+), 228 deletions(-) - create mode 100644 Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt - create mode 100644 Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt - create mode 100644 Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt - create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt - create mode 100644 Documentation/devicetree/bindings/mfd/st,stpmic1.txt - create mode 100644 Documentation/devicetree/bindings/mfd/stmfx.txt - create mode 100644 Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt - create mode 100644 Documentation/devicetree/bindings/nvmem/st,stm32-romem.txt - create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt - create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt - create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt - create mode 100644 Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt - create mode 100644 Documentation/devicetree/bindings/remoteproc/rproc-srm.txt - create mode 100644 Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt - create mode 100644 Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt - create mode 100644 Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt - create mode 100644 Documentation/devicetree/bindings/thermal/stm32-thermal.txt - create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stusb.txt - create mode 100644 Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt - create mode 100644 arch/arm/boot/dts/stm32mp157a-dk1.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi - create mode 100644 arch/arm/boot/dts/stm32mp157caa-pinctrl.dtsi - create mode 100644 arch/arm/boot/dts/stm32mp157cab-pinctrl.dtsi - create mode 100644 arch/arm/boot/dts/stm32mp157cac-pinctrl.dtsi - create mode 100644 arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi - -diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt -index 8855bfc..bf43ee9 100644 ---- a/Documentation/devicetree/bindings/connector/usb-connector.txt -+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt -@@ -18,6 +18,8 @@ Optional properties: - Optional properties for usb-c-connector: - - power-role: should be one of "source", "sink" or "dual"(DRP) if typec - connector has power support. -+- power-opmode: should be one of "default", "1.5A", "3.0A" or -+ "usb_power_delivery" if typec connector has power support. - - try-power-role: preferred power role if "dual"(DRP) can support Try.SNK - or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. - - data-role: should be one of "host", "device", "dual"(DRD) if typec -diff --git a/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt -new file mode 100644 -index 0000000..1292eb2 ---- /dev/null -+++ b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt -@@ -0,0 +1,61 @@ -+STM32 CPUFreq and OPP bindings -+============================== -+ -+STM32 CPUFreq driver needs to read chip information from the SoC to list -+available OPPs. Then it depends on cpufreq-dt bindings. -+ -+Required properties: -+-------------------- -+- clocks: Phandle to the cpu clock "cpu". -+- clocks-name: Should contain "cpu". -+- nvmem-cells: Phandle to nvmem cell that contains "part_number". -+- nvmem-cell-names: Must be "part_number". -+- operating-points-v2: Phandle to operating points table. See ../power/opp.txt -+ for more details. -+ -+Optional properties: -+-------------------- -+See cpufreq-dt.txt for optional properties. -+ -+Examples: -+--------- -+ cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ cpu0: cpu@0 { -+ compatible = "arm,cortex-a7"; -+ device_type = "cpu"; -+ reg = <0>; -+ 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>; -+ 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>; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt -index 72d2dc6..00e9e88 100644 ---- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt -+++ b/Documentation/devicetree/bindings/display/bridge/sii902x.txt -@@ -13,6 +13,8 @@ Optional subnodes: - - video input: this subnode can contain a video input port node - to connect the bridge to a display controller output (See this - documentation [1]). -+ - audio input: this subnode can contain an audio input port node -+ to connect the bridge to an audio controller output. - - [1]: Documentation/devicetree/bindings/media/video-interfaces.txt - -@@ -31,5 +33,12 @@ Example: - remote-endpoint = <&dc_out>; - }; - }; -+ -+ port@1 { -+ reg = <1>; -+ codec_endpoint: endpoint { -+ remote-endpoint = <&i2s0_cpu_endpoint>; -+ }; -+ }; - }; - }; -diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt -index c5f5190..0982c574 100644 ---- a/Documentation/devicetree/bindings/dma/stm32-dma.txt -+++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt -@@ -17,6 +17,12 @@ Optional properties: - - resets: Reference to a reset controller asserting the DMA controller - - st,mem2mem: boolean; if defined, it indicates that the controller supports - memory-to-memory transfer -+- dmas: A list of eight dma specifiers, one for each entry in dma-names. -+ Refer to stm32-mdma.txt for more details. -+- dma-names: should contain "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6" and -+ "ch7" and represents each STM32 DMA channel connected to a STM32 MDMA one. -+- memory-region : phandle to a node describing memory to be used for -+ M2M intermediate transfer between DMA and MDMA. - - Example: - -@@ -36,6 +42,16 @@ Example: - st,mem2mem; - resets = <&rcc 150>; - dma-requests = <8>; -+ dmas = <&mdma1 8 0x10 0x1200000a 0x40026408 0x00000020 1>, -+ <&mdma1 9 0x10 0x1200000a 0x40026408 0x00000800 1>, -+ <&mdma1 10 0x10 0x1200000a 0x40026408 0x00200000 1>, -+ <&mdma1 11 0x10 0x1200000a 0x40026408 0x08000000 1>, -+ <&mdma1 12 0x10 0x1200000a 0x4002640C 0x00000020 1>, -+ <&mdma1 13 0x10 0x1200000a 0x4002640C 0x00000800 1>, -+ <&mdma1 14 0x10 0x1200000a 0x4002640C 0x00200000 1>, -+ <&mdma1 15 0x10 0x1200000a 0x4002640C 0x08000000 1>; -+ dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; -+ memory-region = <&sram_dmapool>; - }; - - * DMA client -@@ -62,13 +78,25 @@ channel: a phandle to the DMA controller plus the following four integer cells: - 0x1: medium - 0x2: high - 0x3: very high --4. A 32bit bitfield value specifying DMA features which are device dependent: -+4. A bitfield value specifying DMA features which are device dependent: - -bit 0-1: DMA FIFO threshold selection - 0x0: 1/4 full FIFO - 0x1: 1/2 full FIFO - 0x2: 3/4 full FIFO - 0x3: full FIFO -- -+ -bit 2: Intermediate M2M transfer from/to DDR to/from SRAM throughout MDMA -+ 0: MDMA not used to generate an intermediate M2M transfer -+ 1: MDMA used to generate an intermediate M2M transfer. -+ -bit 3-4: indicated SRAM Buffer size in (2^order)*PAGE_SIZE. -+ Order is given by those 2 bits starting at 0. -+ Valid only whether Intermediate M2M transfer is set. -+ For cyclic, whether Intermediate M2M transfer is chosen, any value can -+ be set: SRAM buffer size will rely on period size and not on this DT -+ value. -+ -bit 5: DMA direct mode -+ 0: FIFO mode: with threshold level selectable with bit 0-1 -+ 1: Direct mode: each DMA request immediately initiates a transfer -+ from/to the memory. - - Example: - -@@ -77,7 +105,7 @@ Example: - reg = <0x40011000 0x400>; - interrupts = <37>; - clocks = <&clk_pclk2>; -- dmas = <&dma2 2 4 0x10400 0x3>, -- <&dma2 7 5 0x10200 0x3>; -+ dmas = <&dma2 2 4 0x10400 0x1>, -+ <&dma2 7 5 0x10200 0x1>; - dma-names = "rx", "tx"; - }; -diff --git a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt -index 1b893b2..8e092d2 100644 ---- a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt -+++ b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt -@@ -4,9 +4,6 @@ Required properties: - - compatible: "st,stm32h7-dmamux" - - reg: Memory map for accessing module - - #dma-cells: Should be set to <3>. -- First parameter is request line number. -- Second is DMA channel configuration -- Third is Fifo threshold - For more details about the three cells, please see - stm32-dma.txt documentation binding file - - dma-masters: Phandle pointing to the DMA controllers. -@@ -53,7 +50,7 @@ dma2: dma@40020400 { - <68>, - <69>, - <70>; -- clocks = <&timer_clk>; -+ clocks = <&clk_hclk>; - #dma-cells = <4>; - st,mem2mem; - resets = <&rcc 150>; -diff --git a/Documentation/devicetree/bindings/dma/stm32-mdma.txt b/Documentation/devicetree/bindings/dma/stm32-mdma.txt -index d18772d..077c819a 100644 ---- a/Documentation/devicetree/bindings/dma/stm32-mdma.txt -+++ b/Documentation/devicetree/bindings/dma/stm32-mdma.txt -@@ -10,7 +10,7 @@ Required properties: - - interrupts: Should contain the MDMA interrupt. - - clocks: Should contain the input clock of the DMA instance. - - resets: Reference to a reset controller asserting the DMA controller. --- #dma-cells : Must be <5>. See DMA client paragraph for more details. -+- #dma-cells : Must be <6>. See DMA client paragraph for more details. - - Optional properties: - - dma-channels: Number of DMA channels supported by the controller. -@@ -26,7 +26,7 @@ Example: - interrupts = <122>; - clocks = <&timer_clk>; - resets = <&rcc 992>; -- #dma-cells = <5>; -+ #dma-cells = <6>; - dma-channels = <16>; - dma-requests = <32>; - st,ahb-addr-masks = <0x20000000>, <0x00000000>; -@@ -35,60 +35,64 @@ Example: - * DMA client - - DMA clients connected to the STM32 MDMA controller must use the format --described in the dma.txt file, using a five-cell specifier for each channel: --a phandle to the MDMA controller plus the following five integer cells: -+described in the dma.txt file, using a six-cell specifier for each channel: -+a phandle to the MDMA controller plus the following six integer cells: - - 1. The request line number - 2. The priority level -- 0x00: Low -- 0x01: Medium -- 0x10: High -- 0x11: Very high -+ 0x0: Low -+ 0x1: Medium -+ 0x2: High -+ 0x3: Very high - 3. A 32bit mask specifying the DMA channel configuration - -bit 0-1: Source increment mode -- 0x00: Source address pointer is fixed -- 0x10: Source address pointer is incremented after each data transfer -- 0x11: Source address pointer is decremented after each data transfer -+ 0x0: Source address pointer is fixed -+ 0x2: Source address pointer is incremented after each data transfer -+ 0x3: Source address pointer is decremented after each data transfer - -bit 2-3: Destination increment mode -- 0x00: Destination address pointer is fixed -- 0x10: Destination address pointer is incremented after each data -+ 0x0: Destination address pointer is fixed -+ 0x2: Destination address pointer is incremented after each data - transfer -- 0x11: Destination address pointer is decremented after each data -+ 0x3: Destination address pointer is decremented after each data - transfer - -bit 8-9: Source increment offset size -- 0x00: byte (8bit) -- 0x01: half-word (16bit) -- 0x10: word (32bit) -- 0x11: double-word (64bit) -+ 0x0: byte (8bit) -+ 0x1: half-word (16bit) -+ 0x2: word (32bit) -+ 0x3: double-word (64bit) - -bit 10-11: Destination increment offset size -- 0x00: byte (8bit) -- 0x01: half-word (16bit) -- 0x10: word (32bit) -- 0x11: double-word (64bit) -+ 0x0: byte (8bit) -+ 0x1: half-word (16bit) -+ 0x2: word (32bit) -+ 0x3: double-word (64bit) - -bit 25-18: The number of bytes to be transferred in a single transfer - (min = 1 byte, max = 128 bytes) - -bit 29:28: Trigger Mode -- 0x00: Each MDMA request triggers a buffer transfer (max 128 bytes) -- 0x01: Each MDMA request triggers a block transfer (max 64K bytes) -- 0x10: Each MDMA request triggers a repeated block transfer -- 0x11: Each MDMA request triggers a linked list transfer -+ 0x0: Each MDMA request triggers a buffer transfer (max 128 bytes) -+ 0x1: Each MDMA request triggers a block transfer (max 64K bytes) -+ 0x2: Each MDMA request triggers a repeated block transfer -+ 0x3: Each MDMA request triggers a linked list transfer - 4. A 32bit value specifying the register to be used to acknowledge the request - if no HW ack signal is used by the MDMA client - 5. A 32bit mask specifying the value to be written to acknowledge the request - if no HW ack signal is used by the MDMA client -+6. A bitfield value specifying if the MDMA client wants to generate M2M -+ transfer with HW trigger (1) or not (0). This bitfield should be only -+ enabled for M2M transfer triggered by STM32 DMA client. The memory devices -+ involved in this kind of transfer are SRAM and DDR. - - Example: - - i2c4: i2c@5c002000 { - compatible = "st,stm32f7-i2c"; - reg = <0x5c002000 0x400>; -- interrupts = <95>, -- <96>; -- clocks = <&timer_clk>; -+ interrupts = , -+ ; -+ clocks = <&clk_hsi>; - #address-cells = <1>; - #size-cells = <0>; -- dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>, -- <&mdma1 37 0x0 0x40002 0x0 0x0>; -+ dmas = <&mdma1 36 0x0 0x40008 0x0 0x0 0>, -+ <&mdma1 37 0x0 0x40002 0x0 0x0 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; -diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt -index a7c31de..14e2cdb 100644 ---- a/Documentation/devicetree/bindings/gpio/gpio.txt -+++ b/Documentation/devicetree/bindings/gpio/gpio.txt -@@ -82,6 +82,18 @@ Optional standard bitfield specifiers for the last cell: - https://en.wikipedia.org/wiki/Open_collector - - Bit 3: 0 means the output should be maintained during sleep/low-power mode - 1 means the output state can be lost during sleep/low-power mode -+- Bit 4: 0 means no pull-up resistor should be enabled -+ 1 means a pull-up resistor should be enabled -+ This setting only applies to hardware with a simple on/off -+ control for pull-up configuration. If the hardware has more -+ elaborate pull-up configuration, it should be represented -+ using a pin control binding. -+- Bit 5: 0 means no pull-down resistor should be enabled -+ 1 means a pull-down resistor should be enabled -+ This setting only applies to hardware with a simple on/off -+ control for pull-down configuration. If the hardware has more -+ elaborate pull-down configuration, it should be represented -+ using a pin control binding. - - 1.1) GPIO specifier best practices - ---------------------------------- -diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt -new file mode 100644 -index 0000000..adf4f000 ---- /dev/null -+++ b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt -@@ -0,0 +1,23 @@ -+STM32 Hardware Spinlock Device Binding -+------------------------------------- -+ -+Required properties : -+- compatible : should be "st,stm32-hwspinlock". -+- reg : the register address of hwspinlock. -+- #hwlock-cells : hwlock users only use the hwlock id to represent a specific -+ hwlock, so the number of cells should be <1> here. -+- clock-names : Must contain "hsem". -+- clocks : Must contain a phandle entry for the clock in clock-names, see the -+ common clock bindings. -+ -+Please look at the generic hwlock binding for usage information for consumers, -+"Documentation/devicetree/bindings/hwlock/hwlock.txt" -+ -+Example of hwlock provider: -+ hwspinlock@4c000000 { -+ compatible = "st,stm32-hwspinlock"; -+ #hwlock-cells = <1>; -+ reg = <0x4c000000 0x400>; -+ clocks = <&rcc HSEM>; -+ clock-names = "hsem"; -+ }; -diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -index 3b54899..f5194b4 100644 ---- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -+++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -@@ -1,33 +1,52 @@ - * I2C controller embedded in STMicroelectronics STM32 I2C platform - --Required properties : --- compatible : Must be one of the following -+Required properties: -+- compatible: Must be one of the following - - "st,stm32f4-i2c" - - "st,stm32f7-i2c" --- reg : Offset and length of the register set for the device --- interrupts : Must contain the interrupt id for I2C event and then the -+- 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. -+- interrupt-names: Must be "event", "error" and optionnaly "wakeup". - - 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, -+Optional properties: -+- clock-frequency: Desired I2C bus clock frequency in Hz. If not specified, - 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. -+- dmas: List of phandles to rx and tx DMA channels. Refer to stm32-dma.txt. -+- dma-names: List of dma names. Valid names are: "rx" and "tx". -+- 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: 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. -+- st,smbus-alert: enable the SMBus Alert feature -+- st,smbus-host-notify: enable the SMBus Host-Notify feature - --Example : -+Example: - - i2c@40005400 { - compatible = "st,stm32f4-i2c"; -@@ -52,5 +71,44 @@ Example : - resets = <&rcc STM32F7_APB1_RESET(I2C1)>; - clocks = <&rcc 1 CLK_I2C1>; - pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; -- pinctrl-names = "default"; -+ 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 -+i2c.txt file. -+ -+Required properties: -+- compatible -+ Device driver compatible name -+- reg -+ I2C slave addresses (see i2c.txt for more details) -+ -+Optional properties: -+ -+ i2c@40013000 { -+ camera@3c { -+ compatible = "ovti,ov5640"; -+ reg = <0x3c>; -+ }; - }; -diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt -index 59b92cd..fa70fda 100644 ---- a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt -+++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt -@@ -5,6 +5,9 @@ Required properties: - as a generic SD modulator if modulator not specified in compatible list. - - #io-channel-cells = <0>: See the IIO bindings section "IIO consumers". - -+Optional properties: -+- vref-supply: Phandle to the vref input analog reference voltage. -+ - Example node: - - ads1202: adc { -diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -index 8346bcb..a6aa796 100644 ---- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -@@ -46,6 +46,42 @@ Required properties: - Optional properties: - - A pinctrl state named "default" for each ADC channel may be defined to set - inX ADC pins in mode of operation for analog input on external pin. -+- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog -+ circuitry. -+ -+- vdda-supply: Phandle to the vdda input voltage. It can be used to supply ADC -+ analog inputs switches on stm32mp1 and stm32h7. -+ -+- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC -+ analog inputs switches on stm32mp1. -+ -+- st,syscfg-vbooster: Voltage booster control for analog switches supply. -+ This is available on stm32mp1 and stm32h7 (requires vdda-supply property). -+ It must be composed of 3 cells: -+ 1st cell: phandle to syscfg -+ 2nd cell: register offset within SYSCFG -+ 3rd cell: bitmask for BOOSTE on stm32h7, EN_BOOSTER set bit on stm32mp1 -+ -+- st,syscfg-vbooster-clr: Voltage booster clear for analog switches supply. -+ This is available on stm32mp1 (requires st,syscfg-vbooster and vdda-supply). -+ 1st cell: phandle to syscfg -+ 2nd cell: clear register offset within SYSCFG -+ 3rd cell: bitmask for EN_BOOSTER clear bit on stm32mp1 -+ -+- st,syscfg-anaswvdd: VDDA / VDD selection for analog switches supply. -+ This is available on stm32mp1 (requires vdda-supply and vdd-supply). -+ It must be composed of 3 cells: -+ 1st cell: phandle to syscfg -+ 2nd cell: register offset within SYSCFG -+ 3rd cell: bitmask for ANASWVDD set bit -+ -+- st,syscfg-anaswvdd-clr: VDDA / VDD selection clear for analog switches supply. -+ This is available on stm32mp1 (requires st,syscfg-anaswvdd, vdda-supply and -+ vdd-supply). -+ It must be composed of 3 cells: -+ 1st cell: phandle to syscfg -+ 2nd cell: clear register offset within SYSCFG -+ 3rd cell: bitmask for ANASWVDD clear bit - - Contents of a stm32 adc child node: - ----------------------------------- -@@ -63,8 +99,8 @@ Required properties: - - interrupts: IRQ Line for the ADC (e.g. may be 0 for adc@0, 1 for adc@100 or - 2 for adc@200). - - st,adc-channels: List of single-ended channels muxed for this ADC. -- It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered -- from 0 to 15 or 19 (resp. for in0..in15 or in0..in19). -+ It can have up to 19 channels on stm32f4 or 20 channels on stm32h7, numbered -+ from 0 to 18 or 19 (resp. for in0..in18 or in0..in19). - - st,adc-diff-channels: List of differential channels muxed for this ADC. - Depending on part used, some channels can be configured as differential - instead of single-ended (e.g. stm32h7). List here positive and negative -@@ -91,6 +127,38 @@ Optional properties: - fine tune of ADC sampling time may be recommended. - This can be either one value or an array that matches 'st,adc-channels' list, - to set sample time resp. for all channels, or independently for each channel. -+- st,trigger-polarity: Must be 0 (default), 1 or 2 to set default trigger -+ polarity to respectively "rising-edge", "falling-edge" or "both-edges". -+- st,injected: Use injected conversion sequence on an ADC, rather than regular. -+ -+Contents of a STM32 ADC temperature child node: -+----------------------------------------------- -+Required properties: -+- compatible: Should be one of: -+ "st,stm32f4-adc-temp" -+ "st,stm32h7-adc-temp" -+ "st,stm32mp1-adc-temp" -+- io-channels: Phandle to STM32 ADC temperature channel. -+- #io-channel-cells = <0>; -+- #thermal-sensor-cells = <0>; -+ -+Optional properties: -+- nvmem-cells: Phandles to nvmem cells that contain "ts_cal1" and "ts_cal2". -+- nvmem-cell-names: Must be "ts_cal1", "ts_cal2". -+ -+Contents of a stm32 adc EXTI trigger child node: -+------------------------------------------------ -+EXTI (External interrupt) can be used by STM32ADC as trigger source for -+conversions. ADC may use up to two EXTI GPIO lines: 11 & 15, e.g. external -+trigger signal can be routed to GPIOx (x is bank) pin 11 and/or 15. So, -+exti trigger child node is optional. -+ -+Required properties: -+- trigger-name: Must be exti11 (regular) or exti15 (injected). -+- interrupts: The exti interrupt source used as trigger. Generic interrupt -+ client node as described in ../../interrupt-controller/interrupts.txt -+ EXTI IRQ number must match with above trigger-name (e.g. 11 or 15). -+- interrupt-parent: Must be phandle to gpio bank. - - Example: - adc: adc@40012000 { -@@ -119,9 +187,16 @@ Example: - dmas = <&dma2 0 0 0x400 0x0>; - dma-names = "rx"; - assigned-resolution-bits = <8>; -+ st,trigger-polarity = <1>; - }; - ... - other adc child nodes follow... -+ -+ exti11 { -+ trigger-name = "exti11"; -+ interrupts = <11 0>; -+ interrupt-parent = <&gpioa>; -+ }; - }; - - Example to setup: -@@ -138,3 +213,22 @@ Example to setup: - st,adc-diff-channels = <2 6>, <3 7>; - }; - }; -+ -+Temperature sensor example: -+ adc: adc@40012000 { -+ compatible = "st,stm32f4-adc-core"; -+ ... -+ adc1: adc@0 { -+ ... -+ st,adc-channels = <18>; -+ st,min-sample-time-nsecs = <10000>; -+ }; -+ adc_temp: temp { -+ compatible = "st,stm32f4-adc-temp"; -+ io-channels = <&adc1 18>; -+ nvmem-cells = <&ts_cal1>, <&ts_cal2>; -+ nvmem-cell-names = "ts_cal1", "ts_cal2"; -+ #io-channel-cells = <0>; -+ #thermal-sensor-cells = <0>; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt -index a04aa5c..e90bc47 100644 ---- a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt -+++ b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt -@@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node. - - Required properties: - - compatible: Must be "st,stm32-lptimer-counter". --- pinctrl-names: Set to "default". --- pinctrl-0: List of phandles pointing to pin configuration nodes, -+- pinctrl-names: Set to "default". An additional "sleep" state can be -+ defined to set pins in sleep state. -+- pinctrl-n: List of phandles pointing to pin configuration nodes, - to set IN1/IN2 pins in mode of operation for Low-Power - Timer input on external pin. - -@@ -21,7 +22,8 @@ Example: - ... - counter { - compatible = "st,stm32-lptimer-counter"; -- pinctrl-names = "default"; -+ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&lptim1_in_pins>; -+ pinctrl-1 = <&lptim1_sleep_in_pins>; - }; - }; -diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt -index b8e8c76..4713ff1 100644 ---- a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt -+++ b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt -@@ -9,6 +9,12 @@ Required parameters: - "st,stm32h7-timer-trigger" - - reg: Identify trigger hardware block. - -+Optional properties: -+- pinctrl-names: Set to "default". An additional "sleep" state can be -+ defined to set pins in sleep state when in low power. -+- pinctrl-n: Phandle(s) pointing to pin configuration node for PWM, -+ respectively for "default" and "sleep" states. -+ - Example: - timers@40010000 { - #address-cells = <1>; -@@ -21,5 +27,8 @@ Example: - timer@0 { - compatible = "st,stm32-timer-trigger"; - reg = <0>; -+ pinctrl-0 = <&tim1_pins>; -+ pinctrl-1 = <&tim1_sleep_pins>; -+ pinctrl-names = "default", "sleep"; - }; - }; -diff --git a/Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt b/Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt -new file mode 100644 -index 0000000..4494613 ---- /dev/null -+++ b/Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt -@@ -0,0 +1,28 @@ -+STMicroelectronics STPMIC1 Onkey -+ -+Required properties: -+ -+- compatible = "st,stpmic1-onkey"; -+- interrupts: interrupt line to use -+- interrupt-names = "onkey-falling", "onkey-rising" -+ onkey-falling: happens when onkey is pressed; IT_PONKEY_F of pmic -+ onkey-rising: happens when onkey is released; IT_PONKEY_R of pmic -+ -+Optional properties: -+ -+- st,onkey-clear-cc-flag: onkey is able power on after an -+ over-current shutdown event. -+- st,onkey-pu-inactive: onkey pull up is not active -+- power-off-time-sec: Duration in seconds which the key should be kept -+ pressed for device to power off automatically (from 1 to 16 seconds). -+ see See Documentation/devicetree/bindings/input/keys.txt -+ -+Example: -+ -+onkey { -+ compatible = "st,stpmic1-onkey"; -+ interrupt-parent = <&pmic>; -+ interrupts = ,; -+ interrupt-names = "onkey-falling", "onkey-rising"; -+ power-off-time-sec = <10>; -+}; -diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt -index 6a36bf6..abcf816 100644 ---- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt -+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt -@@ -14,7 +14,23 @@ Required properties: - (only needed for exti controller with multiple exti under - same parent interrupt: st,stm32-exti and st,stm32h7-exti) - --Example: -+Optional properties: -+ -+- hwlocks: reference to a phandle of a hardware spinlock provider node. -+ -+Exti could have several parent interrupt controllers. In this case child nodes -+are used to describe those "extra" parent controllers. Properties to use are: -+ -+- interrupt-controller: Indentifies the node as an interrupt controller -+- #interrupt-cells: Specifies the number of cells to encode an interrupt -+ specifier, shall be 2 -+- interrupt-parent: Phandle to the interrupt parent node. -+- st,irq-number: Interrupt number mapped on the parent. -+ -+See example 2. -+ -+ -+Example 1: - - exti: interrupt-controller@40013c00 { - compatible = "st,stm32-exti"; -@@ -23,3 +39,19 @@ exti: interrupt-controller@40013c00 { - reg = <0x40013C00 0x400>; - interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>; - }; -+ -+Example 2: -+ -+exti: interrupt-controller@5000d000 { -+ compatible = "st,stm32mp1-exti", "syscon"; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ reg = <0x5000d000 0x400>; -+ -+ exti_pwr: exti-pwr { -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ interrupt-parent = <&pwr>; -+ st,irq-number = <6>; -+ }; -+}; -diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt -index baf9d97..fa4c112 100644 ---- a/Documentation/devicetree/bindings/media/video-interfaces.txt -+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt -@@ -147,6 +147,8 @@ Optional endpoint properties - as 0 (normal). This property is valid for serial busses only. - - strobe: Whether the clock signal is used as clock (0) or strobe (1). Used - with CCP2, for instance. -+- pclk-max-frequency: maximum pixel clock frequency admissible by video -+ host interface. - - Example - ------- -diff --git a/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt -new file mode 100644 -index 0000000..eb62238 ---- /dev/null -+++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt -@@ -0,0 +1,57 @@ -+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> -+- wakeup-gpios: contains a list of GPIO spec describing each wake-up pin. -+ -+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>; -+ -+ wakeup-gpios = <&gpioa 0 0>, <&gpioa 2 0>, -+ <&gpioc 13 0>, <&gpioi 8 0>, -+ <&gpioi 11 0>, <&gpioc 1 0>; -+ -+ 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>; -+ wakeup-source; -+ }; -+}; -+ -diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -new file mode 100644 -index 0000000..afd45c0 ---- /dev/null -+++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -@@ -0,0 +1,61 @@ -+* STMicroelectronics STPMIC1 Power Management IC -+ -+Required properties: -+- compatible: : "st,stpmic1" -+- reg: : The I2C slave address for the STPMIC1 chip. -+- interrupts: : The interrupt line the device is connected to. -+- #interrupt-cells: : Should be 1. -+- interrupt-controller: : Marks the device node as an interrupt controller. -+ Interrupt numbers are defined at -+ dt-bindings/mfd/st,stpmic1.h. -+ -+STPMIC1 consists in a varied group of sub-devices. -+Each sub-device binding is be described in own documentation file. -+ -+Device Description -+------ ------------ -+st,stpmic1-onkey : Power on key, see ../input/st,stpmic1-onkey.txt -+st,stpmic1-regulators : Regulators, see ../regulator/st,stpmic1-regulator.txt -+st,stpmic1-wdt : Watchdog, see ../watchdog/st,stpmic1-wdt.txt -+ -+Example: -+ -+#include -+ -+pmic: pmic@33 { -+ compatible = "st,stpmic1"; -+ reg = <0x33>; -+ interrupt-parent = <&gpioa>; -+ interrupts = <0 2>; -+ -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ -+ onkey { -+ compatible = "st,stpmic1-onkey"; -+ interrupts = ,; -+ interrupt-names = "onkey-falling", "onkey-rising"; -+ power-off-time-sec = <10>; -+ }; -+ -+ watchdog { -+ compatible = "st,stpmic1-wdt"; -+ }; -+ -+ regulators { -+ compatible = "st,stpmic1-regulators"; -+ -+ vdd_core: buck1 { -+ regulator-name = "vdd_core"; -+ regulator-boot-on; -+ regulator-min-microvolt = <700000>; -+ regulator-max-microvolt = <1200000>; -+ }; -+ vdd: buck3 { -+ regulator-name = "vdd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-pull-down; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/mfd/stmfx.txt b/Documentation/devicetree/bindings/mfd/stmfx.txt -new file mode 100644 -index 0000000..f0c2f7f ---- /dev/null -+++ b/Documentation/devicetree/bindings/mfd/stmfx.txt -@@ -0,0 +1,28 @@ -+STMicroelectonics Multi-Function eXpander (STMFX) Core bindings -+ -+ST Multi-Function eXpander (STMFX) is a slave controller using I2C for -+communication with the main MCU. Its main features are GPIO expansion, main -+MCU IDD measurement (IDD is the amount of current that flows through VDD) and -+resistive touchscreen controller. -+ -+Required properties: -+- compatible: should be "st,stmfx-0300". -+- reg: I2C slave address of the device. -+- interrupts: interrupt specifier triggered by MFX_IRQ_OUT signal. -+ Please refer to ../interrupt-controller/interrupt.txt -+ -+Optional properties: -+- drive-open-drain: configure MFX_IRQ_OUT as open drain. -+- vdd-supply: phandle of the regulator supplying STMFX. -+ -+Example: -+ -+ stmfx: stmfx@42 { -+ compatible = "st,stmfx-0300"; -+ reg = <0x42>; -+ interrupts = <8 IRQ_TYPE_EDGE_RISING>; -+ interrupt-parent = <&gpioi>; -+ vdd-supply = <&v3v3>; -+ }; -+ -+Please refer to ../pinctrl/pinctrl-stmfx.txt for STMFX GPIO expander function bindings. -diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt -index 25d9e9c..a9aaa51 100644 ---- a/Documentation/devicetree/bindings/mfd/syscon.txt -+++ b/Documentation/devicetree/bindings/mfd/syscon.txt -@@ -17,6 +17,7 @@ Optional property: - - reg-io-width: the size (in bytes) of the IO accesses that should be - performed on the device. - - hwlocks: reference to a phandle of a hardware spinlock provider node. -+- clocks: phandle to the syscon clock - - Examples: - gpr: iomuxc-gpr@20e0000 { -diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt -index 03796cf..da6d59e 100644 ---- a/Documentation/devicetree/bindings/mmc/mmci.txt -+++ b/Documentation/devicetree/bindings/mmc/mmci.txt -@@ -15,8 +15,13 @@ Required properties: - Optional properties: - - arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides - the ID provided by the HW -+- reg : sdmmc variant could have a second base register for -+ delay block. -+- resets : phandle to internal reset line. -+ Should be defined for sdmmc variant. - - vqmmc-supply : phandle to the regulator device tree node, mentioned - as the VCCQ/VDD_IO supply in the eMMC/SD specs. -+specific for ux500 variant: - - st,sig-dir-dat0 : bus signal direction pin used for DAT[0]. - - st,sig-dir-dat2 : bus signal direction pin used for DAT[2]. - - st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. -@@ -24,6 +29,14 @@ Optional properties: - - st,sig-dir-cmd : cmd signal direction pin used for CMD. - - st,sig-pin-fbclk : feedback clock signal pin used. - -+specific for sdmmc variant: -+- st,sig-dir : signal direction polarity used for cmd, dat0 dat123. -+- st,neg-edge : data & command phase relation, generated on -+ sd clock falling edge. -+- st,use-ckin : use ckin pin from an external driver to sample -+ the receive data (example: with voltage -+ switch transceiver). -+ - Deprecated properties: - - mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable. - - mmc-cap-sd-highspeed : indicates whether SD is high speed capable. -diff --git a/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt b/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt -new file mode 100644 -index 0000000..70e76be ---- /dev/null -+++ b/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt -@@ -0,0 +1,59 @@ -+STMicroelectronics Flexible Memory Controller 2 (FMC2) -+NAND Interface -+ -+Required properties: -+- compatible: Should be one of: -+ * st,stm32mp15-fmc2 -+- reg: NAND flash controller memory areas. -+ First region contains the register location. -+ Regions 2 to 4 respectively contain the data, command, -+ and address space for CS0. -+ Regions 5 to 7 contain the same areas for CS1. -+- interrupts: The interrupt number -+- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt) -+- clocks: The clock needed by the NAND flash controller -+ -+Optional properties: -+- resets: Reference to a reset controller asserting the FMC controller -+- dmas: DMA specifiers (see: dma/stm32-mdma.txt) -+- dma-names: Must be "tx", "rx" and "ecc" -+ -+Optional children nodes: -+Children nodes represent the available NAND chips. -+ -+Optional properties: -+- nand-on-flash-bbt: see nand.txt -+- nand-ecc-strength: see nand.txt -+- nand-ecc-step-size: see nand.txt -+ -+The following ECC strength and step size are currently supported: -+ - nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming) -+ - nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4) -+ - nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default) -+ -+Example: -+ -+ fmc: nand-controller@58002000 { -+ compatible = "st,stm32mp15-fmc2"; -+ reg = <0x58002000 0x1000>, -+ <0x80000000 0x1000>, -+ <0x88010000 0x1000>, -+ <0x88020000 0x1000>, -+ <0x81000000 0x1000>, -+ <0x89010000 0x1000>, -+ <0x89020000 0x1000>; -+ interrupts = ; -+ clocks = <&rcc FMC_K>; -+ resets = <&rcc FMC_R>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fmc_pins_a>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ nand@0 { -+ reg = <0>; -+ nand-on-flash-bbt; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt -index 1341012..5f6a6ba 100644 ---- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt -+++ b/Documentation/devicetree/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,9 +23,10 @@ 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 --- st,int-phyclk (boolean) : valid only where PHY do not have quartz and need to be clock -- by RCC -+- 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 - - Example: - -diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.txt b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.txt -new file mode 100644 -index 0000000..fbff52e ---- /dev/null -+++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.txt -@@ -0,0 +1,31 @@ -+STMicroelectronics STM32 Factory-programmed data device tree bindings -+ -+This represents STM32 Factory-programmed read only non-volatile area: locked -+flash, OTP, read-only HW regs... This contains various information such as: -+analog calibration data for temperature sensor (e.g. TS_CAL1, TS_CAL2), -+internal vref (VREFIN_CAL), unique device ID... -+ -+Required properties: -+- compatible: Should be one of: -+ "st,stm32-romem" -+ "st,stm32mp15-bsec" -+- reg: Offset and length of factory-programmed area. -+- #address-cells: Should be '<1>'. -+- #size-cells: Should be '<1>'. -+ -+Optional Data cells: -+- Must be child nodes as described in nvmem.txt. -+ -+Example on stm32f4: -+ romem: nvmem@1fff7800 { -+ compatible = "st,stm32-romem"; -+ reg = <0x1fff7800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ /* Data cells: ts_cal1 at 0x1fff7a2c */ -+ ts_cal1: calib@22c { -+ reg = <0x22c 0x2>; -+ }; -+ ... -+ }; -diff --git a/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt -new file mode 100644 -index 0000000..dabc4c7 ---- /dev/null -+++ b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt -@@ -0,0 +1,18 @@ -+* STM32 DDR Performance Monitor (DDRPERFM) -+ -+Required properties: -+- compatible: must be "st,stm32-ddr-pmu". -+- reg: physical address and length of the registers set. -+- clocks: list of phandles and specifiers to all input clocks listed in -+ clock-names property. -+- clock-names: "bus" corresponds to the DDRPERFM bus clock and "ddr" to -+ the DDR frequency. -+ -+Example: -+ ddrperfm: perf@5a007000 { -+ compatible = "st,stm32-ddr-pmu"; -+ reg = <0x5a007000 0x400>; -+ clocks = <&rcc DDRPERFM>, <&rcc PLL2_R>; -+ clock-names = "bus", "ddr"; -+ }; -+ -diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt -index 725ae71..cc44bf4 100644 ---- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt -+++ b/Documentation/devicetree/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/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt -new file mode 100644 -index 0000000..c1b4c18 ---- /dev/null -+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt -@@ -0,0 +1,116 @@ -+STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander bindings -+ -+ST Multi-Function eXpander (STMFX) offers up to 24 GPIOs expansion. -+Please refer to ../mfd/stmfx.txt for STMFX Core bindings. -+ -+Required properties: -+- compatible: should be "st,stmfx-0300-pinctrl". -+- #gpio-cells: should be <2>, the first cell is the GPIO number and the second -+ cell is the gpio flags in accordance with . -+- gpio-controller: marks the device as a GPIO controller. -+- #interrupt-cells: should be <2>, the first cell is the GPIO number and the -+ second cell is the interrupt flags in accordance with -+ . -+- interrupt-controller: marks the device as an interrupt controller. -+- gpio-ranges: specifies the mapping between gpio controller and pin -+ controller pins. Check "Concerning gpio-ranges property" below. -+Please refer to ../gpio/gpio.txt. -+ -+Please refer to pinctrl-bindings.txt for pin configuration. -+ -+Required properties for pin configuration sub-nodes: -+- pins: list of pins to which the configuration applies. -+ -+Optional properties for pin configuration sub-nodes (pinconf-generic ones): -+- bias-disable: disable any bias on the pin. -+- bias-pull-up: the pin will be pulled up. -+- bias-pull-pin-default: use the pin-default pull state. -+- bias-pull-down: the pin will be pulled down. -+- drive-open-drain: the pin will be driven with open drain. -+- drive-push-pull: the pin will be driven actively high and low. -+- output-high: the pin will be configured as an output driving high level. -+- output-low: the pin will be configured as an output driving low level. -+ -+Note that STMFX pins[15:0] are called "gpio[15:0]", and STMFX pins[23:16] are -+called "agpio[7:0]". Example, to refer to pin 18 of STMFX, use "agpio2". -+ -+Concerning gpio-ranges property: -+- if all STMFX pins[24:0] are available (no other STMFX function in use), you -+ should use gpio-ranges = <&stmfx_pinctrl 0 0 24>; -+- if agpio[3:0] are not available (STMFX Touchscreen function in use), you -+ should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>; -+- if agpio[7:4] are not available (STMFX IDD function in use), you -+ should use gpio-ranges = <&stmfx_pinctrl 0 0 20>; -+ -+ -+Example: -+ -+ stmfx: stmfx@42 { -+ ... -+ -+ stmfx_pinctrl: stmfx-pin-controller { -+ compatible = "st,stmfx-0300-pinctrl"; -+ #gpio-cells = <2>; -+ #interrupt-cells = <2>; -+ gpio-controller; -+ interrupt-controller; -+ gpio-ranges = <&stmfx_pinctrl 0 0 24>; -+ -+ joystick_pins: joystick { -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; -+ drive-push-pull; -+ bias-pull-up; -+ }; -+ }; -+ }; -+ -+Example of STMFX GPIO consumers: -+ -+ joystick { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #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>; -+ }; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ orange { -+ gpios = <&stmfx_pinctrl 17 1>; -+ }; -+ -+ blue { -+ gpios = <&stmfx_pinctrl 19 1>; -+ }; -+ } -diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -index ef4f2ff..793e428 100644 ---- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -@@ -56,6 +56,9 @@ Optional properties: - 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 1: - #include -@@ -146,11 +149,16 @@ Required properties: - * ... - * 16 : Alternate Function 15 - * 17 : Analog -+ * 18 : Reserved - - To simplify the usage, macro is available to generate "pinmux" field. - This macro is available here: - - include/dt-bindings/pinctrl/stm32-pinfunc.h - -+ Setting the pinmux's function to the Reserved (RSVD) value is used to inform -+ the driver that it shall not apply the mux setting. This can be used to -+ reserve some pins, for example to a co-processor not running Linux. -+ - Some examples of using macro: - /* GPIO A9 set as alernate function 2 */ - ... { -@@ -164,6 +172,10 @@ Required properties: - ... { - pinmux = ; - }; -+ /* GPIO A9 reserved for co-processor */ -+ ... { -+ pinmux = ; -+ }; - - Optional properties: - - GENERIC_PINCONFIG: is the generic pinconfig options to use. -diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt -index bd23302..6521bc4 100644 ---- a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt -+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt -@@ -11,8 +11,10 @@ Required parameters: - bindings defined in pwm.txt. - - Optional properties: --- pinctrl-names: Set to "default". --- pinctrl-0: Phandle pointing to pin configuration node for PWM. -+- pinctrl-names: Set to "default". An additional "sleep" state can be -+ defined to set pins in sleep state when in low power. -+- pinctrl-n: Phandle(s) pointing to pin configuration node for PWM, -+ respectively for "default" and "sleep" states. - - Example: - timer@40002400 { -@@ -21,7 +23,8 @@ Example: - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; -- pinctrl-names = "default"; -+ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&lppwm1_pins>; -+ pinctrl-1 = <&lppwm1_sleep_pins>; - }; - }; -diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -index 3e6d550..f1620c1 100644 ---- a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -@@ -5,9 +5,12 @@ See ../mfd/stm32-timers.txt for details about the parent node. - - Required parameters: - - compatible: Must be "st,stm32-pwm". --- pinctrl-names: Set to "default". --- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. -+- pinctrl-names: Set to "default". An additional "sleep" state can be -+ defined to set pins in sleep state when in low power. -+- pinctrl-n: List of phandles pointing to pin configuration nodes for PWM module. - For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt -+- #pwm-cells: Should be set to 3. This PWM chip uses the default 3 cells -+ bindings defined in pwm.txt. - - Optional parameters: - - st,breakinput: One or two to describe break input configurations. -@@ -28,8 +31,10 @@ Example: - - pwm { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - pinctrl-0 = <&pwm1_pins>; -- pinctrl-names = "default"; -+ pinctrl-1 = <&pwm1_sleep_pins>; -+ pinctrl-names = "default", "sleep"; - st,breakinput = <0 1 5>; - }; - }; -diff --git a/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt -new file mode 100644 -index 0000000..12acf9d ---- /dev/null -+++ b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt -@@ -0,0 +1,42 @@ -+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 = & ; -+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"; -+ regulator-min-microvolt = <1100000>; -+ regulator-max-microvolt = <1100000>; -+ }; -+ -+ reg18: reg18 { -+ regulator-name = "reg18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ }; -+ -+ usb33: usb33 { -+ regulator-name = "usb33"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt b/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt -new file mode 100644 -index 0000000..0a57e40 ---- /dev/null -+++ b/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt -@@ -0,0 +1,69 @@ -+STMicroelectronics STPMIC1 Voltage regulators -+ -+Regulator Nodes are optional depending on needs. -+ -+Available Regulators in STPMIC1 device are: -+ - buck1 for Buck BUCK1 -+ - buck2 for Buck BUCK2 -+ - buck3 for Buck BUCK3 -+ - buck4 for Buck BUCK4 -+ - ldo1 for LDO LDO1 -+ - ldo2 for LDO LDO2 -+ - ldo3 for LDO LDO3 -+ - ldo4 for LDO LDO4 -+ - ldo5 for LDO LDO5 -+ - ldo6 for LDO LDO6 -+ - vref_ddr for LDO Vref DDR -+ - boost for Buck BOOST -+ - pwr_sw1 for VBUS_OTG switch -+ - pwr_sw2 for SW_OUT switch -+ -+Switches are fixed voltage regulators with only enable/disable capability. -+ -+Optional properties: -+- st,mask-reset: mask reset for this regulator: the regulator configuration -+ is maintained during pmic reset. -+- regulator-pull-down: enable high pull down -+ if not specified light pull down is used -+- regulator-over-current-protection: -+ if set, all regulators are switched off in case of over-current detection -+ on this regulator, -+ if not set, the driver only sends an over-current event. -+- interrupt-parent: phandle to the parent interrupt controller -+- interrupts: index of current limit detection interrupt -+- -supply: phandle to the parent supply/regulator node -+ each regulator supply can be described except vref_ddr. -+- regulator-active-discharge: can be used on pwr_sw1 and pwr_sw2. -+ -+Example: -+regulators { -+ compatible = "st,stpmic1-regulators"; -+ -+ ldo6-supply = <&v3v3>; -+ -+ vdd_core: buck1 { -+ regulator-name = "vdd_core"; -+ interrupts = ; -+ interrupt-parent = <&pmic>; -+ st,mask-reset; -+ regulator-pull-down; -+ regulator-min-microvolt = <700000>; -+ regulator-max-microvolt = <1200000>; -+ }; -+ -+ v3v3: buck4 { -+ regulator-name = "v3v3"; -+ interrupts = ; -+ interrupt-parent = <&mypmic>; -+ -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ }; -+ -+ v1v8: ldo6 { -+ regulator-name = "v1v8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-over-current-protection; -+ }; -+}; -diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -new file mode 100644 -index 0000000..66fccd5 ---- /dev/null -+++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -@@ -0,0 +1,58 @@ -+Remoteproc System Resource Manager -+---------------------------------- -+ -+The remoteproc SRM (System Resource Manager) handles resources allocated -+to remote processors. -+This makes it possible for remote proc to reserve and initialize system -+resources for a peripheral assigned to a coprocessor. -+ -+The devices are grouped in a core node -+ -+Core -+==== -+Required properties: -+- compatible: should be "rproc-srm-core" -+ -+Dev -+=== -+Required properties: -+- compatible: should be "rproc-srm-dev" -+ -+Optional properties: -+- reg: register base address and length -+- clocks: clocks required by the coprocessor -+- clock-names: see clock-bindings.txt -+- pinctrl-0: pins configurations required by the coprocessor. -+ The SRM reserves the pins for the coprocessor, which prevents the local -+ processor to use them. -+- pinctrl-names: must be "default". -+- x-supply: power supplies required by the coprocessor -+- interrupts: external interrupts configurations required by the coprocessor. -+ This is optional since the configuration is done by the coprocessor. -+ When defined, the SRM (over)writes the configuration which allows the -+ interrupt controller to check for configuration conflicts. -+- interrupt-parent: see interrupts.txt -+- interrupt-names: see interrupts.txt -+ -+Example: -+ system_resources { -+ compatible = "rproc-srm-core"; -+ -+ mmc0: sdhci@09060000 { -+ compatible = "rproc-srm-dev"; -+ reg = <0x09060000 0x100>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_mmc0_m4>; -+ clock-names = "mmc", "icn"; -+ clocks = <&clk_s_c0_flexgen CLK_MMC_0>, -+ <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; -+ vdda-supply = <&vdda>; -+ }; -+ -+ button { -+ compatible = "rproc-srm-dev"; -+ interrupt-parent = <&gpioa>; -+ interrupts = <5 1>; -+ interrupt-names = "gpio_key"; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -new file mode 100644 -index 0000000..3960ce9 ---- /dev/null -+++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -0,0 +1,85 @@ -+STMicroelectronics STM32 Remoteproc -+----------------------------------- -+This document defines the binding for the remoteproc component that loads and -+boots firmwares on the ST32MP family chipset. -+ -+Required properties: -+- compatible: Must be "st,stm32mp1-rproc" -+- ranges: Describe memory addresses translation between Linux processor -+ and the remote processor. -+ Each memory region, is declared with 3 parameters: -+ - param 1: device base address (remote processor address), -+ - param 2: physical base address (Linux Processor address), -+ - param 3: size in Byte of the memory region. -+- resets: Reference to a reset controller asserting the remote processor. -+- reset-names: Must be "mcu_rst" -+- st,syscfg-holdboot: Reference to the system configuration controlling the -+ remote processor reset hold boot -+ 1st cell: phandle of syscon block -+ 2nd cell: register offset containing the hold boot setting -+ 3rd cell: register bitmask for the hold boot field -+- st,syscfg-tz: Reference to the system configuration controlling the trust zone -+ mode -+ 1st cell: phandle to syscon block -+ 2nd cell: register offset containing the trust zone mode setting -+ 3rd cell: register bitmask for the trust zone mode bit -+ -+Optional properties: -+- interrupt-parent: phandle to the interrupt controller node. -+- interrupts: Should contain the watchdog interrupt -+- interrupt-names: Must be "wdg" -+- wakeup-source: Flag indicating whether remoteproc can wake up the system by -+ the watchdog interrupt. Only meaningful if the "interrupts" -+ property is defined. -+- mboxes: List of phandle and mailbox channel specifiers: -+ - a channel (a) used to communicate through virtqueues with the -+ remote proc. -+ Bi-directional channel: -+ - from local to remote = send message -+ - from remote to local = send message ack -+ - a channel (b) working the opposite direction of channel (a) -+ - a channel (c) used by the local proc to notify the remote proc -+ that it is about to be shut down. -+ Mono-directional channel: -+ - from local to remote, where ACK from the remote means -+ that it is ready for shutdown -+- mbox-names: This property is required if the mboxes property is used. -+ - must be "vq0" for channel (a) -+ - must be "vq1" for channel (b) -+ - must be "shutdown" for channel (c) -+- memory-region: phandle to the reserved memory node to be associated with the -+ remoteproc device. -+- st,syscfg-pdds: Reference to the system configuration controlling the remote -+ processor deep sleep setting -+ 1st cell: phandle to syscon block -+ 2nd cell: register offset containing the deep sleep setting -+ 3rd cell: register bitmask for the deep sleep bit -+- st,syscfg-rsc-tbl: Reference to the system configuration controlling the -+ resource table address loaded by the bootloader -+ 1st cell: phandle to syscon block -+ 2nd cell: register offset containing the resource table address -+ 3rd cell: register bitmask for the resource table address -+- auto_boot: If defined, when remoteproc is probed, it looks for a default -+ firmware and if it finds some, it loads the firmware and starts -+ the remote processor. -+- recovery: If defined, remoteproc enables the crash recovery process. -+- early-booted: If defined, when remoteproc tries to boot a firmware, it -+ considers that the remote processor is already running and -+ attaches to this hardware state and updates accordingly (state, -+ resources, ...) -+- rsc-address: Resource table address of the early-booted firmware. Meaningful -+ only if 'early-booted' is defined. -+- rsc-size: Resource table size of the early-booted firmware. Meaningful -+ only if 'early-booted' is defined. -+ -+Example: -+ m4_rproc: m4 { -+ compatible = "st,stm32mp1-rproc"; -+ reg = <0x38000000 0x10000>, -+ <0x10000000 0x40000>; -+ reg-names = "retram", "mcusram"; -+ resets = <&rcc MCU_R>; -+ reset-names = "mcu_rst"; -+ st,syscfg-holdboot = <&rcc 0x10C 0x1>; -+ st,syscfg-tz = <&rcc 0x000 0x1>; -+ }; -diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -index 130ca5b..bab0df8 100644 ---- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -@@ -21,9 +21,14 @@ Required properties: - domain (RTC registers) write protection. - It is required on stm32(f4/f7/h7). - --Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): -+Optional properties: -+* to override default rtc_ck parent clock on stm32(f4/f7/h7): - - assigned-clocks: reference to the rtc_ck clock entry. - - assigned-clock-parents: phandle of the new parent clock of rtc_ck. -+* to select and enable RTC Low Speed Clock Output on stm32mp1: -+- st,lsco: defines the RTC output on which RTC Low-Speed Clock is Output. The -+ valid output values are defined in . -+- pinctrl state named "default" may be defined to reserve pin for RTC output. - - Example: - -@@ -58,4 +63,7 @@ Example: - clock-names = "pclk", "rtc_ck"; - interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, - <&exti 19 1>; -+ st,lsco = ; -+ pinctrl-0 = <&rtc_out2_rmp_pins_a>; -+ pinctrl-names = "default"; - }; -diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -index 9d3efed..08b4990 100644 ---- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -@@ -10,15 +10,49 @@ Required properties: - - 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: --- pinctrl: The reference on the pins configuration -+- 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 { -@@ -26,8 +60,11 @@ usart4: serial@40004c00 { - reg = <0x40004c00 0x400>; - interrupts = <52>; - clocks = <&clk_pclk1>; -- pinctrl-names = "default"; -+ 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 { -diff --git a/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt -new file mode 100644 -index 0000000..e2bd82f ---- /dev/null -+++ b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt -@@ -0,0 +1,39 @@ -+STM32 - STM32MP1- HDP Pin configuration for STM32MP1 -+======================================================= -+ -+The Hardware Debug Port (HDP) allows the observation of internal signals. By using multiplexers, -+up to 16 signals for each of 8-bit output can be observed. -+ -+Required Properties: -+ -+ - compatible: Must be "st,stm32mp1-hdp" -+ - muxing-hdp: Indicates for each HDP pins selected which HDP output among the 16 available signals you want -+ -+For each HDP pins you can select one of 16 signals which will be described in file : include/dt-bindings/soc/stm32-hdp.h -+ -+Example -+------- -+ -+In common dtsi file: -+ -+hdp: hdp@5002a000 { -+ compatible = "st,stm32mp1-hdp"; -+ reg = <0x5002a000 0x400>; -+ clocks = <&rcc HDP>; -+ clock-names = "hdp"; -+}; -+ -+In board-specific file: -+ -+In this example I've selected HDP0, HDP6 and HDP7, and for HDP0 the output signal is HDP0_GPOVAL_0, -+for HDP6 is HDP6_GPOVAL_6, and for HDP7 is HDP7_GPOVAL_7. -+ -+&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>; -+ -+ muxing-hdp = <(STM32_HDP(0, HDP0_GPOVAL_0) | -+ STM32_HDP(6, HDP6_GPOVAL_6) | -+ STM32_HDP(7, HDP7_GPOVAL_7))>; -+}; -diff --git a/Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt b/Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt -new file mode 100644 -index 0000000..bfc038b ---- /dev/null -+++ b/Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt -@@ -0,0 +1,47 @@ -+* STMicroelectronics Quad Serial Peripheral Interface(QSPI) -+ -+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 (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 properties: -+- spi-rx-bus-width: see ./spi-bus.txt for the description -+- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, -+Documentation/devicetree/bindings/dma/dma.txt. -+- dma-names: DMA request names should include "tx" and "rx" if present. -+ -+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 { -+ compatible = "jedec,spi-nor"; -+ reg = <0>; -+ spi-rx-bus-width = <4>; -+ spi-max-frequency = <108000000>; -+ ... -+ }; -+}; -diff --git a/Documentation/devicetree/bindings/thermal/stm32-thermal.txt b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt -new file mode 100644 -index 0000000..a45e1e1 ---- /dev/null -+++ b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt -@@ -0,0 +1,56 @@ -+Binding for Thermal Sensor for STMicroelectronics STM32 series of SoCs. -+ -+On STM32 SoCs, the Digital Temperature Sensor (DTS) is in charge of managing an -+analog block which delivers a frequency depending on the internal SoC's -+temperature. By using a reference frequency, DTS is able to provide a sample -+number which can be translated into a temperature by the user. -+ -+Required parameters: -+------------------- -+ -+compatible: Should be "st,stm32-thermal" -+reg: This should be the physical base address and length of the -+ sensor's registers. -+clocks: Phandle of the clock used by the thermal sensor. -+ See: Documentation/devicetree/bindings/clock/clock-bindings.txt -+clock-names: Should be "pclk" for register access clock and reference clock. -+ See: Documentation/devicetree/bindings/resource-names.txt -+#thermal-sensor-cells: Should be 0. See ./thermal.txt for a description. -+interrupts: Standard way to define interrupt number. -+ -+Example: -+ -+ thermal-zones { -+ cpu_thermal: cpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ -+ thermal-sensors = <&thermal>; -+ -+ trips { -+ cpu_alert1: cpu-alert1 { -+ temperature = <85000>; -+ hysteresis = <2000>; -+ type = "passive"; -+ }; -+ -+ cpu-crit: cpu-crit { -+ temperature = <120000>; -+ hysteresis = <2000>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ }; -+ }; -+ }; -+ -+ thermal: thermal@50028000 { -+ compatible = "st,stm32-thermal"; -+ reg = <0x50028000 0x100>; -+ clocks = <&rcc TMPSENS>; -+ clock-names = "pclk"; -+ #thermal-sensor-cells = <0>; -+ interrupts = ; -+ }; -diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt -index 46da5f1..0ae7711 100644 ---- a/Documentation/devicetree/bindings/usb/dwc2.txt -+++ b/Documentation/devicetree/bindings/usb/dwc2.txt -@@ -21,6 +21,9 @@ Required properties: - configured in HS mode; - - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs - configured in HS mode; -+ - "st,stm32mp1-fsotg": The DWC2 USB controller instance in STM32MP1 SoCs, -+ configured in FS mode (using dedicated FS transceiver). -+ - "st,stm32mp1-hsotg": The DWC2 USB controller instance in STM32MP1 SoCs; - - reg : Should contain 1 register range (address and length) - - interrupts : Should contain 1 interrupt - - clocks: clock provider specifier -@@ -36,6 +39,16 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - - g-rx-fifo-size: size of rx fifo size in gadget mode. - - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. - - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. -+- vbus-supply: in Host mode, external VBUS charge pump, when drvvbus signal -+ doesn't drive it. -+- usb33d-supply: external VBUS and ID sensing comparators supply, in order to -+ perform OTG operation, used on STM32MP1 SoCs. -+- extcon: external connector for vbus and id pin changes detection to -+ dynamically force A- or B-peripheral session. -+- wakeup-source: bool flag to indicate this device has wakeup capabilities -+- interrupt-names, if optional wake-up interrupt is used, should be: -+ - "event": the name for the interrupt line of the USB DWC2 instance -+ - "wakeup" the name for the optional wake-up interrupt - - Deprecated properties: - - g-use-dma: gadget DMA mode is automatically detected -diff --git a/Documentation/devicetree/bindings/usb/st,typec-stusb.txt b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -new file mode 100644 -index 0000000..67004b0 ---- /dev/null -+++ b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -@@ -0,0 +1,40 @@ -+STMicroelectronics STUSB Type-C Controller family -+ -+Required properties: -+ - compatible: should be "st,stusb1600". -+ - reg: I2C slave address of the device. -+ -+Optional properties: -+ - vdd-supply: main power supply [4.1V;22V]. -+ - vsys-supply: low power supply [3.0V;5.5V]. -+ - vconn-supply: power supply [2.7;5.5V] used to supply VConn on CC pin in -+ source or dual power role. -+ - interrupts: interrupt specifier triggered by ALERT# signal. -+ Please refer to ../interrupt-controller/interrupt.txt -+ - pinctrl state named "default" may be defined to configure pin for #ALERT -+ signal -+ -+USB-C connector attached to STUSB Type-C port controller can be described in -+an optional connector sub-node. Refer to ../connector/usb-connector.txt. -+ -+Example : -+ -+ typec: stusb1600@28 { -+ compatible = "st,stusb1600"; -+ reg = <0x28>; -+ vdd-supply = <&vbus_drd>; -+ vsys-supply = <&vdd_usb>; -+ interrupts = <11 IRQ_TYPE_EDGE_FALLING>; -+ interrupt-parent = <&gpioi>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&stusb1600_pins_a>; -+ -+ usb_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ power-role = "dual"; -+ power-opmode = "1.5A"; -+ data-role = "dual"; -+ }; -+ }; -+ -diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt -index 0f1b753..6e91f08 100644 ---- a/Documentation/devicetree/bindings/usb/usb-ehci.txt -+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt -@@ -18,6 +18,11 @@ Optional properties: - - clocks : a list of phandle + clock specifier pairs - - phys : see usb-hcd.txt in the current directory - - resets : phandle + reset specifier pair -+ - vbus-supply : phandle of regulator supplying vbus -+ - wakeup-source: bool flag to indicate this device has wakeup capabilities -+ - interrupt-names, if optional wake-up interrupt is used, should be: -+ - "event": the name for the interrupt line of the USB EHCI instance -+ - "wakeup" the name for the optional wake-up interrupt - - additionally the properties from usb-hcd.txt (in the current directory) are - supported. -diff --git a/Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt b/Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt -new file mode 100644 -index 0000000..7cc1407 ---- /dev/null -+++ b/Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt -@@ -0,0 +1,11 @@ -+STMicroelectronics STPMIC1 Watchdog -+ -+Required properties: -+ -+- compatible : should be "st,stpmic1-wdt" -+ -+Example: -+ -+watchdog { -+ compatible = "st,stpmic1-wdt"; -+}; -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index b5bd3de..5665290 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -922,8 +922,14 @@ dtb-$(CONFIG_ARCH_STM32) += \ - stm32746g-eval.dtb \ - stm32h743i-eval.dtb \ - stm32h743i-disco.dtb \ -+ stm32mp157a-dk1.dtb \ -+ stm32mp157c-dk2.dtb \ -+ stm32mp157c-dk2-a7-examples.dtb \ -+ stm32mp157c-dk2-m4-examples.dtb \ - stm32mp157c-ed1.dtb \ -- stm32mp157c-ev1.dtb -+ stm32mp157c-ev1.dtb \ -+ stm32mp157c-ev1-a7-examples.dtb \ -+ stm32mp157c-ev1-m4-examples.dtb - dtb-$(CONFIG_MACH_SUN4I) += \ - sun4i-a10-a1000.dtb \ - sun4i-a10-ba10-tvbox.dtb \ -diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -index c485127..dd796ec 100644 ---- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -+++ b/arch/arm/boot/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 { -@@ -157,6 +169,119 @@ - }; - }; - -+ 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 = <0>; -+ }; -+ }; -+ -+ 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 */ -@@ -166,13 +291,18 @@ - , /* ETH_RGMII_TXD2 */ - , /* ETH_RGMII_TXD3 */ - , /* ETH_RGMII_TX_CTL */ -- , /* ETH_MDIO */ - ; /* ETH_MDC */ - bias-disable; - drive-push-pull; -- slew-rate = <3>; -+ 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 */ -@@ -203,6 +333,95 @@ - }; - }; - -+ 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 */ -+ }; -+ }; -+ -+ 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 */ -+ }; -+ }; -+ -+ 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 */ -+ }; -+ }; -+ - i2c1_pins_a: i2c1-0 { - pins { - pinmux = , /* I2C1_SCL */ -@@ -213,6 +432,13 @@ - }; - }; - -+ i2c1_pins_sleep_a: i2c1-1 { -+ pins { -+ pinmux = , /* I2C1_SCL */ -+ ; /* I2C1_SDA */ -+ }; -+ }; -+ - i2c2_pins_a: i2c2-0 { - pins { - pinmux = , /* I2C2_SCL */ -@@ -223,6 +449,13 @@ - }; - }; - -+ i2c2_pins_sleep_a: i2c2-1 { -+ pins { -+ pinmux = , /* I2C2_SCL */ -+ ; /* I2C2_SDA */ -+ }; -+ }; -+ - i2c5_pins_a: i2c5-0 { - pins { - pinmux = , /* I2C5_SCL */ -@@ -233,10 +466,175 @@ - }; - }; - -+ 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 = <1>; -+ slew-rate = <0>; - drive-push-pull; - bias-disable; - }; -@@ -246,6 +644,32 @@ - }; - }; - -+ 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 */ -@@ -255,6 +679,74 @@ - }; - }; - -+ 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 */ -@@ -264,6 +756,12 @@ - }; - }; - -+ pwm8_sleep_pins_a: pwm8-sleep-0 { -+ pins { -+ pinmux = ; /* TIM8_CH4 */ -+ }; -+ }; -+ - pwm12_pins_a: pwm12-0 { - pins { - pinmux = ; /* TIM12_CH1 */ -@@ -273,12 +771,9 @@ - }; - }; - -- qspi_clk_pins_a: qspi-clk-0 { -+ pwm12_sleep_pins_a: pwm12-sleep-0 { - pins { -- pinmux = ; /* QSPI_CLK */ -- bias-disable; -- drive-push-pull; -- slew-rate = <3>; -+ pinmux = ; /* TIM12_CH1 */ - }; - }; - -@@ -290,13 +785,23 @@ - ; /* QSPI_BK1_IO3 */ - 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>; -+ 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 */ - }; - }; - -@@ -308,20 +813,440 @@ - ; /* QSPI_BK2_IO3 */ - 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>; -+ slew-rate = <1>; - }; - }; - -- uart4_pins_a: uart4-0 { -- pins1 { -- pinmux = ; /* UART4_TX */ -- bias-disable; -+ 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; -+ }; -+ }; -+ -+ sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { -+ pins { -+ pinmux = , /* SDMMC1_D0 */ -+ , /* SDMMC1_D1 */ -+ , /* SDMMC1_D2 */ -+ , /* SDMMC1_D3 */ -+ , /* SDMMC1_CK */ -+ ; /* SDMMC1_CMD */ -+ }; -+ }; -+ -+ 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 = , /* 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; -+ bias-pull-up; -+ }; -+ }; -+ -+ sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 { -+ pins { -+ pinmux = , /* SDMMC2_D0 */ -+ , /* SDMMC2_D1 */ -+ , /* SDMMC2_D2 */ -+ , /* SDMMC2_D3 */ -+ , /* SDMMC2_CK */ -+ ; /* SDMMC2_CMD */ -+ }; -+ }; -+ -+ 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 */ -+ , /* SDMMC2_D5 */ -+ , /* SDMMC2_D6 */ -+ ; /* SDMMC2_D7 */ -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-pull-up; -+ }; -+ }; -+ -+ sdmmc2_d47_sleep_pins_a: sdmmc2-d47-sleep-0 { -+ pins { -+ 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; -+ bias-pull-up; -+ }; -+ pins2 { -+ pinmux = ; /* SDMMC3_CK */ -+ slew-rate = <2>; -+ drive-push-pull; -+ bias-pull-up; -+ }; -+ }; -+ -+ 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; -+ 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; -+ }; -+ }; -+ -+ sdmmc3_b4_sleep_pins_a: sdmmc3-b4-sleep-0 { -+ pins { -+ pinmux = , /* SDMMC3_D0 */ -+ , /* SDMMC3_D1 */ -+ , /* SDMMC3_D2 */ -+ , /* SDMMC3_D3 */ -+ , /* SDMMC3_CK */ -+ ; /* SDMMC3_CMD */ -+ }; -+ }; -+ -+ spdifrx_pins_a: spdifrx-0 { -+ pins { -+ pinmux = ; /* SPDIF_IN1 */ -+ bias-disable; -+ }; -+ }; -+ -+ spdifrx_sleep_pins_a: spdifrx-1 { -+ pins { -+ pinmux = ; /* SPDIF_IN1 */ -+ }; -+ }; -+ -+ spi4_pins_a: spi4-0 { -+ pins1 { -+ pinmux = , /* SPI4_SCK */ -+ ; /* SPI4_MOSI */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <1>; -+ }; -+ -+ pins2 { -+ pinmux = ; /* SPI4_MISO */ -+ bias-disable; -+ }; -+ }; -+ -+ spi4_sleep_pins_a: spi4-sleep-0 { -+ pins { -+ pinmux = , /* SPI4_SCK */ -+ , /* SPI4_MISO */ -+ ; /* SPI4_MOSI */ -+ }; -+ }; -+ -+ spi5_pins_a: spi5-0 { -+ pins1 { -+ pinmux = , /* SPI5_SCK */ -+ ; /* SPI5_MOSI */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <1>; -+ }; -+ -+ pins2 { -+ pinmux = ; /* SPI5_MISO */ -+ bias-disable; -+ }; -+ }; -+ -+ spi5_sleep_pins_a: spi5-sleep-0 { -+ pins { -+ pinmux = , /* SPI5_SCK */ -+ , /* SPI5_MISO */ -+ ; /* SPI5_MOSI */ -+ }; -+ }; -+ -+ stusb1600_pins_a: stusb1600-0 { -+ pins { -+ pinmux = ; -+ bias-pull-up; -+ }; -+ }; -+ -+ uart4_pins_a: uart4-0 { -+ pins1 { -+ pinmux = ; /* UART4_TX */ -+ bias-disable; - drive-push-pull; - slew-rate = <0>; - }; -@@ -330,6 +1255,174 @@ - bias-disable; - }; - }; -+ -+ uart4_idle_pins_a: uart4-idle-0 { -+ pins1 { -+ pinmux = ; /* UART4_TX */ -+ }; -+ pins2 { -+ pinmux = ; /* UART4_RX */ -+ bias-disable; -+ }; -+ }; -+ -+ uart4_sleep_pins_a: uart4-sleep-0 { -+ pins { -+ pinmux = , /* UART4_TX */ -+ ; /* UART4_RX */ -+ }; -+ }; -+ -+ 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 */ -+ ; /* USART2_RTS */ -+ bias-disable; -+ drive-push-pull; -+ 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; -+ }; -+ }; -+ -+ usart2_sleep_pins_a: usart2-sleep-0 { -+ pins { -+ 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; -+ 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; -+ }; -+ }; -+ -+ usart3_sleep_pins_a: usart3-sleep-0 { -+ pins { -+ pinmux = , /* USART3_TX */ -+ , /* USART3_RTS */ -+ , /* USART3_CTS_NSS */ -+ ; /* USART3_RX */ -+ }; -+ }; -+ -+ usart3_pins_b: usart3-1 { -+ pins1 { -+ pinmux = , /* USART3_TX */ -+ ; /* USART3_RTS */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <0>; -+ }; -+ pins2 { -+ 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 { -@@ -340,6 +1433,7 @@ - pins-are-numbered; - interrupt-parent = <&exti>; - st,syscfg = <&exti 0x60 0xff>; -+ hwlocks = <&hsem 0>; - - gpioz: gpio@54004000 { - gpio-controller; -@@ -350,8 +1444,7 @@ - clocks = <&rcc GPIOZ>; - st,bank-name = "GPIOZ"; - st,bank-ioport = <11>; -- ngpios = <8>; -- gpio-ranges = <&pinctrl_z 0 400 8>; -+ status = "disabled"; - }; - - i2c4_pins_a: i2c4-0 { -@@ -364,6 +1457,13 @@ - }; - }; - -+ i2c4_pins_sleep_a: i2c4-1 { -+ pins { -+ pinmux = , /* I2C4_SCL */ -+ ; /* I2C4_SDA */ -+ }; -+ }; -+ - spi1_pins_a: spi1-0 { - pins1 { - pinmux = , /* SPI1_SCK */ -@@ -378,6 +1478,14 @@ - bias-disable; - }; - }; -+ -+ spi1_sleep_pins_a: spi1-sleep-0 { -+ pins { -+ pinmux = , /* SPI1_SCK */ -+ , /* SPI1_MISO */ -+ ; /* SPI1_MOSI */ -+ }; -+ }; - }; - }; - }; -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -new file mode 100644 -index 0000000..9ec45de ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -0,0 +1,767 @@ -+// 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 "stm32mp157c-m4-srm.dtsi" -+#include -+#include -+ -+/ { -+ model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; -+ compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; -+ -+ aliases { -+ ethernet0 = ðernet0; -+ serial0 = &uart4; -+ serial1 = &usart3; -+ serial2 = &uart7; -+ }; -+ -+ 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@d4000000 { -+ reg = <0xd4000000 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_ain_pins_a>, <&adc12_usb_pwr_pins_a>; -+ vdd-supply = <&vdd>; -+ vdda-supply = <&vdd>; -+ vref-supply = <&vrefbuf>; -+ status = "disabled"; -+ 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>; -+ /* AIN connector, USB Type-C CC1 & CC2 */ -+ st,adc-channels = <0 1 6 13 18 19>; -+ status = "okay"; -+ }; -+ adc2: adc@100 { -+ /* 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"; -+ }; -+ adc_temp: temp { -+ status = "okay"; -+ }; -+}; -+ -+&cec { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&cec_pins_b>; -+ pinctrl-1 = <&cec_pins_sleep_b>; -+ status = "okay"; -+}; -+ -+&cpu0{ -+ cpu-supply = <&vddcore>; -+}; -+ -+&cpu1{ -+ cpu-supply = <&vddcore>; -+}; -+ -+&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-id"; -+ 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>; -+ 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>; -+ clock-frequency = <400000>; -+ status = "okay"; -+ /delete-property/dmas; -+ /delete-property/dma-names; -+ -+ 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 { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ power-role = "dual"; -+ power-opmode = "default"; -+ }; -+ }; -+ -+ pmic: stpmic@33 { -+ compatible = "st,stpmic1"; -+ reg = <0x33>; -+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ status = "okay"; -+ wakeup-source; -+ -+ regulators { -+ compatible = "st,stpmic1-regulators"; -+ -+ ldo1-supply = <&v3v3>; -+ ldo3-supply = <&vdd_ddr>; -+ ldo6-supply = <&v3v3>; -+ pwr_sw1-supply = <&bst_out>; -+ pwr_sw2-supply = <&bst_out>; -+ -+ vddcore: buck1 { -+ regulator-name = "vddcore"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-always-on; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ vdd_ddr: buck2 { -+ regulator-name = "vdd_ddr"; -+ regulator-min-microvolt = <1350000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-always-on; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ vdd: buck3 { -+ regulator-name = "vdd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ st,mask-reset; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ v3v3: buck4 { -+ regulator-name = "v3v3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-over-current-protection; -+ regulator-initial-mode = <0>; -+ }; -+ -+ v1v8_audio: ldo1 { -+ regulator-name = "v1v8_audio"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ interrupts = ; -+ -+ }; -+ -+ v3v3_hdmi: ldo2 { -+ regulator-name = "v3v3_hdmi"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ interrupts = ; -+ -+ }; -+ -+ vtt_ddr: ldo3 { -+ regulator-name = "vtt_ddr"; -+ regulator-min-microvolt = <500000>; -+ regulator-max-microvolt = <750000>; -+ regulator-always-on; -+ regulator-over-current-protection; -+ }; -+ -+ vdd_usb: ldo4 { -+ regulator-name = "vdd_usb"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ interrupts = ; -+ }; -+ -+ vdda: ldo5 { -+ regulator-name = "vdda"; -+ regulator-min-microvolt = <2900000>; -+ regulator-max-microvolt = <2900000>; -+ interrupts = ; -+ regulator-boot-on; -+ }; -+ -+ v1v2_hdmi: ldo6 { -+ regulator-name = "v1v2_hdmi"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1200000>; -+ regulator-always-on; -+ interrupts = ; -+ -+ }; -+ -+ vref_ddr: vref_ddr { -+ regulator-name = "vref_ddr"; -+ regulator-always-on; -+ regulator-over-current-protection; -+ }; -+ -+ bst_out: boost { -+ regulator-name = "bst_out"; -+ interrupts = ; -+ }; -+ -+ vbus_otg: pwr_sw1 { -+ regulator-name = "vbus_otg"; -+ interrupts = ; -+ }; -+ -+ vbus_sw: pwr_sw2 { -+ regulator-name = "vbus_sw"; -+ interrupts = ; -+ regulator-active-discharge = <1>; -+ }; -+ }; -+ -+ onkey { -+ compatible = "st,stpmic1-onkey"; -+ interrupts = , ; -+ interrupt-names = "onkey-falling", "onkey-rising"; -+ power-off-time-sec = <10>; -+ status = "okay"; -+ }; -+ -+ watchdog { -+ compatible = "st,stpmic1-wdt"; -+ status = "disabled"; -+ }; -+ }; -+}; -+ -+&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"; -+ 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 { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <<dc_pins_a>; -+ pinctrl-1 = <<dc_pins_sleep_a>; -+ 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"; -+ wakeup-source; -+ recovery; -+ status = "okay"; -+}; -+ -+&pwr { -+ pwr-regulators { -+ vdd-supply = <&vdd>; -+ vdd_3v3_usbfs-supply = <&vdd_usb>; -+ }; -+}; -+ -+&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"; -+}; -+ -+&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>; -+ 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; -+ status = "disabled"; -+ 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; -+ status = "disabled"; -+ 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; -+ status = "disabled"; -+ 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; -+ status = "disabled"; -+ 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; -+ status = "disabled"; -+ 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>; -+ /delete-property/dmas; -+ /delete-property/dma-names; -+ 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>; -+ /delete-property/dmas; -+ /delete-property/dma-names; -+ status = "disabled"; -+}; -+ -+&usart3 { -+ pinctrl-names = "default", "sleep", "idle"; -+ pinctrl-0 = <&usart3_pins_b>; -+ pinctrl-1 = <&usart3_sleep_pins_b>; -+ pinctrl-2 = <&usart3_idle_pins_b>; -+ st,hw-flow-ctrl; -+ status = "disabled"; -+}; -+ -+&usbh_ehci { -+ phys = <&usbphyc_port0>; -+ phy-names = "usb"; -+ status = "okay"; -+}; -+ -+&usbotg_hs { -+ extcon = <&typec>; -+ 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/boot/dts/stm32mp157c-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts -new file mode 100644 -index 0000000..9c89733 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts -@@ -0,0 +1,14 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -+/* -+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ */ -+ -+/dts-v1/; -+ -+#include "stm32mp157c-dk2.dts" -+ -+/ { -+ model = "STMicroelectronics STM32MP157C-DK2 configured to run Linux A7 examples"; -+ compatible = "st,stm32mp157c-dk2-a7-examples", "st,stm32mp157c-dk2", "st,stm32mp157"; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts -new file mode 100644 -index 0000000..14eac74 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts -@@ -0,0 +1,129 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -+/* -+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ */ -+ -+/dts-v1/; -+ -+#include "stm32mp157c-dk2.dts" -+ -+/ { -+ model = "STMicroelectronics STM32MP157C-DK2 configured to run M4 examples"; -+ compatible = "st,stm32mp157c-dk2-m4-examples", "st,stm32mp157c-dk2", "st,stm32mp157"; -+}; -+ -+&adc { -+ status = "disabled"; -+}; -+ -+&dac { -+ status = "disabled"; -+}; -+ -+&dma2 { -+ status = "disabled"; -+}; -+ -+&dmamux1 { -+ dma-masters = <&dma1>; -+ dma-channels = <8>; -+}; -+ -+&m4_adc { -+ vref-supply = <&vrefbuf>; -+ status = "okay"; -+}; -+ -+&m4_dac { -+ vref-supply = <&vrefbuf>; -+ status = "okay"; -+}; -+ -+&m4_dma2 { -+ status = "okay"; -+}; -+ -+&m4_crc2 { -+ status = "okay"; -+}; -+ -+&m4_cryp2 { -+ status = "okay"; -+}; -+ -+&m4_hash2 { -+ status = "okay"; -+}; -+ -+&m4_i2c5 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_i2c5_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_rng2 { -+ status = "okay"; -+}; -+ -+&m4_rproc { -+ m4_system_resources { -+ status = "okay"; -+ -+ button { -+ compatible = "rproc-srm-dev"; -+ interrupt-parent = <&gpioa>; -+ interrupts = <14 2>; -+ interrupt-names = "irq"; -+ status = "okay"; -+ }; -+ -+ m4_led: m4_led { -+ compatible = "rproc-srm-dev"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_leds_orange_pins>; -+ status = "okay"; -+ }; -+ }; -+}; -+ -+&m4_spi4 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_spi4_pins_a>; -+ status = "okay"; -+}; -+ -+ -+&m4_timers2 { -+ status = "okay"; -+}; -+ -+&m4_timers1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_pwm1_pins_a_ch1>; -+ status = "okay"; -+}; -+ -+&m4_uart7 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_uart7_pins_a>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ m4_leds_orange_pins: m4-leds-orange-0 { -+ pins { -+ pinmux = ; -+ }; -+ }; -+ -+ m4_pwm1_pins_a_ch1: m4-pwm1-0-ch1 { -+ pins { -+ pinmux = ; -+ }; -+ }; -+}; -+ -+&timers1 { -+ status = "disabled"; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -new file mode 100644 -index 0000000..5523dc3 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -0,0 +1,147 @@ -+// 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 { -+ serial3 = &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: panel@0 { -+ compatible = "orisetech,otm8009a"; -+ reg = <0>; -+ reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; -+ power-supply = <&v3v3>; -+ 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>; -+ panel = <&panel>; -+ 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>; -+ panel = <&panel>; -+ 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 { -+ arm,primecell-periphid = <0x10153180>; -+ pinctrl-names = "default", "opendrain", "sleep"; -+ 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; -+ 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 { -+ shutdown-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <3000000>; -+ }; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index f77bea4..f5e685d 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -6,7 +6,9 @@ - /dts-v1/; - - #include "stm32mp157c.dtsi" --#include "stm32mp157-pinctrl.dtsi" -+#include "stm32mp157caa-pinctrl.dtsi" -+#include "stm32mp157c-m4-srm.dtsi" -+#include - - / { - model = "STMicroelectronics STM32MP157C eval daughter"; -@@ -20,40 +22,309 @@ - 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@e8000000 { -+ reg = <0xe8000000 0x8000000>; -+ no-map; -+ }; -+ }; -+ - aliases { - serial0 = &uart4; - }; - -- reg11: reg11 { -- compatible = "regulator-fixed"; -- regulator-name = "reg11"; -- regulator-min-microvolt = <1100000>; -- regulator-max-microvolt = <1100000>; -- regulator-always-on; -+ 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; -+ }; - }; - -- reg18: reg18 { -- compatible = "regulator-fixed"; -- regulator-name = "reg18"; -+ 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"; - regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <1800000>; -+ regulator-max-microvolt = <2900000>; -+ regulator-type = "voltage"; - regulator-always-on; -+ -+ gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; -+ gpios-states = <0>; -+ states = <1800000 0x1 2900000 0x0>; - }; -+}; - -- vdd_usb: vdd-usb { -- compatible = "regulator-fixed"; -- regulator-name = "vdd_usb"; -- regulator-min-microvolt = <3300000>; -- regulator-max-microvolt = <3300000>; -- regulator-always-on; -+&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"; - }; - }; - --&i2c4 { -+&cpu0{ -+ cpu-supply = <&vddcore>; -+}; -+ -+&cpu1{ -+ cpu-supply = <&vddcore>; -+}; -+ -+&dac { - pinctrl-names = "default"; -+ pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; -+ vref-supply = <&vdda>; -+ status = "okay"; -+ 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", "sleep"; - pinctrl-0 = <&i2c4_pins_a>; -+ 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; -+ -+ pmic: stpmic@33 { -+ compatible = "st,stpmic1"; -+ reg = <0x33>; -+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ status = "okay"; -+ wakeup-source; -+ -+ regulators { -+ compatible = "st,stpmic1-regulators"; -+ ldo1-supply = <&v3v3>; -+ ldo2-supply = <&v3v3>; -+ ldo3-supply = <&vdd_ddr>; -+ ldo5-supply = <&v3v3>; -+ ldo6-supply = <&v3v3>; -+ pwr_sw1-supply = <&bst_out>; -+ pwr_sw2-supply = <&bst_out>; -+ -+ vddcore: buck1 { -+ regulator-name = "vddcore"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-always-on; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ vdd_ddr: buck2 { -+ regulator-name = "vdd_ddr"; -+ regulator-min-microvolt = <1350000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-always-on; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ vdd: buck3 { -+ regulator-name = "vdd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ st,mask-reset; -+ regulator-initial-mode = <0>; -+ regulator-over-current-protection; -+ }; -+ -+ v3v3: buck4 { -+ regulator-name = "v3v3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-over-current-protection; -+ regulator-initial-mode = <0>; -+ }; -+ -+ vdda: ldo1 { -+ regulator-name = "vdda"; -+ regulator-min-microvolt = <2900000>; -+ regulator-max-microvolt = <2900000>; -+ interrupts = ; -+ }; -+ -+ v2v8: ldo2 { -+ regulator-name = "v2v8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ 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 = ; -+ }; -+ -+ vdd_sd: ldo5 { -+ regulator-name = "vdd_sd"; -+ regulator-min-microvolt = <2900000>; -+ regulator-max-microvolt = <2900000>; -+ interrupts = ; -+ regulator-boot-on; -+ }; -+ -+ v1v8: ldo6 { -+ regulator-name = "v1v8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ 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 = ; -+ }; -+ -+ vbus_sw: pwr_sw2 { -+ regulator-name = "vbus_sw"; -+ interrupts = ; -+ regulator-active-discharge = <1>; -+ }; -+ }; -+ -+ onkey { -+ compatible = "st,stpmic1-onkey"; -+ interrupts = , ; -+ interrupt-names = "onkey-falling", "onkey-rising"; -+ power-off-time-sec = <10>; -+ status = "okay"; -+ }; -+ -+ watchdog { -+ compatible = "st,stpmic1-wdt"; -+ status = "disabled"; -+ }; -+ }; -+}; -+ -+&ipcc { - status = "okay"; - }; - -@@ -62,6 +333,26 @@ - 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"; -+ wakeup-source; -+ recovery; -+ status = "okay"; -+}; -+ -+&pwr { -+ pwr-regulators { -+ vdd-supply = <&vdd>; -+ vdd_3v3_usbfs-supply = <&vdd_usb>; -+ }; -+}; -+ - &rng1 { - status = "okay"; - }; -@@ -70,27 +361,67 @@ - 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,sig-dir; -+ st,neg-edge; -+ st,use-ckin; -+ bus-width = <4>; -+ vmmc-supply = <&vdd_sd>; -+ vqmmc-supply = <&sd_switch>; -+ sd-uhs-sdr12; -+ sd-uhs-sdr25; -+ sd-uhs-sdr50; -+ sd-uhs-ddr50; -+ sd-uhs-sdr104; -+ status = "okay"; -+}; -+ -+&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,neg-edge; -+ bus-width = <8>; -+ vmmc-supply = <&v3v3>; -+ 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>; -+ /delete-property/dmas; -+ /delete-property/dma-names; - status = "okay"; - }; - --&usbphyc_port0 { -- phy-supply = <&vdd_usb>; -- vdda1v1-supply = <®11>; -- vdda1v8-supply = <®18>; -+&usbotg_hs { -+ 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/boot/dts/stm32mp157c-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts -new file mode 100644 -index 0000000..a927b00 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts -@@ -0,0 +1,33 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -+/* -+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ */ -+ -+/dts-v1/; -+ -+#include "stm32mp157c-ev1.dts" -+#include -+ -+/ { -+ model = "STMicroelectronics STM32MP157C-EV1 configured to run Linux A7 examples"; -+ compatible = "st,stm32mp157c-ev1-a7-examples", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; -+ -+ test_keys { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ autorepeat; -+ status = "okay"; -+ /* gpio needs vdd core in retention for wakeup */ -+ power-domains = <&pd_core_ret>; -+ -+ button@1 { -+ label = "PA13"; -+ linux,code = ; -+ interrupts-extended = <&gpioa 13 IRQ_TYPE_EDGE_FALLING>; -+ status = "okay"; -+ wakeup-source; -+ }; -+ }; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts -new file mode 100644 -index 0000000..8edcb4f ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts -@@ -0,0 +1,146 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -+/* -+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved -+ * Author: Alexandre Torgue for STMicroelectronics. -+ */ -+ -+/dts-v1/; -+ -+#include "stm32mp157c-ev1.dts" -+ -+/ { -+ model = "STMicroelectronics STM32MP157C-EV1 configured to run M4 examples"; -+ compatible = "st,stm32mp157c-ev1-m4-examples", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; -+}; -+ -+&adc { -+ status = "disabled"; -+}; -+ -+&dac { -+ status = "disabled"; -+}; -+ -+&dcmi { -+ status = "disabled"; -+}; -+ -+&dma2 { -+ status = "disabled"; -+}; -+ -+&dmamux1 { -+ dma-masters = <&dma1>; -+ dma-channels = <8>; -+}; -+ -+&fmc { -+ status = "disabled"; -+}; -+ -+&i2c5 { -+ status = "disabled"; -+}; -+ -+&m4_adc { -+ vref-supply = <&vdda>; -+ status = "okay"; -+}; -+ -+&m4_crc2 { -+ status = "okay"; -+}; -+ -+&m4_cryp2 { -+ status = "okay"; -+}; -+ -+&m4_dac { -+ vref-supply = <&vdda>; -+ status = "okay"; -+}; -+ -+&m4_dma2 { -+ status = "okay"; -+}; -+ -+&m4_hash2 { -+ status = "okay"; -+}; -+ -+&m4_i2c5 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_i2c5_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_qspi { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_qspi_clk_pins_a &m4_qspi_bk1_pins_a -+ &m4_qspi_bk2_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_rproc { -+ m4_system_resources { -+ status = "okay"; -+ -+ button { -+ compatible = "rproc-srm-dev"; -+ interrupt-parent = <&gpioa>; -+ interrupts = <14 2>; -+ interrupt-names = "irq"; -+ status = "okay"; -+ }; -+ -+ m4_led: m4_led { -+ compatible = "rproc-srm-dev"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_leds_orange_pins>; -+ status = "okay"; -+ }; -+ }; -+}; -+ -+&m4_rng2 { -+ status = "okay"; -+}; -+ -+&m4_spi1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_spi1_pins_a>; -+ status = "okay"; -+}; -+ -+ -+&m4_timers2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_pwm2_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_usart3 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_usart3_pins_a>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ m4_leds_orange_pins: m4-leds-orange-0 { -+ pins { -+ pinmux = ; -+ }; -+ }; -+}; -+ -+&qspi { -+ status = "disabled"; -+}; -+ -+&sai2b { -+ status = "disabled"; -+}; -+ -+&timers2 { -+ status = "disabled"; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index 063ee8a..7323f40 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ev1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -6,7 +6,8 @@ - /dts-v1/; - - #include "stm32mp157c-ed1.dts" --#include -+#include -+#include - - / { - model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -17,22 +18,287 @@ - }; - - aliases { -- serial0 = &uart4; -+ 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: 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 { -@@ -59,10 +325,11 @@ - }; - }; - -- panel-dsi@0 { -+ panel_dsi: panel-dsi@0 { - compatible = "raydium,rm68200"; - reg = <0>; - reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; -+ power-supply = <&v3v3>; - backlight = <&panel_backlight>; - status = "okay"; - -@@ -79,7 +346,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>; - -@@ -93,20 +360,167 @@ - }; - }; - -+&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"; -+ reg = <0x3c>; -+ clocks = <&clk_ext_camera>; -+ clock-names = "xclk"; -+ DOVDD-supply = <&v2v8>; -+ 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"; -+ -+ 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"; -+ bias-pull-down; -+ }; -+ -+ joystick_pins: joystick { -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; -+ bias-pull-down; -+ }; -+ }; -+ }; -+ -+ gt9147: goodix_ts@5d { -+ compatible = "goodix,gt9147"; -+ reg = <0x5d>; -+ panel = <&panel_dsi>; -+ 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>; -- status = "okay"; -+ /delete-property/dmas; -+ /delete-property/dma-names; - }; - - <dc { -@@ -124,20 +538,23 @@ - }; - - &m_can1 { -- pinctrl-names = "default"; -+ 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>; -@@ -146,6 +563,7 @@ - }; - - flash1: mx66l51235l@1 { -+ compatible = "jedec,spi-nor"; - reg = <1>; - spi-rx-bus-width = <4>; - spi-max-frequency = <108000000>; -@@ -154,17 +572,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_pins_a>; -+ status = "okay"; -+ -+ spdifrx_port: port { -+ spdifrx_endpoint: endpoint { -+ remote-endpoint = <&spdif_in_endpoint>; -+ }; -+ }; -+}; -+ - &spi1 { -- pinctrl-names = "default"; -+ 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 { -@@ -174,9 +685,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 { -@@ -186,9 +700,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 { -@@ -196,14 +713,25 @@ - }; - }; - -+&usart3 { -+ pinctrl-names = "default", "sleep", "idle"; -+ pinctrl-0 = <&usart3_pins_a>; -+ pinctrl-1 = <&usart3_sleep_pins_a>; -+ pinctrl-2 = <&usart3_idle_pins_a>; -+ st,hw-flow-ctrl; -+ status = "disabled"; -+}; -+ - &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; -+ vbus-supply = <&vbus_sw>; - status = "okay"; - }; - - &usbotg_hs { -- dr_mode = "peripheral"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usbotg_hs_pins_a>; - phys = <&usbphyc_port1 0>; - phy-names = "usb2-phy"; - status = "okay"; -@@ -212,3 +740,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/boot/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -new file mode 100644 -index 0000000..4d641a9 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -@@ -0,0 +1,961 @@ -+// 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>; -+ #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 FDCAN>, <&rcc FDCAN_K>; -+ clock-names = "hclk", "cclk"; -+ status = "disabled"; -+ }; -+ m4_m_can2: can@4400f000 { -+ compatible = "rproc-srm-dev"; -+ reg = <0x4400f000>, <0x44011000>; -+ clocks = <&rcc FDCAN>, <&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"; -+ }; -+ }; -+}; -+ -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index c50c36b..d56e0f9 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -5,6 +5,7 @@ - */ - #include - #include -+#include - #include - - / { -@@ -19,20 +20,50 @@ - compatible = "arm,cortex-a7"; - device_type = "cpu"; - reg = <0>; -+ 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>; -+ 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>; -+ }; -+ }; -+ -+ arm-pmu { -+ compatible = "arm,cortex-a7-pmu"; -+ interrupts = , -+ ; -+ interrupt-affinity = <&cpu0>, <&cpu1>; -+ interrupt-parent = <&intc>; -+ }; -+ - psci { -- compatible = "arm,psci"; -+ compatible = "arm,psci-1.0"; - method = "smc"; -- cpu_off = <0x84000002>; -- cpu_on = <0x84000003>; - }; - - intc: interrupt-controller@a0021000 { -@@ -50,6 +81,7 @@ - , - ; - interrupt-parent = <&intc>; -+ always-on; - }; - - clocks { -@@ -82,6 +114,87 @@ - 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 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "st,stm32mp157c-pd"; -+ -+ pd_core_ret: core-ret-power-domain@1 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <1>; -+ #power-domain-cells = <0>; -+ label = "CORE-RETENTION"; -+ -+ pd_core: core-power-domain@2 { -+ reg = <2>; -+ #power-domain-cells = <0>; -+ label = "CORE"; -+ }; -+ }; -+ }; -+ -+ thermal-zones { -+ cpu_thermal: cpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&dts>; -+ -+ trips { -+ 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 { -@@ -98,10 +211,17 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -119,10 +239,18 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -140,10 +268,16 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -161,10 +295,18 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -182,6 +324,8 @@ - reg = <0x40004000 0x400>; - clocks = <&rcc TIM6_K>; - clock-names = "int"; -+ dmas = <&dmamux1 69 0x400 0x5>; -+ dma-names = "up"; - status = "disabled"; - - timer@5 { -@@ -198,6 +342,8 @@ - reg = <0x40005000 0x400>; - clocks = <&rcc TIM7_K>; - clock-names = "int"; -+ dmas = <&dmamux1 70 0x400 0x5>; -+ dma-names = "up"; - status = "disabled"; - - timer@6 { -@@ -218,6 +364,7 @@ - - pwm { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -239,6 +386,7 @@ - - pwm { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -260,6 +408,7 @@ - - pwm { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -277,6 +426,7 @@ - reg = <0x40009000 0x400>; - clocks = <&rcc LPTIM1_K>; - clock-names = "mux"; -+ power-domains = <&pd_core>; - status = "disabled"; - - pwm { -@@ -305,8 +455,20 @@ - 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"; -+ }; -+ -+ 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"; - }; -@@ -319,93 +481,178 @@ - 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"; -+ }; -+ -+ 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>; -+ dmas = <&dmamux1 43 0x400 0x21>, -+ <&dmamux1 44 0x400 0x1>; -+ dma-names = "rx", "tx"; - 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>; -+ dmas = <&dmamux1 45 0x400 0x21>, -+ <&dmamux1 46 0x400 0x1>; -+ dma-names = "rx", "tx"; - 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>; -+ dmas = <&dmamux1 63 0x400 0x21>, -+ <&dmamux1 64 0x400 0x1>; -+ dma-names = "rx", "tx"; - 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>; -+ dmas = <&dmamux1 65 0x400 0x21>, -+ <&dmamux1 66 0x400 0x1>; -+ dma-names = "rx", "tx"; - 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 0x10>; - status = "disabled"; - }; - -@@ -413,8 +660,9 @@ - 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"; - }; - -@@ -445,16 +693,32 @@ - 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>; -+ dmas = <&dmamux1 79 0x400 0x21>, -+ <&dmamux1 80 0x400 0x1>; -+ dma-names = "rx", "tx"; - 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>; -+ dmas = <&dmamux1 81 0x400 0x21>, -+ <&dmamux1 82 0x400 0x1>; -+ dma-names = "rx", "tx"; - status = "disabled"; - }; - -@@ -465,10 +729,20 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -486,10 +760,20 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -503,8 +787,16 @@ - 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>; -+ dmas = <&dmamux1 71 0x400 0x21>, -+ <&dmamux1 72 0x400 0x1>; -+ dma-names = "rx", "tx"; - status = "disabled"; - }; - -@@ -516,8 +808,20 @@ - 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"; -+ }; -+ -+ 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"; - }; -@@ -530,9 +834,10 @@ - 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"; - }; - -@@ -543,10 +848,16 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -564,10 +875,14 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - timer@15 { -@@ -584,10 +899,14 @@ - 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 { - compatible = "st,stm32-pwm"; -+ #pwm-cells = <3>; - status = "disabled"; - }; - -@@ -606,12 +925,107 @@ - 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"; - }; - -+ 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>; -+ clocks = <&rcc SAI1_K>; -+ clock-names = "sai_ck"; -+ dmas = <&dmamux1 87 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai1b: audio-controller@4400a024 { -+ #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"; -+ }; -+ }; -+ -+ 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>; -+ clocks = <&rcc SAI2_K>; -+ clock-names = "sai_ck"; -+ dmas = <&dmamux1 89 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai2b: audio-controller@4400b024 { -+ #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"; -+ }; -+ }; -+ -+ 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>; -+ clocks = <&rcc SAI3_K>; -+ clock-names = "sai_ck"; -+ dmas = <&dmamux1 113 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai3b: audio-controller@4400c024 { -+ #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"; -+ }; -+ }; -+ - dfsdm: dfsdm@4400d000 { - compatible = "st,stm32mp1-dfsdm"; - reg = <0x4400d000 0x800>; -@@ -684,12 +1098,12 @@ - - m_can1: can@4400e000 { - compatible = "bosch,m_can"; -- reg = <0x4400e000 0x400>, <0x44011000 0x2800>; -+ reg = <0x4400e000 0x400>, <0x44011000 0x1400>; - reg-names = "m_can", "message_ram"; - 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"; -@@ -702,9 +1116,9 @@ - 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>; -+ bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; - status = "disabled"; - }; - -@@ -720,9 +1134,19 @@ - , - ; - clocks = <&rcc DMA1>; -+ resets = <&rcc DMA1_R>; - #dma-cells = <4>; - st,mem2mem; - dma-requests = <8>; -+ 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"; - }; - - dma2: dma@48001000 { -@@ -737,9 +1161,19 @@ - , - ; - clocks = <&rcc DMA2>; -+ resets = <&rcc DMA2_R>; - #dma-cells = <4>; - st,mem2mem; - dma-requests = <8>; -+ 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"; - }; - - dmamux1: dma-router@48002000 { -@@ -750,6 +1184,7 @@ - dma-masters = <&dma1 &dma2>; - dma-channels = <16>; - clocks = <&rcc DMAMUX>; -+ resets = <&rcc DMAMUX_R>; - }; - - adc: adc@48003000 { -@@ -760,6 +1195,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>; -@@ -771,7 +1210,7 @@ - reg = <0x0>; - interrupt-parent = <&adc>; - interrupts = <0>; -- dmas = <&dmamux1 9 0x400 0x01>; -+ dmas = <&dmamux1 9 0x400 0x05>; - dma-names = "rx"; - status = "disabled"; - }; -@@ -782,24 +1221,117 @@ - reg = <0x100>; - interrupt-parent = <&adc>; - interrupts = <1>; -- dmas = <&dmamux1 10 0x400 0x01>; -+ 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 = "arm,pl18x", "arm,primecell"; -+ arm,primecell-periphid = <0x00253180>; -+ reg = <0x48004000 0x400>, <0x48005000 0x400>; -+ interrupts = ; -+ interrupt-names = "cmd_irq"; -+ clocks = <&rcc SDMMC3_K>; -+ clock-names = "apb_pclk"; -+ resets = <&rcc SDMMC3_R>; -+ cap-sd-highspeed; -+ cap-mmc-highspeed; -+ max-frequency = <120000000>; -+ status = "disabled"; -+ }; -+ - usbotg_hs: usb-otg@49000000 { -- compatible = "snps,dwc2"; -+ compatible = "st,stm32mp1-hsotg", "snps,dwc2"; - reg = <0x49000000 0x10000>; - clocks = <&rcc USBO_K>; - 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"; -+ }; -+ -+ 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 0x1d>; -+ dma-names = "tx"; - status = "disabled"; - }; - -@@ -808,6 +1340,47 @@ - reg = <0x50000000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; -+ interrupts = ; -+ }; -+ -+ pwr: pwr@50001000 { -+ compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd"; -+ reg = <0x50001000 0x400>; -+ -+ interrupts = ; -+ -+ 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>; -+ -+ 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>; -+ }; -+ -+ usb33: usb33 { -+ regulator-name = "usb33"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ }; -+ }; - }; - - exti: interrupt-controller@5000d000 { -@@ -815,11 +1388,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: syscon@50020000 { - compatible = "st,stm32mp157-syscfg", "syscon"; - reg = <0x50020000 0x400>; -+ clocks = <&rcc SYSCFG>; - }; - - lptimer2: timer@50021000 { -@@ -829,6 +1415,7 @@ - reg = <0x50021000 0x400>; - clocks = <&rcc LPTIM2_K>; - clock-names = "mux"; -+ power-domains = <&pd_core>; - status = "disabled"; - - pwm { -@@ -856,6 +1443,7 @@ - reg = <0x50022000 0x400>; - clocks = <&rcc LPTIM3_K>; - clock-names = "mux"; -+ power-domains = <&pd_core>; - status = "disabled"; - - pwm { -@@ -876,6 +1464,7 @@ - reg = <0x50023000 0x400>; - clocks = <&rcc LPTIM4_K>; - clock-names = "mux"; -+ power-domains = <&pd_core>; - status = "disabled"; - - pwm { -@@ -890,6 +1479,7 @@ - reg = <0x50024000 0x400>; - clocks = <&rcc LPTIM5_K>; - clock-names = "mux"; -+ power-domains = <&pd_core>; - status = "disabled"; - - pwm { -@@ -908,6 +1498,198 @@ - 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>; -+ clocks = <&rcc SAI4_K>; -+ clock-names = "sai_ck"; -+ 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>; -@@ -923,7 +1705,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"; -@@ -942,21 +1724,74 @@ - reg = <0x58000000 0x1000>; - interrupts = ; - clocks = <&rcc MDMA>; -- #dma-cells = <5>; -+ resets = <&rcc MDMA_R>; -+ #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 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: spi@58003000 { - compatible = "st,stm32f469-qspi"; - reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; - reg-names = "qspi", "qspi_mm"; - interrupts = ; -+ 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>; - status = "disabled"; - }; - -+ sdmmc1: sdmmc@58005000 { -+ compatible = "arm,pl18x", "arm,primecell"; -+ arm,primecell-periphid = <0x00253180>; -+ reg = <0x58005000 0x1000>, <0x58006000 0x1000>; -+ interrupts = ; -+ interrupt-names = "cmd_irq"; -+ clocks = <&rcc SDMMC1_K>; -+ clock-names = "apb_pclk"; -+ resets = <&rcc SDMMC1_R>; -+ cap-sd-highspeed; -+ cap-mmc-highspeed; -+ max-frequency = <120000000>; -+ status = "disabled"; -+ }; -+ -+ sdmmc2: sdmmc@58007000 { -+ compatible = "arm,pl18x", "arm,primecell"; -+ arm,primecell-periphid = <0x00253180>; -+ reg = <0x58007000 0x1000>, <0x58008000 0x1000>; -+ interrupts = ; -+ interrupt-names = "cmd_irq"; -+ clocks = <&rcc SDMMC2_K>; -+ clock-names = "apb_pclk"; -+ resets = <&rcc SDMMC2_R>; -+ cap-sd-highspeed; -+ cap-mmc-highspeed; -+ max-frequency = <120000000>; -+ status = "disabled"; -+ }; -+ - crc1: crc@58009000 { - compatible = "st,stm32f7-crc"; - reg = <0x58009000 0x400>; -@@ -974,23 +1809,27 @@ - compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; - reg = <0x5800a000 0x2000>; - reg-names = "stmmaceth"; -- interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; -- interrupt-names = "macirq"; -+ 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", -- "syscfg-clk"; -+ "ethstp"; - clocks = <&rcc ETHMAC>, - <&rcc ETHTX>, - <&rcc ETHRX>, -- <&rcc ETHSTP>, -- <&rcc SYSCFG>; -+ <&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"; - }; - -@@ -1008,8 +1847,22 @@ - 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"; -+ }; -+ -+ 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"; - }; - -@@ -1020,6 +1873,7 @@ - clock-names = "pclk", "ref", "px_clk"; - resets = <&rcc DSI_R>; - reset-names = "apb"; -+ phy-dsi-supply = <®18>; - status = "disabled"; - }; - -@@ -1045,10 +1899,13 @@ - 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 { -@@ -1062,11 +1919,25 @@ - }; - }; - -+ 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>; -- 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"; - }; - -@@ -1078,22 +1949,30 @@ - interrupts = ; - clocks = <&rcc SPI6_K>; - resets = <&rcc SPI6_R>; -- dmas = <&mdma1 34 0x0 0x40008 0x0 0x0>, -- <&mdma1 35 0x0 0x40002 0x0 0x0>; -+ 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 0x8>; - status = "disabled"; - }; - -@@ -1102,21 +1981,93 @@ - reg = <0x5c004000 0x400>; - clocks = <&rcc RTCAPB>, <&rcc RTC>; - clock-names = "pclk", "rtc_ck"; -- interrupts = ; -+ 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>; -+ -+ part_number_otp: part_number_otp@4 { -+ reg = <0x4 0x1>; -+ }; -+ 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>; -+ st,syscfg-fmp-clr = <&syscfg 0x44 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>; -+ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; -+ status = "disabled"; -+ -+ m4_system_resources { -+ compatible = "rproc-srm-core"; - status = "disabled"; - }; - }; -+ -+ firmware { -+ optee { -+ compatible = "linaro,optee-tz"; -+ method = "smc"; -+ }; -+ }; - }; -diff --git a/arch/arm/boot/dts/stm32mp157caa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157caa-pinctrl.dtsi -new file mode 100644 -index 0000000..9b9cd08 ---- /dev/null -+++ b/arch/arm/boot/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/boot/dts/stm32mp157cab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157cab-pinctrl.dtsi -new file mode 100644 -index 0000000..c570cf9 ---- /dev/null -+++ b/arch/arm/boot/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/boot/dts/stm32mp157cac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157cac-pinctrl.dtsi -new file mode 100644 -index 0000000..777f991 ---- /dev/null -+++ b/arch/arm/boot/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/boot/dts/stm32mp157cad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi -new file mode 100644 -index 0000000..c4c303a ---- /dev/null -+++ b/arch/arm/boot/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>; -+ }; -+ }; -+ }; -+}; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch new file mode 100644 index 0000000..8b8171f --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch @@ -0,0 +1,58 @@ +From fda596ab13299af0f9cebfa8f9bde2827b02a2b3 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:36:29 +0200 +Subject: [PATCH 01/23] ARM-stm32mp1-r1-MACHINE + +--- + arch/arm/kernel/time.c | 2 ++ + arch/arm/mach-stm32/Kconfig | 1 + + arch/arm/mach-stm32/board-dt.c | 2 ++ + 3 files changed, 5 insertions(+) + +diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c +index b996b2cf0..dddc7ebf4 100644 +--- a/arch/arm/kernel/time.c ++++ b/arch/arm/kernel/time.c +@@ -9,6 +9,7 @@ + * reading the RTC at bootup, etc... + */ + #include ++#include + #include + #include + #include +@@ -107,5 +108,6 @@ void __init time_init(void) + of_clk_init(NULL); + #endif + timer_probe(); ++ tick_setup_hrtimer_broadcast(); + } + } +diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig +index 57699bd8f..8f9fd1da9 100644 +--- a/arch/arm/mach-stm32/Kconfig ++++ b/arch/arm/mach-stm32/Kconfig +@@ -46,6 +46,7 @@ if ARCH_MULTI_V7 + config MACH_STM32MP157 + bool "STMicroelectronics STM32MP157" + select ARM_ERRATA_814220 ++ select REGULATOR + default y + + endif # ARMv7-A +diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c +index 011d57b48..8e06a9442 100644 +--- a/arch/arm/mach-stm32/board-dt.c ++++ b/arch/arm/mach-stm32/board-dt.c +@@ -17,6 +17,8 @@ static const char *const stm32_compat[] __initconst = { + "st,stm32f746", + "st,stm32f769", + "st,stm32h743", ++ "st,stm32mp151", ++ "st,stm32mp153", + "st,stm32mp157", + NULL + }; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch similarity index 67% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch index b27de52..440b21e 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch @@ -1,21 +1,22 @@ -From 704a13efcc696fa4d151b741e0882f4c42eef870 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Thu, 30 Jan 2020 15:28:05 +0100 -Subject: [PATCH 02/31] ARM stm32mp1 r3 CPUFREQ +From 14bcead6b5ca532f85cffadab2753cc044002f86 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:37:04 +0200 +Subject: [PATCH 02/23] ARM-stm32mp1-r1-CPUFREQ --- - drivers/cpufreq/Kconfig.arm | 7 +++ - drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/cpufreq-dt-platdev.c | 1 + - drivers/cpufreq/stm32-cpufreq.c | 99 ++++++++++++++++++++++++++++++++++++ - 4 files changed, 108 insertions(+) + drivers/cpufreq/Kconfig.arm | 7 ++ + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + + drivers/cpufreq/stm32-cpufreq.c | 101 +++++++++++++++++++++++++++ + drivers/opp/core.c | 11 ++- + 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/stm32-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index 0cd8eb7..b950d5a 100644 +index a905796f7..b2beb1708 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm -@@ -255,6 +255,13 @@ config ARM_STI_CPUFREQ +@@ -295,6 +295,13 @@ config ARM_STI_CPUFREQ this config option if you wish to add CPUFreq support for STi based SoCs. @@ -30,22 +31,22 @@ index 0cd8eb7..b950d5a 100644 bool depends on CPUFREQ_DT && ARCH_TANGO diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index c1ffeab..c15b4f7 100644 +index 9a9f5ccd1..6139d2aeb 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile -@@ -79,6 +79,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o +@@ -80,6 +80,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o +obj-$(CONFIG_ARM_STM32_CPUFREQ) += stm32-cpufreq.o + obj-$(CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM) += sun50i-cpufreq-nvmem.o obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o - obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c -index fe14c57..d61a02a 100644 +index bca8d1f47..7ac5715e4 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c -@@ -121,6 +121,7 @@ static const struct of_device_id blacklist[] __initconst = { +@@ -131,6 +131,7 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, @@ -55,10 +56,10 @@ index fe14c57..d61a02a 100644 diff --git a/drivers/cpufreq/stm32-cpufreq.c b/drivers/cpufreq/stm32-cpufreq.c new file mode 100644 -index 0000000..f4a41e0 +index 000000000..35fb3520d --- /dev/null +++ b/drivers/cpufreq/stm32-cpufreq.c -@@ -0,0 +1,99 @@ +@@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -115,7 +116,9 @@ index 0000000..f4a41e0 + priv->opps = dev_pm_opp_set_supported_hw(cpu_dev, &supported_hw, 1); + if (IS_ERR(priv->opps)) { + ret = PTR_ERR(priv->opps); -+ dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ++ ret); + return ret; + } + @@ -158,6 +161,37 @@ index 0000000..f4a41e0 +MODULE_DESCRIPTION("STM32 CPU freq driver"); +MODULE_AUTHOR("Alexandre Torgue "); +MODULE_LICENSE("GPL v2"); +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 9ff0538ee..1974bf21f 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -980,9 +980,14 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index) + opp_table->clk = clk_get(dev, NULL); + if (IS_ERR(opp_table->clk)) { + ret = PTR_ERR(opp_table->clk); +- if (ret != -EPROBE_DEFER) ++ if (ret != -EPROBE_DEFER) { + dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, + ret); ++ } ++ else { ++ kfree(opp_table); ++ return ERR_PTR(-EPROBE_DEFER); ++ } + } + + BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head); +@@ -1443,6 +1448,10 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); ++ ++ if (PTR_ERR(opp_table) == -EPROBE_DEFER) ++ return opp_table; ++ + if (!opp_table) + return ERR_PTR(-ENOMEM); + -- -2.7.4 +2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch new file mode 100644 index 0000000..1ff660e --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch @@ -0,0 +1,1233 @@ +From ad399098098fb0ed48ccab85bbc70e15de7777c0 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:38:03 +0200 +Subject: [PATCH 03/23] ARM-stm32mp1-r1-CRYPTO + +--- + drivers/crypto/stm32/stm32-crc32.c | 228 +++++++++++++++------- + drivers/crypto/stm32/stm32-cryp.c | 300 +++++++++++++++++++++-------- + drivers/crypto/stm32/stm32-hash.c | 57 ++++-- + 3 files changed, 417 insertions(+), 168 deletions(-) + +diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c +index 9e11c3480..892d5b6eb 100644 +--- a/drivers/crypto/stm32/stm32-crc32.c ++++ b/drivers/crypto/stm32/stm32-crc32.c +@@ -28,18 +28,23 @@ + + /* Registers values */ + #define CRC_CR_RESET BIT(0) +-#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5)) +-#define CRC_INIT_DEFAULT 0xFFFFFFFF ++#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5)) ++#define CRC_CR_REV_IN_BYTE BIT(5) ++#define CRC_CR_REV_OUT BIT(7) ++#define CRC32C_INIT_DEFAULT 0xFFFFFFFF + + #define CRC_AUTOSUSPEND_DELAY 50 + ++static unsigned int burst_size; ++module_param(burst_size, uint, 0644); ++MODULE_PARM_DESC(burst_size, "Select burst byte size (0 unlimited)"); ++ + struct stm32_crc { + struct list_head list; + struct device *dev; + void __iomem *regs; + struct clk *clk; +- u8 pending_data[sizeof(u32)]; +- size_t nb_pending_bytes; ++ spinlock_t lock; + }; + + struct stm32_crc_list { +@@ -59,14 +64,13 @@ struct stm32_crc_ctx { + + struct stm32_crc_desc_ctx { + u32 partial; /* crc32c: partial in first 4 bytes of that struct */ +- struct stm32_crc *crc; + }; + + static int stm32_crc32_cra_init(struct crypto_tfm *tfm) + { + struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); + +- mctx->key = CRC_INIT_DEFAULT; ++ mctx->key = 0; + mctx->poly = CRC32_POLY_LE; + return 0; + } +@@ -75,7 +79,7 @@ static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) + { + struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); + +- mctx->key = CRC_INIT_DEFAULT; ++ mctx->key = CRC32C_INIT_DEFAULT; + mctx->poly = CRC32C_POLY_LE; + return 0; + } +@@ -94,87 +98,135 @@ static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, + return 0; + } + ++static struct stm32_crc *stm32_crc_get_next_crc(void) ++{ ++ struct stm32_crc *crc; ++ ++ spin_lock_bh(&crc_list.lock); ++ crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); ++ if (crc) ++ list_move_tail(&crc->list, &crc_list.dev_list); ++ spin_unlock_bh(&crc_list.lock); ++ ++ return crc; ++} ++ + static int stm32_crc_init(struct shash_desc *desc) + { + struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); + struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); + struct stm32_crc *crc; ++ unsigned long flags; + +- spin_lock_bh(&crc_list.lock); +- list_for_each_entry(crc, &crc_list.dev_list, list) { +- ctx->crc = crc; +- break; +- } +- spin_unlock_bh(&crc_list.lock); ++ crc = stm32_crc_get_next_crc(); ++ if (!crc) ++ return -ENODEV; ++ ++ pm_runtime_get_sync(crc->dev); + +- pm_runtime_get_sync(ctx->crc->dev); ++ spin_lock_irqsave(&crc->lock, flags); + + /* Reset, set key, poly and configure in bit reverse mode */ +- writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); +- writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); +- writel_relaxed(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR); ++ writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT); ++ writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); ++ writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, ++ crc->regs + CRC_CR); + + /* Store partial result */ +- ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); +- ctx->crc->nb_pending_bytes = 0; ++ ctx->partial = readl_relaxed(crc->regs + CRC_DR); + +- pm_runtime_mark_last_busy(ctx->crc->dev); +- pm_runtime_put_autosuspend(ctx->crc->dev); ++ spin_unlock_irqrestore(&crc->lock, flags); ++ ++ pm_runtime_mark_last_busy(crc->dev); ++ pm_runtime_put_autosuspend(crc->dev); + + return 0; + } + +-static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, +- unsigned int length) ++static int burst_update(struct shash_desc *desc, const u8 *d8, ++ size_t length) + { + struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); +- struct stm32_crc *crc = ctx->crc; +- u32 *d32; +- unsigned int i; ++ struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); ++ struct stm32_crc *crc; ++ unsigned long flags; ++ ++ crc = stm32_crc_get_next_crc(); ++ if (!crc) ++ return -ENODEV; + + pm_runtime_get_sync(crc->dev); + +- if (unlikely(crc->nb_pending_bytes)) { +- while (crc->nb_pending_bytes != sizeof(u32) && length) { +- /* Fill in pending data */ +- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); ++ spin_lock_irqsave(&crc->lock, flags); ++ ++ /* ++ * Restore previously calculated CRC for this context as init value ++ * Restore polynomial configuration ++ * Configure in register for word input data, ++ * Configure out register in reversed bit mode data. ++ */ ++ writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT); ++ writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); ++ writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, ++ crc->regs + CRC_CR); ++ ++ if (d8 != PTR_ALIGN(d8, sizeof(u32))) { ++ /* Configure for byte data */ ++ writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, ++ crc->regs + CRC_CR); ++ while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) { ++ writeb_relaxed(*d8++, crc->regs + CRC_DR); + length--; + } +- +- if (crc->nb_pending_bytes == sizeof(u32)) { +- /* Process completed pending data */ +- writel_relaxed(*(u32 *)crc->pending_data, +- crc->regs + CRC_DR); +- crc->nb_pending_bytes = 0; +- } ++ /* Configure for word data */ ++ writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, ++ crc->regs + CRC_CR); + } + +- d32 = (u32 *)d8; +- for (i = 0; i < length >> 2; i++) +- /* Process 32 bits data */ +- writel_relaxed(*(d32++), crc->regs + CRC_DR); ++ for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32)) ++ writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR); ++ ++ if (length) { ++ /* Configure for byte data */ ++ writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, ++ crc->regs + CRC_CR); ++ while (length--) ++ writeb_relaxed(*d8++, crc->regs + CRC_DR); ++ } + + /* Store partial result */ + ctx->partial = readl_relaxed(crc->regs + CRC_DR); + ++ spin_unlock_irqrestore(&crc->lock, flags); ++ + pm_runtime_mark_last_busy(crc->dev); + pm_runtime_put_autosuspend(crc->dev); + +- /* Check for pending data (non 32 bits) */ +- length &= 3; +- if (likely(!length)) +- return 0; ++ return 0; ++} + +- if ((crc->nb_pending_bytes + length) >= sizeof(u32)) { +- /* Shall not happen */ +- dev_err(crc->dev, "Pending data overflow\n"); +- return -EINVAL; +- } ++static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, ++ unsigned int length) ++{ ++ const unsigned int burst_sz = burst_size; ++ unsigned int rem_sz; ++ const u8 *cur; ++ size_t size; ++ int ret; + +- d8 = (const u8 *)d32; +- for (i = 0; i < length; i++) +- /* Store pending data */ +- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); ++ if (!burst_sz) ++ return burst_update(desc, d8, length); ++ ++ /* Digest first bytes not 32bit aligned at first pass in the loop */ ++ size = min(length, ++ burst_sz + (unsigned int)d8 - ALIGN_DOWN((unsigned int)d8, ++ sizeof(u32))); ++ for (rem_sz = length, cur = d8; rem_sz; ++ rem_sz -= size, cur += size, size = min(rem_sz, burst_sz)) { ++ ret = burst_update(desc, cur, size); ++ if (ret) ++ return ret; ++ } + + return 0; + } +@@ -204,6 +256,8 @@ static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, + return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); + } + ++static unsigned int refcnt; ++static DEFINE_MUTEX(refcnt_lock); + static struct shash_alg algs[] = { + /* CRC-32 */ + { +@@ -271,7 +325,9 @@ static int stm32_crc_probe(struct platform_device *pdev) + + crc->clk = devm_clk_get(dev, NULL); + if (IS_ERR(crc->clk)) { +- dev_err(dev, "Could not get clock\n"); ++ if (PTR_ERR(crc->clk) != -EPROBE_DEFER) ++ dev_err(dev, "Could not get clock\n"); ++ + return PTR_ERR(crc->clk); + } + +@@ -286,20 +342,29 @@ static int stm32_crc_probe(struct platform_device *pdev) + + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); ++ pm_runtime_irq_safe(dev); + pm_runtime_enable(dev); + ++ spin_lock_init(&crc->lock); ++ + platform_set_drvdata(pdev, crc); + + spin_lock(&crc_list.lock); + list_add(&crc->list, &crc_list.dev_list); + spin_unlock(&crc_list.lock); + +- ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); +- if (ret) { +- dev_err(dev, "Failed to register\n"); +- clk_disable_unprepare(crc->clk); +- return ret; ++ mutex_lock(&refcnt_lock); ++ if (!refcnt) { ++ ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); ++ if (ret) { ++ mutex_unlock(&refcnt_lock); ++ dev_err(dev, "Failed to register\n"); ++ clk_disable_unprepare(crc->clk); ++ return ret; ++ } + } ++ refcnt++; ++ mutex_unlock(&refcnt_lock); + + dev_info(dev, "Initialized\n"); + +@@ -320,7 +385,10 @@ static int stm32_crc_remove(struct platform_device *pdev) + list_del(&crc->list); + spin_unlock(&crc_list.lock); + +- crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); ++ mutex_lock(&refcnt_lock); ++ if (!--refcnt) ++ crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); ++ mutex_unlock(&refcnt_lock); + + pm_runtime_disable(crc->dev); + pm_runtime_put_noidle(crc->dev); +@@ -331,11 +399,39 @@ static int stm32_crc_remove(struct platform_device *pdev) + } + + #ifdef CONFIG_PM ++static int stm32_crc_suspend(struct device *dev) ++{ ++ struct stm32_crc *crc = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pm_runtime_force_suspend(dev); ++ if (ret) ++ return ret; ++ ++ clk_unprepare(crc->clk); ++ ++ return 0; ++} ++ ++static int stm32_crc_resume(struct device *dev) ++{ ++ struct stm32_crc *crc = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_prepare(crc->clk); ++ if (ret) { ++ dev_err(crc->dev, "Failed to prepare clock\n"); ++ return ret; ++ } ++ ++ return pm_runtime_force_resume(dev); ++} ++ + static int stm32_crc_runtime_suspend(struct device *dev) + { + struct stm32_crc *crc = dev_get_drvdata(dev); + +- clk_disable_unprepare(crc->clk); ++ clk_disable(crc->clk); + + return 0; + } +@@ -345,9 +441,9 @@ static int stm32_crc_runtime_resume(struct device *dev) + struct stm32_crc *crc = dev_get_drvdata(dev); + int ret; + +- ret = clk_prepare_enable(crc->clk); ++ ret = clk_enable(crc->clk); + if (ret) { +- dev_err(crc->dev, "Failed to prepare_enable clock\n"); ++ dev_err(crc->dev, "Failed to enable clock\n"); + return ret; + } + +@@ -356,8 +452,8 @@ static int stm32_crc_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops stm32_crc_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, +- pm_runtime_force_resume) ++ SET_SYSTEM_SLEEP_PM_OPS(stm32_crc_suspend, ++ stm32_crc_resume) + SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, + stm32_crc_runtime_resume, NULL) + }; +diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c +index ba5ea6434..fbf522dc3 100644 +--- a/drivers/crypto/stm32/stm32-cryp.c ++++ b/drivers/crypto/stm32/stm32-cryp.c +@@ -143,10 +143,10 @@ struct stm32_cryp { + size_t authsize; + size_t hw_blocksize; + ++ size_t remain_in; + size_t total_in; +- size_t total_in_save; ++ size_t remain_out; + size_t total_out; +- size_t total_out_save; + + struct scatterlist *in_sg; + struct scatterlist *out_sg; +@@ -156,9 +156,6 @@ struct stm32_cryp { + struct scatterlist out_sgl; + bool sgs_copied; + +- int in_sg_len; +- int out_sg_len; +- + struct scatter_walk in_walk; + struct scatter_walk out_walk; + +@@ -321,28 +318,46 @@ static int stm32_cryp_check_io_aligned(struct stm32_cryp *cryp) + + ret = stm32_cryp_check_aligned(cryp->out_sg, cryp->total_out, + cryp->hw_blocksize); ++ if (ret) ++ return ret; ++ ++ if (is_gcm(cryp) || is_ccm(cryp)) ++ if (!IS_ALIGNED(cryp->areq->assoclen, sizeof(u32))) ++ ret = -EINVAL; + + return ret; + } + + static void sg_copy_buf(void *buf, struct scatterlist *sg, +- unsigned int start, unsigned int nbytes, int out) ++ unsigned int start, unsigned int first_len, ++ unsigned int zero_len, ++ unsigned int second_len, ++ int out) + { + struct scatter_walk walk; ++ unsigned int nbytes = first_len + zero_len + second_len; ++ u32 empty = 0; + + if (!nbytes) + return; + + scatterwalk_start(&walk, sg); + scatterwalk_advance(&walk, start); +- scatterwalk_copychunks(buf, &walk, nbytes, out); ++ if (first_len) ++ scatterwalk_copychunks(buf, &walk, first_len, out); ++ if (zero_len) ++ memcpy(buf+first_len, &empty, zero_len); ++ if (second_len) ++ scatterwalk_copychunks(buf + first_len + zero_len, &walk, ++ second_len, out); ++ + scatterwalk_done(&walk, out, 0); + } + + static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) + { + void *buf_in, *buf_out; +- int pages, total_in, total_out; ++ int pages_in, pages_out, total_in, total_out; + + if (!stm32_cryp_check_io_aligned(cryp)) { + cryp->sgs_copied = 0; +@@ -350,29 +365,37 @@ static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) + } + + total_in = ALIGN(cryp->total_in, cryp->hw_blocksize); +- pages = total_in ? get_order(total_in) : 1; +- buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); ++ pages_in = total_in ? get_order(total_in) : 1; ++ buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages_in); + + total_out = ALIGN(cryp->total_out, cryp->hw_blocksize); +- pages = total_out ? get_order(total_out) : 1; +- buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); ++ pages_out = total_out ? get_order(total_out) : 1; ++ buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages_out); + + if (!buf_in || !buf_out) { + dev_err(cryp->dev, "Can't allocate pages when unaligned\n"); ++ if (buf_in) ++ free_pages((unsigned long)buf_in, pages_in); + cryp->sgs_copied = 0; + return -EFAULT; + } + +- sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0); ++ ++ if ((is_gcm(cryp) || is_ccm(cryp)) && (!IS_ALIGNED(cryp->areq->assoclen, ++ sizeof(u32)))) { ++ sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->areq->assoclen, ++ ALIGN(cryp->areq->assoclen, sizeof(u32)) ++ - cryp->areq->assoclen, ++ cryp->areq->cryptlen, 0); ++ } else ++ sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0, 0, 0); + + sg_init_one(&cryp->in_sgl, buf_in, total_in); + cryp->in_sg = &cryp->in_sgl; +- cryp->in_sg_len = 1; + + sg_init_one(&cryp->out_sgl, buf_out, total_out); + cryp->out_sg_save = cryp->out_sg; + cryp->out_sg = &cryp->out_sgl; +- cryp->out_sg_len = 1; + + cryp->sgs_copied = 1; + +@@ -649,14 +672,14 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) + buf_in = sg_virt(&cryp->in_sgl); + buf_out = sg_virt(&cryp->out_sgl); + +- sg_copy_buf(buf_out, cryp->out_sg_save, 0, +- cryp->total_out_save, 1); ++ sg_copy_buf(buf_out, cryp->out_sg_save, 0, 0, 0, ++ cryp->total_out, 1); + +- len = ALIGN(cryp->total_in_save, cryp->hw_blocksize); ++ len = ALIGN(cryp->total_in, cryp->hw_blocksize); + pages = len ? get_order(len) : 1; + free_pages((unsigned long)buf_in, pages); + +- len = ALIGN(cryp->total_out_save, cryp->hw_blocksize); ++ len = ALIGN(cryp->total_out, cryp->hw_blocksize); + pages = len ? get_order(len) : 1; + free_pages((unsigned long)buf_out, pages); + } +@@ -796,7 +819,20 @@ static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, + static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) + { +- return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL; ++ switch (authsize) { ++ case 4: ++ case 8: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ case 16: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; + } + + static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, +@@ -820,31 +856,61 @@ static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, + + static int stm32_cryp_aes_ecb_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ecb_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB); + } + + static int stm32_cryp_aes_cbc_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_cbc_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC); + } + + static int stm32_cryp_aes_ctr_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ctr_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR); + } + +@@ -858,53 +924,122 @@ static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req) + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM); + } + ++static inline int crypto_ccm_check_iv(const u8 *iv) ++{ ++ /* 2 <= L <= 8, so 1 <= L' <= 7. */ ++ if (iv[0] < 1 || iv[0] > 7) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req) + { ++ int err; ++ ++ err = crypto_ccm_check_iv(req->iv); ++ if (err) ++ return err; ++ + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req) + { ++ int err; ++ ++ err = crypto_ccm_check_iv(req->iv); ++ if (err) ++ return err; ++ + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM); + } + + static int stm32_cryp_des_ecb_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_des_ecb_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB); + } + + static int stm32_cryp_des_cbc_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_des_cbc_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC); + } + + static int stm32_cryp_tdes_ecb_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_tdes_ecb_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB); + } + + static int stm32_cryp_tdes_cbc_encrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_tdes_cbc_decrypt(struct ablkcipher_request *req) + { ++ if (req->nbytes % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->nbytes == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC); + } + +@@ -966,36 +1101,25 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, + cryp->areq = areq; + cryp->req = NULL; + cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq)); +- cryp->total_in = areq->assoclen + areq->cryptlen; ++ cryp->total_in = ALIGN(areq->assoclen, sizeof(u32)) ++ + areq->cryptlen; + if (is_encrypt(cryp)) + /* Append auth tag to output */ +- cryp->total_out = cryp->total_in + cryp->authsize; ++ cryp->total_out = areq->assoclen + areq->cryptlen ++ + cryp->authsize; + else + /* No auth tag in output */ +- cryp->total_out = cryp->total_in - cryp->authsize; ++ cryp->total_out = areq->assoclen + areq->cryptlen ++ - cryp->authsize; + } + +- cryp->total_in_save = cryp->total_in; +- cryp->total_out_save = cryp->total_out; ++ cryp->remain_in = cryp->total_in; ++ cryp->remain_out = cryp->total_out; + + cryp->in_sg = req ? req->src : areq->src; + cryp->out_sg = req ? req->dst : areq->dst; + cryp->out_sg_save = cryp->out_sg; + +- cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in); +- if (cryp->in_sg_len < 0) { +- dev_err(cryp->dev, "Cannot get in_sg_len\n"); +- ret = cryp->in_sg_len; +- return ret; +- } +- +- cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); +- if (cryp->out_sg_len < 0) { +- dev_err(cryp->dev, "Cannot get out_sg_len\n"); +- ret = cryp->out_sg_len; +- return ret; +- } +- + ret = stm32_cryp_copy_sgs(cryp); + if (ret) + return ret; +@@ -1006,7 +1130,7 @@ static int stm32_cryp_prepare_req(struct ablkcipher_request *req, + if (is_gcm(cryp) || is_ccm(cryp)) { + /* In output, jump after assoc data */ + scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen); +- cryp->total_out -= cryp->areq->assoclen; ++ cryp->remain_out -= cryp->areq->assoclen; + } + + ret = stm32_cryp_hw_init(cryp); +@@ -1125,7 +1249,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, size_bit); + + size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen : +- cryp->areq->cryptlen - AES_BLOCK_SIZE; ++ cryp->areq->cryptlen - cryp->authsize; + size_bit *= 8; + if (cryp->caps->swap_final) + size_bit = cpu_to_be32(size_bit); +@@ -1159,14 +1283,14 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + dst = sg_virt(cryp->out_sg) + _walked_out; + + for (i = 0; i < AES_BLOCK_32; i++) { +- if (cryp->total_out >= sizeof(u32)) { ++ if (cryp->remain_out >= sizeof(u32)) { + /* Read a full u32 */ + *dst = stm32_cryp_read(cryp, CRYP_DOUT); + + dst = stm32_cryp_next_out(cryp, dst, + sizeof(u32)); +- cryp->total_out -= sizeof(u32); +- } else if (!cryp->total_out) { ++ cryp->remain_out -= sizeof(u32); ++ } else if (!cryp->remain_out) { + /* Empty fifo out (data from input padding) */ + stm32_cryp_read(cryp, CRYP_DOUT); + } else { +@@ -1174,11 +1298,11 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + d32 = stm32_cryp_read(cryp, CRYP_DOUT); + d8 = (u8 *)&d32; + +- for (j = 0; j < cryp->total_out; j++) { ++ for (j = 0; j < cryp->remain_out; j++) { + *((u8 *)dst) = *(d8++); + dst = stm32_cryp_next_out(cryp, dst, 1); + } +- cryp->total_out = 0; ++ cryp->remain_out = 0; + } + } + } else { +@@ -1186,7 +1310,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32]; + + scatterwalk_map_and_copy(in_tag, cryp->in_sg, +- cryp->total_in_save - cryp->authsize, ++ cryp->total_in - cryp->authsize, + cryp->authsize, 0); + + for (i = 0; i < AES_BLOCK_32; i++) +@@ -1246,13 +1370,13 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) + dst = sg_virt(cryp->out_sg) + _walked_out; + + for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { +- if (likely(cryp->total_out - tag_size >= sizeof(u32))) { ++ if (likely(cryp->remain_out - tag_size >= sizeof(u32))) { + /* Read a full u32 */ + *dst = stm32_cryp_read(cryp, CRYP_DOUT); + + dst = stm32_cryp_next_out(cryp, dst, sizeof(u32)); +- cryp->total_out -= sizeof(u32); +- } else if (cryp->total_out == tag_size) { ++ cryp->remain_out -= sizeof(u32); ++ } else if (cryp->remain_out == tag_size) { + /* Empty fifo out (data from input padding) */ + d32 = stm32_cryp_read(cryp, CRYP_DOUT); + } else { +@@ -1260,15 +1384,15 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) + d32 = stm32_cryp_read(cryp, CRYP_DOUT); + d8 = (u8 *)&d32; + +- for (j = 0; j < cryp->total_out - tag_size; j++) { ++ for (j = 0; j < cryp->remain_out - tag_size; j++) { + *((u8 *)dst) = *(d8++); + dst = stm32_cryp_next_out(cryp, dst, 1); + } +- cryp->total_out = tag_size; ++ cryp->remain_out = tag_size; + } + } + +- return !(cryp->total_out - tag_size) || !cryp->total_in; ++ return !(cryp->remain_out - tag_size) || !cryp->remain_in; + } + + static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) +@@ -1287,25 +1411,25 @@ static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) + src = sg_virt(cryp->in_sg) + _walked_in; + + for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { +- if (likely(cryp->total_in - tag_size >= sizeof(u32))) { ++ if (likely(cryp->remain_in - tag_size >= sizeof(u32))) { + /* Write a full u32 */ + stm32_cryp_write(cryp, CRYP_DIN, *src); + + src = stm32_cryp_next_in(cryp, src, sizeof(u32)); +- cryp->total_in -= sizeof(u32); +- } else if (cryp->total_in == tag_size) { ++ cryp->remain_in -= sizeof(u32); ++ } else if (cryp->remain_in == tag_size) { + /* Write padding data */ + stm32_cryp_write(cryp, CRYP_DIN, 0); + } else { + /* Write less than an u32 */ + memset(d8, 0, sizeof(u32)); +- for (j = 0; j < cryp->total_in - tag_size; j++) { ++ for (j = 0; j < cryp->remain_in - tag_size; j++) { + d8[j] = *((u8 *)src); + src = stm32_cryp_next_in(cryp, src, 1); + } + + stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- cryp->total_in = tag_size; ++ cryp->remain_in = tag_size; + } + } + } +@@ -1314,7 +1438,7 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + { + int err; + u32 cfg, tmp[AES_BLOCK_32]; +- size_t total_in_ori = cryp->total_in; ++ size_t remain_in_ori = cryp->remain_in; + struct scatterlist *out_sg_ori = cryp->out_sg; + unsigned int i; + +@@ -1340,7 +1464,7 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + + /* b) pad and write the last block */ + stm32_cryp_irq_write_block(cryp); +- cryp->total_in = total_in_ori; ++ cryp->remain_in = remain_in_ori; + err = stm32_cryp_wait_output(cryp); + if (err) { + dev_err(cryp->dev, "Timeout (write gcm header)\n"); +@@ -1350,8 +1474,8 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + /* c) get and store encrypted data */ + stm32_cryp_irq_read_data(cryp); + scatterwalk_map_and_copy(tmp, out_sg_ori, +- cryp->total_in_save - total_in_ori, +- total_in_ori, 0); ++ cryp->total_in - remain_in_ori, ++ remain_in_ori, 0); + + /* d) change mode back to AES GCM */ + cfg &= ~CR_ALGO_MASK; +@@ -1365,12 +1489,12 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + + /* f) write padded data */ + for (i = 0; i < AES_BLOCK_32; i++) { +- if (cryp->total_in) ++ if (cryp->remain_in) + stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); + else + stm32_cryp_write(cryp, CRYP_DIN, 0); + +- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); ++ cryp->remain_in -= min_t(size_t, sizeof(u32), cryp->remain_in); + } + + /* g) Empty fifo out */ +@@ -1396,8 +1520,8 @@ static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp) + cfg &= ~CR_CRYPEN; + stm32_cryp_write(cryp, CRYP_CR, cfg); + +- payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize : +- cryp->total_in; ++ payload_bytes = is_decrypt(cryp) ? cryp->remain_in - cryp->authsize : ++ cryp->remain_in; + cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT; + cfg |= CR_CRYPEN; + stm32_cryp_write(cryp, CRYP_CR, cfg); +@@ -1408,7 +1532,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + int err = 0; + u32 cfg, iv1tmp; + u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32]; +- size_t last_total_out, total_in_ori = cryp->total_in; ++ size_t last_remain_out, remain_in_ori = cryp->remain_in; + struct scatterlist *out_sg_ori = cryp->out_sg; + unsigned int i; + +@@ -1443,7 +1567,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + + /* b) pad and write the last block */ + stm32_cryp_irq_write_block(cryp); +- cryp->total_in = total_in_ori; ++ cryp->remain_in = remain_in_ori; + err = stm32_cryp_wait_output(cryp); + if (err) { + dev_err(cryp->dev, "Timeout (wite ccm padded data)\n"); +@@ -1451,13 +1575,13 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + } + + /* c) get and store decrypted data */ +- last_total_out = cryp->total_out; ++ last_remain_out = cryp->remain_out; + stm32_cryp_irq_read_data(cryp); + + memset(tmp, 0, sizeof(tmp)); + scatterwalk_map_and_copy(tmp, out_sg_ori, +- cryp->total_out_save - last_total_out, +- last_total_out, 0); ++ cryp->total_out - last_remain_out, ++ last_remain_out, 0); + + /* d) Load again CRYP_CSGCMCCMxR */ + for (i = 0; i < ARRAY_SIZE(cstmp2); i++) +@@ -1491,12 +1615,12 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + + static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) + { +- if (unlikely(!cryp->total_in)) { ++ if (unlikely(!cryp->remain_in)) { + dev_warn(cryp->dev, "No more data to process\n"); + return; + } + +- if (unlikely(cryp->total_in < AES_BLOCK_SIZE && ++ if (unlikely(cryp->remain_in < AES_BLOCK_SIZE && + (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) && + is_encrypt(cryp))) { + /* Padding for AES GCM encryption */ +@@ -1508,7 +1632,7 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) + stm32_cryp_irq_set_npblb(cryp); + } + +- if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) && ++ if (unlikely((cryp->remain_in - cryp->authsize < AES_BLOCK_SIZE) && + (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) && + is_decrypt(cryp))) { + /* Padding for AES CCM decryption */ +@@ -1538,10 +1662,10 @@ static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, *src); + + src = stm32_cryp_next_in(cryp, src, sizeof(u32)); +- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); ++ cryp->remain_in -= min_t(size_t, sizeof(u32), cryp->remain_in); + + /* Check if whole header written */ +- if ((cryp->total_in_save - cryp->total_in) == ++ if ((cryp->total_in - cryp->remain_in) >= + cryp->areq->assoclen) { + /* Write padding if needed */ + for (j = i + 1; j < AES_BLOCK_32; j++) +@@ -1573,7 +1697,7 @@ static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) + break; + } + +- if (!cryp->total_in) ++ if (!cryp->remain_in) + break; + } + } +@@ -1601,7 +1725,7 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); + i++; + +- cryp->total_in -= min_t(size_t, 2, cryp->total_in); ++ cryp->remain_in -= min_t(size_t, 2, cryp->remain_in); + } else { + /* Build the two first u32 of B1 */ + d8[0] = 0xFF; +@@ -1622,7 +1746,7 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); + i++; + +- cryp->total_in -= min_t(size_t, 2, cryp->total_in); ++ cryp->remain_in -= min_t(size_t, 2, cryp->remain_in); + } + } + +@@ -1634,14 +1758,14 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) + d8[k] = *((u8 *)src); + src = stm32_cryp_next_in(cryp, src, 1); + +- cryp->total_in -= min_t(size_t, 1, cryp->total_in); +- if ((cryp->total_in_save - cryp->total_in) == alen) ++ cryp->remain_in -= min_t(size_t, 1, cryp->remain_in); ++ if ((cryp->total_in - cryp->remain_in) == alen) + break; + } + + stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); + +- if ((cryp->total_in_save - cryp->total_in) == alen) { ++ if ((cryp->total_in - cryp->remain_in) == alen) { + /* Write padding if needed */ + for (j = i + 1; j < AES_BLOCK_32; j++) + stm32_cryp_write(cryp, CRYP_DIN, 0); +@@ -1966,7 +2090,9 @@ static int stm32_cryp_probe(struct platform_device *pdev) + + cryp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cryp->clk)) { +- dev_err(dev, "Could not get clock\n"); ++ if (PTR_ERR(cryp->clk) != -EPROBE_DEFER) ++ dev_err(dev, "Could not get clock\n"); ++ + return PTR_ERR(cryp->clk); + } + +@@ -1984,7 +2110,11 @@ static int stm32_cryp_probe(struct platform_device *pdev) + pm_runtime_enable(dev); + + rst = devm_reset_control_get(dev, NULL); +- if (!IS_ERR(rst)) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_rst; ++ } else { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); +@@ -2035,7 +2165,7 @@ static int stm32_cryp_probe(struct platform_device *pdev) + spin_lock(&cryp_list.lock); + list_del(&cryp->list); + spin_unlock(&cryp_list.lock); +- ++err_rst: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); +diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c +index cfc8e0e37..f8b0e1b28 100644 +--- a/drivers/crypto/stm32/stm32-hash.c ++++ b/drivers/crypto/stm32/stm32-hash.c +@@ -507,6 +507,7 @@ static int stm32_hash_hmac_dma_send(struct stm32_hash_dev *hdev) + static int stm32_hash_dma_init(struct stm32_hash_dev *hdev) + { + struct dma_slave_config dma_conf; ++ struct dma_chan *chan; + int err; + + memset(&dma_conf, 0, sizeof(dma_conf)); +@@ -518,11 +519,11 @@ static int stm32_hash_dma_init(struct stm32_hash_dev *hdev) + dma_conf.dst_maxburst = hdev->dma_maxburst; + dma_conf.device_fc = false; + +- hdev->dma_lch = dma_request_slave_channel(hdev->dev, "in"); +- if (!hdev->dma_lch) { +- dev_err(hdev->dev, "Couldn't acquire a slave DMA channel.\n"); +- return -EBUSY; +- } ++ chan = dma_request_chan(hdev->dev, "in"); ++ if (IS_ERR(chan)) ++ return PTR_ERR(chan); ++ ++ hdev->dma_lch = chan; + + err = dmaengine_slave_config(hdev->dma_lch, &dma_conf); + if (err) { +@@ -923,15 +924,10 @@ static int stm32_hash_final(struct ahash_request *req) + static int stm32_hash_finup(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); + int err1, err2; + + rctx->flags |= HASH_FLAGS_FINUP; + +- if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) +- rctx->flags &= ~HASH_FLAGS_CPU; +- + err1 = stm32_hash_update(req); + + if (err1 == -EINPROGRESS || err1 == -EBUSY) +@@ -948,7 +944,19 @@ static int stm32_hash_finup(struct ahash_request *req) + + static int stm32_hash_digest(struct ahash_request *req) + { +- return stm32_hash_init(req) ?: stm32_hash_finup(req); ++ int ret; ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); ++ struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ ++ ret = stm32_hash_init(req); ++ if (ret) ++ return ret; ++ ++ if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) ++ rctx->flags &= ~HASH_FLAGS_CPU; ++ ++ return stm32_hash_finup(req); + } + + static int stm32_hash_export(struct ahash_request *req, void *out) +@@ -1463,8 +1471,11 @@ static int stm32_hash_probe(struct platform_device *pdev) + + hdev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(hdev->clk)) { +- dev_err(dev, "failed to get clock for hash (%lu)\n", +- PTR_ERR(hdev->clk)); ++ if (PTR_ERR(hdev->clk) != -EPROBE_DEFER) { ++ dev_err(dev, "failed to get clock for hash (%lu)\n", ++ PTR_ERR(hdev->clk)); ++ } ++ + return PTR_ERR(hdev->clk); + } + +@@ -1482,7 +1493,12 @@ static int stm32_hash_probe(struct platform_device *pdev) + pm_runtime_enable(dev); + + hdev->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (!IS_ERR(hdev->rst)) { ++ if (IS_ERR(hdev->rst)) { ++ if (PTR_ERR(hdev->rst) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ goto err_reset; ++ } ++ } else { + reset_control_assert(hdev->rst); + udelay(2); + reset_control_deassert(hdev->rst); +@@ -1493,8 +1509,15 @@ static int stm32_hash_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, hdev); + + ret = stm32_hash_dma_init(hdev); +- if (ret) ++ switch (ret) { ++ case 0: ++ break; ++ case -ENOENT: + dev_dbg(dev, "DMA mode not available\n"); ++ break; ++ default: ++ goto err_dma; ++ } + + spin_lock(&stm32_hash.lock); + list_add_tail(&hdev->list, &stm32_hash.dev_list); +@@ -1532,10 +1555,10 @@ static int stm32_hash_probe(struct platform_device *pdev) + spin_lock(&stm32_hash.lock); + list_del(&hdev->list); + spin_unlock(&stm32_hash.lock); +- ++err_dma: + if (hdev->dma_lch) + dma_release_channel(hdev->dma_lch); +- ++err_reset: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch new file mode 100644 index 0000000..a24c2a3 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch @@ -0,0 +1,231 @@ +From 31ac3e358c9c6303d58c3f24fe33b6924a56bddd Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:39:52 +0200 +Subject: [PATCH 04/23] ARM-stm32mp1-r1-RNG-DEBUG-NVMEM + +--- + arch/arm/Kconfig.debug | 42 +++++++++++++++++++++++++----- + arch/arm/include/debug/stm32.S | 9 +++---- + drivers/char/hw_random/stm32-rng.c | 5 +++- + drivers/nvmem/core.c | 37 ++++++++++++++++++++++++++ + include/linux/nvmem-consumer.h | 7 +++++ + 5 files changed, 88 insertions(+), 12 deletions(-) + +diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug +index 8bcbd0cd7..3357e294a 100644 +--- a/arch/arm/Kconfig.debug ++++ b/arch/arm/Kconfig.debug +@@ -1201,23 +1201,49 @@ choice + + config STM32F4_DEBUG_UART + bool "Use STM32F4 UART for low-level debug" +- depends on ARCH_STM32 ++ depends on MACH_STM32F429 || MACH_STM32F469 + select DEBUG_STM32_UART + help + Say Y here if you want kernel low-level debugging support + on STM32F4 based platforms, which default UART is wired on +- USART1. ++ USART1, but another UART instance can be selected by modifying ++ CONFIG_DEBUG_UART_PHYS. + + If unsure, say N. + + config STM32F7_DEBUG_UART + bool "Use STM32F7 UART for low-level debug" +- depends on ARCH_STM32 ++ depends on MACH_STM32F746 || MACH_STM32F769 + select DEBUG_STM32_UART + help + Say Y here if you want kernel low-level debugging support + on STM32F7 based platforms, which default UART is wired on +- USART1. ++ USART1, but another UART instance can be selected by modifying ++ CONFIG_DEBUG_UART_PHYS. ++ ++ If unsure, say N. ++ ++ config STM32H7_DEBUG_UART ++ bool "Use STM32H7 UART for low-level debug" ++ depends on MACH_STM32H743 ++ select DEBUG_STM32_UART ++ help ++ Say Y here if you want kernel low-level debugging support ++ on STM32H7 based platforms, which default UART is wired on ++ USART1, but another UART instance can be selected by modifying ++ CONFIG_DEBUG_UART_PHYS. ++ ++ If unsure, say N. ++ ++ config STM32MP1_DEBUG_UART ++ bool "Use STM32MP1 UART for low-level debug" ++ depends on MACH_STM32MP157 ++ select DEBUG_STM32_UART ++ help ++ Say Y here if you want kernel low-level debugging support ++ on STM32MP1 based platforms, wich default UART is wired on ++ UART4, but another UART instance can be selected by modifying ++ CONFIG_DEBUG_UART_PHYS and CONFIG_DEBUG_UART_VIRT. + + If unsure, say N. + +@@ -1619,6 +1645,9 @@ config DEBUG_UART_PHYS + default 0x3e000000 if DEBUG_BCM_KONA_UART + default 0x3f201000 if DEBUG_BCM2836 + default 0x4000e400 if DEBUG_LL_UART_EFM32 ++ default 0x40010000 if STM32MP1_DEBUG_UART ++ default 0x40011000 if STM32F4_DEBUG_UART || STM32F7_DEBUG_UART || \ ++ STM32H7_DEBUG_UART + default 0x40028000 if DEBUG_AT91_SAMV7_USART1 + default 0x40081000 if DEBUG_LPC18XX_UART0 + default 0x40090000 if DEBUG_LPC32XX +@@ -1713,7 +1742,7 @@ config DEBUG_UART_PHYS + DEBUG_S3C64XX_UART || \ + DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ + DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ +- DEBUG_AT91_UART ++ DEBUG_AT91_UART || DEBUG_STM32_UART + + config DEBUG_UART_VIRT + hex "Virtual base address of debug UART" +@@ -1779,6 +1808,7 @@ config DEBUG_UART_VIRT + default 0xfcfe8600 if DEBUG_BCM63XX_UART + default 0xfd000000 if DEBUG_SPEAR3XX || DEBUG_SPEAR13XX + default 0xfd883000 if DEBUG_ALPINE_UART0 ++ default 0xfe010000 if STM32MP1_DEBUG_UART + default 0xfe017000 if DEBUG_MMP_UART2 + default 0xfe018000 if DEBUG_MMP_UART3 + default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART +@@ -1823,7 +1853,7 @@ config DEBUG_UART_VIRT + DEBUG_S3C64XX_UART || \ + DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ + DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ +- DEBUG_AT91_UART ++ DEBUG_AT91_UART || DEBUG_STM32_UART + + config DEBUG_UART_8250_SHIFT + int "Register offset shift for the 8250 debug UART" +diff --git a/arch/arm/include/debug/stm32.S b/arch/arm/include/debug/stm32.S +index 1abb32f68..6446e4692 100644 +--- a/arch/arm/include/debug/stm32.S ++++ b/arch/arm/include/debug/stm32.S +@@ -4,14 +4,13 @@ + * Author: Gerald Baeza for STMicroelectronics. + */ + +-#define STM32_UART_BASE 0x40011000 /* USART1 */ +- + #ifdef CONFIG_STM32F4_DEBUG_UART + #define STM32_USART_SR_OFF 0x00 + #define STM32_USART_TDR_OFF 0x04 + #endif + +-#ifdef CONFIG_STM32F7_DEBUG_UART ++#if defined(CONFIG_STM32F7_DEBUG_UART) || (CONFIG_STM32H7_DEBUG_UART) || \ ++ defined(CONFIG_STM32MP1_DEBUG_UART) + #define STM32_USART_SR_OFF 0x1C + #define STM32_USART_TDR_OFF 0x28 + #endif +@@ -20,8 +19,8 @@ + #define STM32_USART_TXE (1 << 7) /* Tx data reg empty */ + + .macro addruart, rp, rv, tmp +- ldr \rp, =STM32_UART_BASE @ physical base +- ldr \rv, =STM32_UART_BASE @ virt base /* NoMMU */ ++ ldr \rp, =CONFIG_DEBUG_UART_PHYS @ physical base ++ ldr \rv, =CONFIG_DEBUG_UART_VIRT @ virt base + .endm + + .macro senduart,rd,rx +diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c +index 38324c2dd..a25c4b5c3 100644 +--- a/drivers/char/hw_random/stm32-rng.c ++++ b/drivers/char/hw_random/stm32-rng.c +@@ -135,7 +135,10 @@ static int stm32_rng_probe(struct platform_device *ofdev) + return PTR_ERR(priv->clk); + + priv->rst = devm_reset_control_get(&ofdev->dev, NULL); +- if (!IS_ERR(priv->rst)) { ++ if (IS_ERR(priv->rst)) { ++ if (PTR_ERR(priv->rst) != -ENOENT) ++ return PTR_ERR(priv->rst); ++ } else { + reset_control_assert(priv->rst); + udelay(2); + reset_control_deassert(priv->rst); +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index 960542dea..8105fe423 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -1080,6 +1080,43 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) + } + EXPORT_SYMBOL_GPL(nvmem_cell_write); + ++/** ++ * nvmem_cell_read_u8() - Read a cell value as an u8 ++ * ++ * @dev: Device that requests the nvmem cell. ++ * @cell_id: Name of nvmem cell to read. ++ * @val: pointer to output value. ++ * ++ * Return: 0 on success or negative errno. ++ */ ++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) ++{ ++ struct nvmem_cell *cell; ++ void *buf; ++ size_t len; ++ ++ cell = nvmem_cell_get(dev, cell_id); ++ if (IS_ERR(cell)) ++ return PTR_ERR(cell); ++ ++ buf = nvmem_cell_read(cell, &len); ++ if (IS_ERR(buf)) { ++ nvmem_cell_put(cell); ++ return PTR_ERR(buf); ++ } ++ if (len != sizeof(*val)) { ++ kfree(buf); ++ nvmem_cell_put(cell); ++ return -EINVAL; ++ } ++ memcpy(val, buf, sizeof(*val)); ++ kfree(buf); ++ nvmem_cell_put(cell); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); ++ + /** + * nvmem_cell_read_u16() - Read a cell value as an u16 + * +diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h +index 5c17cb733..c3c53a63e 100644 +--- a/include/linux/nvmem-consumer.h ++++ b/include/linux/nvmem-consumer.h +@@ -61,6 +61,7 @@ void nvmem_cell_put(struct nvmem_cell *cell); + void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); + void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); + int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); ++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); + int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); + int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); + +@@ -123,6 +124,12 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell, + return -EOPNOTSUPP; + } + ++static inline int nvmem_cell_read_u8(struct device *dev, ++ const char *cell_id, u8 *val) ++{ ++ return -EOPNOTSUPP; ++} ++ + static inline int nvmem_cell_read_u16(struct device *dev, + const char *cell_id, u16 *val) + { +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch new file mode 100644 index 0000000..87dfb55 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch @@ -0,0 +1,1542 @@ +From 8e898b8cdce1f6bfb91ce5720946d4cbece59da6 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:40:17 +0200 +Subject: [PATCH 05/23] ARM-stm32mp1-r1-CLOCK + +--- + drivers/clk/clk-stm32mp1.c | 875 ++++++++++++++++++++-------- + drivers/clk/clk.c | 7 +- + drivers/counter/stm32-lptimer-cnt.c | 2 +- + drivers/counter/stm32-timer-cnt.c | 68 ++- + 4 files changed, 700 insertions(+), 252 deletions(-) + +diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c +index a875649df..4a282bfd2 100644 +--- a/drivers/clk/clk-stm32mp1.c ++++ b/drivers/clk/clk-stm32mp1.c +@@ -5,15 +5,26 @@ + * Author: Gabriel Fernandez for STMicroelectronics. + */ + ++#include ++#include + #include + #include + #include ++#include + #include ++#include + #include ++#include ++#include ++#include + #include + #include ++#include ++#include ++#include + #include + #include ++#include + + #include + +@@ -45,6 +56,7 @@ static DEFINE_SPINLOCK(rlock); + #define RCC_AHB5ENSETR 0x210 + #define RCC_AHB6ENSETR 0x218 + #define RCC_AHB6LPENSETR 0x318 ++#define RCC_MLAHBENSETR 0xA38 + #define RCC_RCK12SELR 0x28 + #define RCC_RCK3SELR 0x820 + #define RCC_RCK4SELR 0x824 +@@ -101,8 +113,12 @@ static DEFINE_SPINLOCK(rlock); + #define RCC_TIMG2PRER 0x82C + #define RCC_RTCDIVR 0x44 + #define RCC_DBGCFGR 0x80C ++#define RCC_SREQSETR 0x104 ++#define RCC_SREQCLRR 0x108 ++#define RCC_CIER 0x414 ++#define RCC_CIFR 0x418 + +-#define RCC_CLR 0x4 ++#define RCC_CLR 0x4 + + static const char * const ref12_parents[] = { + "ck_hsi", "ck_hse" +@@ -113,7 +129,7 @@ static const char * const ref3_parents[] = { + }; + + static const char * const ref4_parents[] = { +- "ck_hsi", "ck_hse", "ck_csi" ++ "ck_hsi", "ck_hse", "ck_csi", "i2s_ckin" + }; + + static const char * const cpu_src[] = { +@@ -245,7 +261,7 @@ static const char * const dsi_src[] = { + }; + + static const char * const rtc_src[] = { +- "off", "ck_lse", "ck_lsi", "ck_hse_rtc" ++ "off", "ck_lse", "ck_lsi", "ck_hse" + }; + + static const char * const mco1_src[] = { +@@ -291,6 +307,8 @@ static const struct clk_div_table ck_trace_div_table[] = { + struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; ++ u8 saved_parent; ++ u8 enable_count; + }; + + struct stm32_clk_mmux { +@@ -323,7 +341,7 @@ struct clock_config { + const struct clock_config *cfg); + }; + +-#define NO_ID ~0 ++#define NO_ID GENMASK(31, 0) + + struct gate_cfg { + u32 reg_off; +@@ -469,7 +487,7 @@ static const struct clk_ops mp1_gate_clk_ops = { + .is_enabled = clk_gate_is_enabled, + }; + +-static struct clk_hw *_get_stm32_mux(void __iomem *base, ++static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, + const struct stm32_mux_cfg *cfg, + spinlock_t *lock) + { +@@ -478,7 +496,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, + struct clk_hw *mux_hw; + + if (cfg->mmux) { +- mmux = kzalloc(sizeof(*mmux), GFP_KERNEL); ++ mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); + if (!mmux) + return ERR_PTR(-ENOMEM); + +@@ -493,7 +511,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, + cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; + + } else { +- mux = kzalloc(sizeof(*mux), GFP_KERNEL); ++ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + +@@ -509,13 +527,13 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, + return mux_hw; + } + +-static struct clk_hw *_get_stm32_div(void __iomem *base, ++static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base, + const struct stm32_div_cfg *cfg, + spinlock_t *lock) + { + struct clk_divider *div; + +- div = kzalloc(sizeof(*div), GFP_KERNEL); ++ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + + if (!div) + return ERR_PTR(-ENOMEM); +@@ -530,16 +548,16 @@ static struct clk_hw *_get_stm32_div(void __iomem *base, + return &div->hw; + } + +-static struct clk_hw * +-_get_stm32_gate(void __iomem *base, +- const struct stm32_gate_cfg *cfg, spinlock_t *lock) ++static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base, ++ const struct stm32_gate_cfg *cfg, ++ spinlock_t *lock) + { + struct stm32_clk_mgate *mgate; + struct clk_gate *gate; + struct clk_hw *gate_hw; + + if (cfg->mgate) { +- mgate = kzalloc(sizeof(*mgate), GFP_KERNEL); ++ mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); + if (!mgate) + return ERR_PTR(-ENOMEM); + +@@ -554,7 +572,7 @@ _get_stm32_gate(void __iomem *base, + gate_hw = &mgate->gate.hw; + + } else { +- gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + +@@ -592,7 +610,7 @@ clk_stm32_register_gate_ops(struct device *dev, + if (cfg->ops) + init.ops = cfg->ops; + +- hw = _get_stm32_gate(base, cfg, lock); ++ hw = _get_stm32_gate(dev, base, cfg, lock); + if (IS_ERR(hw)) + return ERR_PTR(-ENOMEM); + +@@ -623,7 +641,7 @@ clk_stm32_register_composite(struct device *dev, + gate_ops = NULL; + + if (cfg->mux) { +- mux_hw = _get_stm32_mux(base, cfg->mux, lock); ++ mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); + + if (!IS_ERR(mux_hw)) { + mux_ops = &clk_mux_ops; +@@ -634,7 +652,7 @@ clk_stm32_register_composite(struct device *dev, + } + + if (cfg->div) { +- div_hw = _get_stm32_div(base, cfg->div, lock); ++ div_hw = _get_stm32_div(dev, base, cfg->div, lock); + + if (!IS_ERR(div_hw)) { + div_ops = &clk_divider_ops; +@@ -645,7 +663,7 @@ clk_stm32_register_composite(struct device *dev, + } + + if (cfg->gate) { +- gate_hw = _get_stm32_gate(base, cfg->gate, lock); ++ gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); + + if (!IS_ERR(gate_hw)) { + gate_ops = &clk_gate_ops; +@@ -714,7 +732,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) +- clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); ++ clk_hw_set_parent(clk_mmux->mmux->hws[n], hwp); + + return 0; + } +@@ -725,178 +743,260 @@ static const struct clk_ops clk_mmux_ops = { + .determine_rate = __clk_mux_determine_rate, + }; + +-/* STM32 PLL */ +-struct stm32_pll_obj { +- /* lock pll enable/disable registers */ +- spinlock_t *lock; +- void __iomem *reg; +- struct clk_hw hw; +-}; ++#define MMUX_SAFE_POSITION 0 + +-#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) ++static int clk_mmux_set_safe_position(struct clk_hw *hw) ++{ ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +-#define PLL_ON BIT(0) +-#define PLL_RDY BIT(1) +-#define DIVN_MASK 0x1FF +-#define DIVM_MASK 0x3F +-#define DIVM_SHIFT 16 +-#define DIVN_SHIFT 0 +-#define FRAC_OFFSET 0xC +-#define FRAC_MASK 0x1FFF +-#define FRAC_SHIFT 3 +-#define FRACLE BIT(16) ++ if (--clk_mmux->mmux->enable_count == 0) { ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(mux_hw); ++ clk_mux_ops.set_parent(mux_hw, MMUX_SAFE_POSITION); ++ } + +-static int __pll_is_enabled(struct clk_hw *hw) ++ return 0; ++} ++ ++static int clk_mmux_restore_parent(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- return readl_relaxed(clk_elem->reg) & PLL_ON; +-} ++ if (clk_mmux->mmux->enable_count == 0) ++ clk_mux_ops.set_parent(mux_hw, clk_mmux->mmux->saved_parent); + +-#define TIMEOUT 5 ++ clk_mmux->mmux->enable_count++; + +-static int pll_enable(struct clk_hw *hw) ++ return 0; ++} ++ ++static u8 clk_mmux_get_parent_safe(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg; +- unsigned long flags = 0; +- unsigned int timeout = TIMEOUT; +- int bit_status = 0; ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- spin_lock_irqsave(clk_elem->lock, flags); ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(hw); + +- if (__pll_is_enabled(hw)) +- goto unlock; ++ return clk_mmux->mmux->saved_parent; ++} ++ ++static int clk_mmux_set_parent_safe(struct clk_hw *hw, u8 index) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +- reg = readl_relaxed(clk_elem->reg); +- reg |= PLL_ON; +- writel_relaxed(reg, clk_elem->reg); ++ clk_mmux_set_parent(hw, index); ++ clk_mmux->mmux->saved_parent = index; + +- /* We can't use readl_poll_timeout() because we can be blocked if +- * someone enables this clock before clocksource changes. +- * Only jiffies counter is available. Jiffies are incremented by +- * interruptions and enable op does not allow to be interrupted. +- */ +- do { +- bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); ++ return 0; ++} + +- if (bit_status) +- udelay(120); ++static const struct clk_ops clk_mmux_safe_ops = { ++ .get_parent = clk_mmux_get_parent_safe, ++ .set_parent = clk_mmux_set_parent_safe, ++ .determine_rate = __clk_mux_determine_rate, ++}; + +- } while (bit_status && --timeout); ++static int mp1_mgate_clk_enable_safe(struct clk_hw *hw) ++{ ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); + +-unlock: +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ clk_mmux_restore_parent(composite_hw); ++ mp1_mgate_clk_enable(hw); + +- return bit_status; ++ return 0; + } + +-static void pll_disable(struct clk_hw *hw) ++static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg; +- unsigned long flags = 0; +- +- spin_lock_irqsave(clk_elem->lock, flags); ++ struct clk_gate *gate = to_clk_gate(hw); ++ struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); + +- reg = readl_relaxed(clk_elem->reg); +- reg &= ~PLL_ON; +- writel_relaxed(reg, clk_elem->reg); ++ clk_mgate->mgate->flag &= ~clk_mgate->mask; + +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ if (clk_mgate->mgate->flag == 0) { ++ clk_mmux_set_safe_position(composite_hw); ++ mp1_gate_clk_disable(hw); ++ } + } + +-static u32 pll_frac_val(struct clk_hw *hw) ++static const struct clk_ops mp1_mgate_clk_safe_ops = { ++ .enable = mp1_mgate_clk_enable_safe, ++ .disable = mp1_mgate_clk_disable_safe, ++ .is_enabled = clk_gate_is_enabled, ++}; ++ ++/* STM32 PLL */ ++struct clk_pll_fractional_divider { ++ struct clk_hw hw; ++ void __iomem *mreg; ++ u8 mshift; ++ u8 mwidth; ++ u8 mflags; ++ void __iomem *nreg; ++ u8 nshift; ++ u8 nwidth; ++ u8 nflags; ++ void __iomem *freg; ++ u8 fshift; ++ u8 fwidth; ++ ++ /* lock pll enable/disable registers */ ++ spinlock_t *lock; ++}; ++ ++#define to_pll_fractional_divider(_hw)\ ++ container_of(_hw, struct clk_pll_fractional_divider, hw) ++ ++static unsigned long clk_pll_frac_div_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg, frac = 0; ++ struct clk_pll_fractional_divider *fd = to_pll_fractional_divider(hw); ++ u32 mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; ++ u32 nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; ++ u32 fmask = GENMASK(fd->fwidth - 1, 0) << fd->fshift; ++ unsigned long m, n, f; ++ u64 rate, frate = 0; ++ u32 val; ++ ++ val = readl(fd->mreg); ++ m = (val & mmask) >> fd->mshift; ++ if (fd->mflags & CLK_FRAC_DIVIDER_ZERO_BASED) ++ m++; ++ ++ val = readl(fd->nreg); ++ n = (val & nmask) >> fd->nshift; ++ if (fd->nflags & CLK_FRAC_DIVIDER_ZERO_BASED) ++ n++; ++ ++ if (!n || !m) ++ return parent_rate; + +- reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); +- if (reg & FRACLE) +- frac = (reg >> FRAC_SHIFT) & FRAC_MASK; ++ rate = (u64)parent_rate * n; ++ do_div(rate, m); + +- return frac; ++ val = readl(fd->freg); ++ f = (val & fmask) >> fd->fshift; ++ if (f) { ++ frate = (u64)parent_rate * (u64)f; ++ do_div(frate, (m * (1 << fd->fwidth))); ++ } ++ return rate + frate; + } + +-static unsigned long pll_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) ++static const struct clk_ops clk_pll_frac_div_ops = { ++ .recalc_rate = clk_pll_frac_div_recalc_rate, ++}; ++ ++#define PLL_BIT_ON 0 ++#define PLL_BIT_RDY 1 ++#define PLL_MUX_SHIFT 0 ++#define PLL_MUX_MASK 3 ++#define PLL_DIVMN_OFFSET 4 ++#define PLL_DIVM_SHIFT 16 ++#define PLL_DIVM_WIDTH 6 ++#define PLL_DIVN_SHIFT 0 ++#define PLL_DIVN_WIDTH 9 ++#define PLL_FRAC_OFFSET 0xC ++#define PLL_FRAC_SHIFT 3 ++#define PLL_FRAC_WIDTH 13 ++ ++#define TIMEOUT 5 ++ ++static int pll_enable(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- u32 reg; +- u32 frac, divm, divn; +- u64 rate, rate_frac = 0; ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 timeout = TIMEOUT; ++ int bit_status = 0; ++ ++ if (clk_gate_ops.is_enabled(hw)) ++ return 0; + +- reg = readl_relaxed(clk_elem->reg + 4); ++ clk_gate_ops.enable(hw); + +- divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; +- divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; +- rate = (u64)parent_rate * divn; ++ do { ++ bit_status = !(readl_relaxed(gate->reg) & BIT(PLL_BIT_RDY)); + +- do_div(rate, divm); ++ if (bit_status) ++ udelay(120); + +- frac = pll_frac_val(hw); +- if (frac) { +- rate_frac = (u64)parent_rate * (u64)frac; +- do_div(rate_frac, (divm * 8192)); +- } ++ } while (bit_status && --timeout); + +- return rate + rate_frac; ++ return bit_status; + } + +-static int pll_is_enabled(struct clk_hw *hw) ++static void pll_disable(struct clk_hw *hw) + { +- struct stm32_pll_obj *clk_elem = to_pll(hw); +- unsigned long flags = 0; +- int ret; +- +- spin_lock_irqsave(clk_elem->lock, flags); +- ret = __pll_is_enabled(hw); +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ if (!clk_gate_ops.is_enabled(hw)) ++ return; + +- return ret; ++ clk_gate_ops.disable(hw); + } + +-static const struct clk_ops pll_ops = { ++const struct clk_ops pll_gate_ops = { + .enable = pll_enable, + .disable = pll_disable, +- .recalc_rate = pll_recalc_rate, +- .is_enabled = pll_is_enabled, ++ .is_enabled = clk_gate_is_enabled, + }; + + static struct clk_hw *clk_register_pll(struct device *dev, const char *name, +- const char *parent_name, ++ const char * const *parent_names, ++ int num_parents, + void __iomem *reg, ++ void __iomem *mux_reg, + unsigned long flags, + spinlock_t *lock) + { +- struct stm32_pll_obj *element; +- struct clk_init_data init; +- struct clk_hw *hw; +- int err; ++ struct clk_pll_fractional_divider *frac_div; ++ struct clk_gate *gate; ++ struct clk_mux *mux; + +- element = kzalloc(sizeof(*element), GFP_KERNEL); +- if (!element) ++ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); ++ if (!mux) + return ERR_PTR(-ENOMEM); + +- init.name = name; +- init.ops = &pll_ops; +- init.flags = flags; +- init.parent_names = &parent_name; +- init.num_parents = 1; ++ mux->reg = mux_reg; ++ mux->shift = PLL_MUX_SHIFT; ++ mux->mask = PLL_MUX_MASK; ++ mux->flags = CLK_MUX_READ_ONLY; ++ mux->table = NULL; ++ mux->lock = lock; + +- element->hw.init = &init; +- element->reg = reg; +- element->lock = lock; ++ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); + +- hw = &element->hw; +- err = clk_hw_register(dev, hw); ++ gate->reg = reg; ++ gate->bit_idx = PLL_BIT_ON; ++ gate->flags = 0; ++ gate->lock = lock; + +- if (err) { +- kfree(element); +- return ERR_PTR(err); +- } ++ frac_div = devm_kzalloc(dev, sizeof(*frac_div), GFP_KERNEL); ++ if (!frac_div) ++ return ERR_PTR(-ENOMEM); + +- return hw; ++ frac_div->mreg = reg + PLL_DIVMN_OFFSET; ++ frac_div->mshift = PLL_DIVM_SHIFT; ++ frac_div->mwidth = PLL_DIVM_WIDTH; ++ frac_div->mflags = CLK_FRAC_DIVIDER_ZERO_BASED; ++ frac_div->nreg = reg + PLL_DIVMN_OFFSET; ++ frac_div->nshift = PLL_DIVN_SHIFT; ++ frac_div->nwidth = PLL_DIVN_WIDTH; ++ frac_div->nflags = CLK_FRAC_DIVIDER_ZERO_BASED; ++ frac_div->freg = reg + PLL_FRAC_OFFSET; ++ frac_div->fshift = PLL_FRAC_SHIFT; ++ frac_div->fwidth = PLL_FRAC_WIDTH; ++ ++ return clk_hw_register_composite(dev, name, parent_names, num_parents, ++ &mux->hw, &clk_mux_ops, ++ &frac_div->hw, &clk_pll_frac_div_ops, ++ &gate->hw, &pll_gate_ops, flags); + } + + /* Kernel Timer */ +@@ -1005,7 +1105,7 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + struct clk_hw *hw; + int err; + +- tim_ker = kzalloc(sizeof(*tim_ker), GFP_KERNEL); ++ tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); + if (!tim_ker) + return ERR_PTR(-ENOMEM); + +@@ -1023,16 +1123,51 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + hw = &tim_ker->hw; + err = clk_hw_register(dev, hw); + +- if (err) { +- kfree(tim_ker); ++ if (err) + return ERR_PTR(err); +- } + + return hw; + } + ++#define HSE_RTC 3 ++ ++static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) ++ return clk_divider_ops.recalc_rate(hw, parent_rate); ++ ++ return parent_rate; ++} ++ ++static long clk_divider_rtc_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) ++ return clk_divider_ops.round_rate(hw, rate, prate); ++ ++ return *prate; ++} ++ ++static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) ++ return clk_divider_ops.set_rate(hw, rate, parent_rate); ++ ++ return parent_rate; ++} ++ ++static const struct clk_ops rtc_div_clk_ops = { ++ .recalc_rate = clk_divider_rtc_recalc_rate, ++ .round_rate = clk_divider_rtc_round_rate, ++ .set_rate = clk_divider_rtc_set_rate, ++}; ++ + struct stm32_pll_cfg { + u32 offset; ++ u32 muxoff; ++ const struct clk_ops *ops; + }; + + static struct clk_hw *_clk_register_pll(struct device *dev, +@@ -1042,8 +1177,11 @@ static struct clk_hw *_clk_register_pll(struct device *dev, + { + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + +- return clk_register_pll(dev, cfg->name, cfg->parent_name, +- base + stm_pll_cfg->offset, cfg->flags, lock); ++ return clk_register_pll(dev, cfg->name, cfg->parent_names, ++ cfg->num_parents, ++ base + stm_pll_cfg->offset, ++ base + stm_pll_cfg->muxoff, ++ cfg->flags, lock); + } + + struct stm32_cktim_cfg { +@@ -1153,14 +1291,16 @@ _clk_stm32_register_composite(struct device *dev, + .func = _clk_hw_register_mux,\ + } + +-#define PLL(_id, _name, _parent, _flags, _offset)\ ++#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ + {\ + .id = _id,\ + .name = _name,\ +- .parent_name = _parent,\ +- .flags = _flags,\ ++ .parent_names = _parents,\ ++ .num_parents = ARRAY_SIZE(_parents),\ ++ .flags = CLK_IGNORE_UNUSED | (_flags),\ + .cfg = &(struct stm32_pll_cfg) {\ +- .offset = _offset,\ ++ .offset = _offset_p,\ ++ .muxoff = _offset_mux,\ + },\ + .func = _clk_register_pll,\ + } +@@ -1216,7 +1356,7 @@ _clk_stm32_register_composite(struct device *dev, + NULL, &mp1_gate_clk_ops)\ + + #define _MGATE_MP1(_mgate)\ +- .gate = &per_gate_cfg[_mgate] ++ &per_gate_cfg[_mgate] + + #define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ +@@ -1228,7 +1368,7 @@ _clk_stm32_register_composite(struct device *dev, + + #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ +- .div = &(struct stm32_div_cfg) {\ ++ (&(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ +@@ -1237,14 +1377,18 @@ _clk_stm32_register_composite(struct device *dev, + .table = _div_table,\ + },\ + .ops = _ops,\ +- } ++ }) + + #define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ +- _div_flags, _div_table, NULL)\ ++ _div_flags, _div_table, NULL) ++ ++#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ ++ _STM32_DIV(_div_offset, _div_shift, _div_width,\ ++ _div_flags, _div_table, &rtc_div_clk_ops) + + #define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ +- .mux = &(struct stm32_mux_cfg) {\ ++ (&(struct stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ +@@ -1254,18 +1398,18 @@ _clk_stm32_register_composite(struct device *dev, + },\ + .mmux = _mmux,\ + .ops = _ops,\ +- } ++ }) + + #define _MUX(_offset, _shift, _width, _mux_flags)\ +- _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ ++ _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL) + +-#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] ++#define _MMUX(_mmux) &ker_mux_cfg[_mmux] + +-#define PARENT(_parent) ((const char *[]) { _parent}) ++#define PARENT(_parent) ((const char *[]) { _parent}) + +-#define _NO_MUX .mux = NULL +-#define _NO_DIV .div = NULL +-#define _NO_GATE .gate = NULL ++#define _NO_MUX NULL ++#define _NO_DIV NULL ++#define _NO_GATE NULL + + #define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ + {\ +@@ -1275,9 +1419,9 @@ _clk_stm32_register_composite(struct device *dev, + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ +- _gate,\ +- _mux,\ +- _div,\ ++ .gate = (_gate),\ ++ .mux = (_mux),\ ++ .div = (_div),\ + },\ + .func = _clk_stm32_register_composite,\ + } +@@ -1292,6 +1436,11 @@ _clk_stm32_register_composite(struct device *dev, + _MMUX(_mmux),\ + _NO_DIV) + ++/* ++ * ++ * Security management ++ */ ++ + enum { + G_SAI1, + G_SAI2, +@@ -1409,8 +1558,7 @@ enum { + + static struct stm32_mgate mp1_mgate[G_LAST]; + +-#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ +- _mgate, _ops)\ ++#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ + [_id] = {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ +@@ -1429,6 +1577,10 @@ static struct stm32_mgate mp1_mgate[G_LAST]; + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + ++#define K_MGATE_SAFE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ ++ _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ ++ &mp1_mgate[_id], &mp1_mgate_clk_safe_ops) ++ + /* Peripheral gates */ + static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ +@@ -1540,16 +1692,19 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + + K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), + K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), +- K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), +- K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), +- K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), +- K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), ++ K_MGATE_SAFE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), ++ K_MGATE_SAFE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), ++ K_MGATE_SAFE(G_QSPI, RCC_AHB6ENSETR, 14, 0), ++ K_MGATE_SAFE(G_FMC, RCC_AHB6ENSETR, 12, 0), ++ + K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), + K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), + K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), + K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), ++ + K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), + K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), ++ + K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), + }; + +@@ -1615,9 +1770,13 @@ static struct stm32_mmux ker_mux[M_LAST]; + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + ++#define K_MMUX_SAFE(_id, _offset, _shift, _width, _mux_flags)\ ++ _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ ++ &ker_mux[_id], &clk_mmux_safe_ops) ++ + static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel multi mux */ +- K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), ++ K_MMUX_SAFE(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), + K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), + K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), + K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), +@@ -1634,8 +1793,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel simple mux */ + K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), + K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), +- K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), +- K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), ++ K_MMUX_SAFE(M_FMC, RCC_FMCCKSELR, 0, 2, 0), ++ K_MMUX_SAFE(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), + K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), + K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), + K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), +@@ -1656,40 +1815,43 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), + }; + ++/* ++ * On stm32mp15x, when TZEN is enabled, secure firmware provides ++ * the secure clocks RCC clock driver relies on. Firmware registers ++ * the following clocks in the Linux clock tree: ++ * "ck_hse", "ck_hsi", "ck_csi", "ck_lse", "ck_lsi", ++ * "pll2_q", "pll2_r", "ck_mpu", "ck_axi", ++ * "bsec", "cryp1", "gpioz", "hash1", "i2c4_k", "i2c6_k", "iwdg1", "rng1_k", ++ * "ck_rtc", "rtcapb", "spi6_k" and "usart1_k". ++ * For these clocks and there dependencies, SECURE bit is set in clock ++ * identifier field id to state which clocks RCC clock driver does not register ++ * because it has limited or no access to. ++ */ + static const struct clock_config stm32mp1_clock_cfg[] = { +- /* Oscillator divider */ +- DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, +- RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), +- +- /* External / Internal Oscillators */ ++ /* External / Internal Oscillators */ + GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), +- /* ck_csi is used by IO compensation and should be critical */ +- GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, +- RCC_OCENSETR, 4, 0), +- GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), ++ COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0, ++ _GATE_MP1(RCC_OCENSETR, 0, 0), ++ _NO_MUX, ++ _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO | ++ CLK_DIVIDER_READ_ONLY, NULL)), ++ /* ck_csi is used by IO compensation and shall be critical */ ++ GATE_MP1(CK_CSI, "ck_csi", "clk-csi", ++ CLK_IS_CRITICAL, RCC_OCENSETR, 4, 0), + GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), + GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), + + FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), + +- /* ref clock pll */ +- MUX(NO_ID, "ref1", ref12_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK12SELR, +- 0, 2, CLK_MUX_READ_ONLY), +- +- MUX(NO_ID, "ref3", ref3_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK3SELR, +- 0, 2, CLK_MUX_READ_ONLY), +- +- MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, +- 0, 2, CLK_MUX_READ_ONLY), +- + /* PLLs */ +- PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), +- PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), +- PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), +- PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), ++ PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR), ++ PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR), ++ PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR), ++ PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), + + /* ODF */ +- COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, ++ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), ++ CLK_SET_RATE_PARENT, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), +@@ -1743,34 +1905,36 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, + RCC_CPERCKSELR, 0, 2, 0), + +- MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | +- CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), ++ MUX(CK_MPU, "ck_mpu", cpu_src, ++ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT | ++ CLK_IS_CRITICAL, ++ RCC_MPCKSELR, 0, 2, 0), + +- COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | +- CLK_OPS_PARENT_ENABLE, +- _NO_GATE, +- _MUX(RCC_ASSCKSELR, 0, 2, 0), +- _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), ++ COMPOSITE(CK_AXI, "ck_axi", axi_src, ++ CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE, ++ _NO_GATE, ++ _MUX(RCC_ASSCKSELR, 0, 2, 0), ++ _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), + +- COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | +- CLK_OPS_PARENT_ENABLE, +- _NO_GATE, +- _MUX(RCC_MSSCKSELR, 0, 2, 0), +- _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), ++ COMPOSITE(CK_MCU, "ck_mcu", mcu_src, ++ CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE, ++ _NO_GATE, ++ _MUX(RCC_MSSCKSELR, 0, 2, 0), ++ _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), + +- DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, ++ DIV_TABLE(PCLK1, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + +- DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, ++ DIV_TABLE(PCLK2, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + +- DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, ++ DIV_TABLE(PCLK3, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + +- DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, ++ DIV_TABLE(PCLK4, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + +- DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, ++ DIV_TABLE(PCLK5, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + /* Kernel Timers */ +@@ -1852,8 +2016,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), + PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), + PCLK(USART1, "usart1", "pclk5", 0, G_USART1), +- PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | +- CLK_IS_CRITICAL, G_RTCAPB), ++ PCLK(RTCAPB, "rtcapb", "pclk5", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, G_RTCAPB), + PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), + PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), + PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), +@@ -1888,7 +2052,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), + PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), + PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), +- PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), ++ PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, ++ G_BKPSRAM), + PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), + PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), +@@ -1912,7 +2077,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), + KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), + KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), +- KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), ++ KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, ++ G_STGEN, M_STGEN), + KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), + KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), + KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), +@@ -1965,23 +2131,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), + + /* RTC clock */ +- DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0), +- +- COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | +- CLK_SET_RATE_PARENT, ++ COMPOSITE(RTC, "ck_rtc", rtc_src, ++ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, + _GATE(RCC_BDCR, 20, 0), + _MUX(RCC_BDCR, 16, 2, 0), +- _NO_DIV), ++ _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)), + + /* MCO clocks */ +- COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | +- CLK_SET_RATE_NO_REPARENT, ++ COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, ++ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO1CFGR, 12, 0), + _MUX(RCC_MCO1CFGR, 0, 3, 0), + _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), + +- COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | +- CLK_SET_RATE_NO_REPARENT, ++ COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, ++ CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO2CFGR, 12, 0), + _MUX(RCC_MCO2CFGR, 0, 3, 0), + _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), +@@ -1996,10 +2160,60 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), + }; + ++static const u32 stm32mp1_clock_secured[] = { ++ CK_HSE, ++ CK_HSI, ++ CK_CSI, ++ CK_LSI, ++ CK_LSE, ++ PLL1, ++ PLL2, ++ PLL1_P, ++ PLL2_P, ++ PLL2_Q, ++ PLL2_R, ++ CK_MPU, ++ CK_AXI, ++ SPI6, ++ I2C4, ++ I2C6, ++ USART1, ++ RTCAPB, ++ TZC1, ++ TZC2, ++ TZPC, ++ IWDG1, ++ BSEC, ++ STGEN, ++ GPIOZ, ++ CRYP1, ++ HASH1, ++ RNG1, ++ BKPSRAM, ++ RNG1_K, ++ STGEN_K, ++ SPI6_K, ++ I2C4_K, ++ I2C6_K, ++ USART1_K, ++ RTC, ++}; ++ ++static bool stm32_check_security(const struct clock_config *cfg) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++) ++ if (cfg->id == stm32mp1_clock_secured[i]) ++ return true; ++ return false; ++} ++ + struct stm32_clock_match_data { + const struct clock_config *cfg; + unsigned int num; + unsigned int maxbinding; ++ bool (*check_security)(const struct clock_config *cfg); + }; + + static struct stm32_clock_match_data stm32mp1_data = { +@@ -2008,13 +2222,25 @@ static struct stm32_clock_match_data stm32mp1_data = { + .maxbinding = STM32MP1_LAST_CLK, + }; + ++static struct stm32_clock_match_data stm32mp1_data_secure = { ++ .cfg = stm32mp1_clock_cfg, ++ .num = ARRAY_SIZE(stm32mp1_clock_cfg), ++ .maxbinding = STM32MP1_LAST_CLK, ++ .check_security = &stm32_check_security ++}; ++ + static const struct of_device_id stm32mp1_match_data[] = { + { + .compatible = "st,stm32mp1-rcc", + .data = &stm32mp1_data, + }, ++ { ++ .compatible = "st,stm32mp1-rcc-secure", ++ .data = &stm32mp1_data_secure, ++ }, + { } + }; ++MODULE_DEVICE_TABLE(of, stm32mp1_match_data); + + static int stm32_register_hw_clk(struct device *dev, + struct clk_hw_onecell_data *clk_data, +@@ -2040,8 +2266,7 @@ static int stm32_register_hw_clk(struct device *dev, + return 0; + } + +-static int stm32_rcc_init(struct device_node *np, +- void __iomem *base, ++static int stm32_rcc_init(struct device *dev, void __iomem *base, + const struct of_device_id *match_data) + { + struct clk_hw_onecell_data *clk_data; +@@ -2050,9 +2275,9 @@ static int stm32_rcc_init(struct device_node *np, + const struct stm32_clock_match_data *data; + int err, n, max_binding; + +- match = of_match_node(match_data, np); ++ match = of_match_node(match_data, dev_of_node(dev)); + if (!match) { +- pr_err("%s: match data not found\n", __func__); ++ dev_err(dev, "match data not found\n"); + return -ENODEV; + } + +@@ -2060,8 +2285,8 @@ static int stm32_rcc_init(struct device_node *np, + + max_binding = data->maxbinding; + +- clk_data = kzalloc(struct_size(clk_data, hws, max_binding), +- GFP_KERNEL); ++ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), ++ GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + +@@ -2073,36 +2298,194 @@ static int stm32_rcc_init(struct device_node *np, + hws[n] = ERR_PTR(-ENOENT); + + for (n = 0; n < data->num; n++) { +- err = stm32_register_hw_clk(NULL, clk_data, base, &rlock, ++ if (data->check_security && data->check_security(&data->cfg[n])) ++ continue; ++ ++ err = stm32_register_hw_clk(dev, clk_data, base, &rlock, + &data->cfg[n]); + if (err) { +- pr_err("%s: can't register %s\n", __func__, +- data->cfg[n].name); +- +- kfree(clk_data); ++ dev_err(dev, "Can't register clk %s: %d\n", ++ data->cfg[n].name, err); + + return err; + } + } + +- return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); ++ return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, ++ clk_data); + } + +-static void stm32mp1_rcc_init(struct device_node *np) ++static int stm32_rcc_init_pwr(struct device *dev, void __iomem *rcc_base); ++ ++static int stm32mp1_rcc_init(struct device *dev) + { +- void __iomem *base; ++ void __iomem *rcc_base; ++ int ret = -ENOMEM; + +- base = of_iomap(np, 0); +- if (!base) { +- pr_err("%pOFn: unable to map resource", np); +- of_node_put(np); +- return; ++ rcc_base = of_iomap(dev_of_node(dev), 0); ++ if (!rcc_base) { ++ dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev)); ++ goto out; ++ } ++ ++ ret = stm32_rcc_init(dev, rcc_base, stm32mp1_match_data); ++ if (ret) ++ goto out; ++ ++ ret = stm32_rcc_init_pwr(dev, rcc_base); ++ ++out: ++ if (ret) { ++ if (rcc_base) ++ iounmap(rcc_base); ++ rcc_base = NULL; ++ ++ of_node_put(dev_of_node(dev)); ++ } ++ ++ return ret; ++} ++ ++/* ++ * RCC POWER ++ * ++ */ ++ ++struct reg { ++ u32 address; ++ u32 val; ++}; ++ ++/* This table lists the IPs for which CSLEEP is enabled */ ++static const struct reg lp_table[] = { ++ { 0xB04, 0x00000000 }, /* APB1 */ ++ { 0xB0C, 0x00000000 }, /* APB2 */ ++ { 0xB14, 0x00000800 }, /* APB3 */ ++ { 0x304, 0x00000000 }, /* APB4 */ ++ { 0xB1C, 0x00000000 }, /* AHB2 */ ++ { 0xB24, 0x00000000 }, /* AHB3 */ ++ { 0xB2C, 0x00000000 }, /* AHB4 */ ++ { 0x31C, 0x00000000 }, /* AHB6 */ ++ { 0xB34, 0x00000000 }, /* AXIM */ ++ { 0xB3C, 0x00000000 }, /* MLAHB */ ++}; ++ ++#define SMC(class, op, address, val)\ ++ ({\ ++ struct arm_smccc_res res;\ ++ arm_smccc_smc(class, op, address, val,\ ++ 0, 0, 0, 0, &res);\ ++ }) ++ ++#define STM32_SVC_RCC 0x82001000 ++#define STM32_WRITE 0x1 ++#define RCC_IRQ_FLAGS_MASK 0x110F1F ++ ++static irqreturn_t stm32mp1_rcc_irq_handler(int irq, void *sdata) ++{ ++ pr_info("RCC generic interrupt received\n"); ++ ++ /* clear interrupt flag */ ++ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction rcc_irq = { ++ .name = "rcc irq", ++ .flags = IRQF_ONESHOT, ++ .handler = stm32mp1_rcc_irq_handler, ++}; ++ ++static int stm32_rcc_init_pwr(struct device *dev, void __iomem *rcc_base) ++{ ++ int irq; ++ int ret; ++ int i; ++ ++ /* register generic irq */ ++ irq = of_irq_get(dev_of_node(dev), 0); ++ if (irq <= 0) { ++ pr_err("%s: failed to get RCC generic IRQ\n", __func__); ++ return irq ? irq : -ENXIO; + } + +- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { +- iounmap(base); +- of_node_put(np); ++ ret = setup_irq(irq, &rcc_irq); ++ if (ret) { ++ pr_err("%s: failed to register generic IRQ\n", __func__); ++ return ret; + } ++ ++ /* Configure LPEN static table */ ++ for (i = 0; i < ARRAY_SIZE(lp_table); i++) ++ writel_relaxed(lp_table[i].val, rcc_base + lp_table[i].address); ++ ++ return 0; ++} ++ ++static int get_clock_deps(struct device *dev) ++{ ++ const char *clock_deps_name[] = { ++ "hsi", "hse", "csi", "lsi", "lse", ++ }; ++ size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name); ++ struct clk **clk_deps; ++ int i; ++ ++ clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL); ++ if (!clk_deps) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) { ++ struct clk *clk = of_clk_get_by_name(dev_of_node(dev), ++ clock_deps_name[i]); ++ ++ if (IS_ERR(clk)) { ++ if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT) ++ return PTR_ERR(clk); ++ } else { ++ /* Device gets a reference count on the clock */ ++ clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); ++ clk_put(clk); ++ } ++ } ++ ++ return 0; + } + +-CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); ++static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ int ret = get_clock_deps(dev); ++ ++ if (!ret) ++ ret = stm32mp1_rcc_init(dev); ++ ++ return ret; ++} ++ ++static int stm32mp1_rcc_clocks_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *child, *np = dev_of_node(dev); ++ ++ for_each_available_child_of_node(np, child) ++ of_clk_del_provider(child); ++ ++ return 0; ++} ++ ++static struct platform_driver stm32mp1_rcc_clocks_driver = { ++ .driver = { ++ .name = "stm32mp1_rcc", ++ .of_match_table = stm32mp1_match_data, ++ }, ++ .probe = stm32mp1_rcc_clocks_probe, ++ .remove = stm32mp1_rcc_clocks_remove, ++}; ++ ++static int __init stm32mp1_clocks_init(void) ++{ ++ return platform_driver_register(&stm32mp1_rcc_clocks_driver); ++} ++core_initcall(stm32mp1_clocks_init); +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 62d0fc486..815067c28 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -1713,6 +1713,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) + core->parent = new_parent; + } + ++static const struct clk_ops clk_nodrv_ops; + static struct clk_core *__clk_set_parent_before(struct clk_core *core, + struct clk_core *parent) + { +@@ -1741,7 +1742,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core, + + /* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */ + if (core->flags & CLK_OPS_PARENT_ENABLE) { +- clk_core_prepare_enable(old_parent); ++ if (old_parent && old_parent->ops != &clk_nodrv_ops) ++ clk_core_prepare_enable(old_parent); + clk_core_prepare_enable(parent); + } + +@@ -1775,7 +1777,8 @@ static void __clk_set_parent_after(struct clk_core *core, + /* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */ + if (core->flags & CLK_OPS_PARENT_ENABLE) { + clk_core_disable_unprepare(parent); +- clk_core_disable_unprepare(old_parent); ++ if (old_parent && old_parent->ops != &clk_nodrv_ops) ++ clk_core_disable_unprepare(old_parent); + } + } + +diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c +index bbc930a59..28b63645c 100644 +--- a/drivers/counter/stm32-lptimer-cnt.c ++++ b/drivers/counter/stm32-lptimer-cnt.c +@@ -347,7 +347,7 @@ static const struct iio_chan_spec stm32_lptim_cnt_channels = { + }; + + /** +- * stm32_lptim_cnt_function - enumerates stm32 LPTimer counter & encoder modes ++ * enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes + * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges + * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) + */ +diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c +index 644ba18a7..6c51ff2cf 100644 +--- a/drivers/counter/stm32-timer-cnt.c ++++ b/drivers/counter/stm32-timer-cnt.c +@@ -8,10 +8,10 @@ + * + */ + #include +-#include +-#include + #include ++#include + #include ++#include + #include + + #define TIM_CCMR_CCXS (BIT(8) | BIT(0)) +@@ -20,15 +20,24 @@ + #define TIM_CCER_MASK (TIM_CCER_CC1P | TIM_CCER_CC1NP | \ + TIM_CCER_CC2P | TIM_CCER_CC2NP) + ++struct stm32_timer_regs { ++ u32 cr1; ++ u32 cnt; ++ u32 smcr; ++ u32 arr; ++}; ++ + struct stm32_timer_cnt { + struct counter_device counter; + struct regmap *regmap; + struct clk *clk; + u32 ceiling; ++ bool enabled; ++ struct stm32_timer_regs bak; + }; + + /** +- * stm32_count_function - enumerates stm32 timer counter encoder modes ++ * enum stm32_count_function - enumerates stm32 timer counter encoder modes + * @STM32_COUNT_SLAVE_MODE_DISABLED: counts on internal clock when CEN=1 + * @STM32_COUNT_ENCODER_MODE_1: counts TI1FP1 edges, depending on TI2FP2 level + * @STM32_COUNT_ENCODER_MODE_2: counts TI2FP2 edges, depending on TI1FP1 level +@@ -231,6 +240,9 @@ static ssize_t stm32_count_enable_write(struct counter_device *counter, + clk_disable(priv->clk); + } + ++ /* Keep enabled state to properly handle low power states */ ++ priv->enabled = enable; ++ + return len; + } + +@@ -365,10 +377,59 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) + priv->counter.num_signals = ARRAY_SIZE(stm32_signals); + priv->counter.priv = priv; + ++ platform_set_drvdata(pdev, priv); ++ + /* Register Counter device */ + return devm_counter_register(dev, &priv->counter); + } + ++static int __maybe_unused stm32_timer_cnt_suspend(struct device *dev) ++{ ++ struct stm32_timer_cnt *priv = dev_get_drvdata(dev); ++ ++ /* Only take care of enabled counter: don't disturb other MFD child */ ++ if (priv->enabled) { ++ /* Backup registers that may get lost in low power mode */ ++ regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr); ++ regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr); ++ regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt); ++ regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1); ++ ++ /* Disable the counter */ ++ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); ++ clk_disable(priv->clk); ++ } ++ ++ return pinctrl_pm_select_sleep_state(dev); ++} ++ ++static int __maybe_unused stm32_timer_cnt_resume(struct device *dev) ++{ ++ struct stm32_timer_cnt *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pinctrl_pm_select_default_state(dev); ++ if (ret) ++ return ret; ++ ++ if (priv->enabled) { ++ clk_enable(priv->clk); ++ ++ /* Restore registers that may have been lost */ ++ regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr); ++ regmap_write(priv->regmap, TIM_ARR, priv->bak.arr); ++ regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt); ++ ++ /* Also re-enables the counter */ ++ regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1); ++ } ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(stm32_timer_cnt_pm_ops, stm32_timer_cnt_suspend, ++ stm32_timer_cnt_resume); ++ + static const struct of_device_id stm32_timer_cnt_of_match[] = { + { .compatible = "st,stm32-timer-counter", }, + {}, +@@ -380,6 +441,7 @@ static struct platform_driver stm32_timer_cnt_driver = { + .driver = { + .name = "stm32-timer-counter", + .of_match_table = stm32_timer_cnt_of_match, ++ .pm = &stm32_timer_cnt_pm_ops, + }, + }; + module_platform_driver(stm32_timer_cnt_driver); +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch similarity index 72% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch index b4c389c..3088f33 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch @@ -1,24 +1,110 @@ -From ba9b118a08bddb954d75f84134705c9c28673128 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:39 +0100 -Subject: [PATCH 06/31] ARM stm32mp1 r3 DMA +From ec7780453caf21817873becfdb8efb2a99cad0d5 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:40:57 +0200 +Subject: [PATCH 06/23] ARM-stm32mp1-r1-DMA --- - drivers/dma/dmaengine.c | 35 ++ - drivers/dma/stm32-dma.c | 1164 ++++++++++++++++++++++++++++++++++++++------ - drivers/dma/stm32-dmamux.c | 110 ++++- - drivers/dma/stm32-mdma.c | 234 ++++++++- - include/linux/dmaengine.h | 11 + - 5 files changed, 1358 insertions(+), 196 deletions(-) + drivers/dma/dmaengine.c | 113 +++- + drivers/dma/stm32-dma.c | 1118 +++++++++++++++++++++++++++++++----- + drivers/dma/stm32-dmamux.c | 95 ++- + drivers/dma/stm32-mdma.c | 273 +++++++-- + include/linux/dmaengine.h | 18 + + 5 files changed, 1379 insertions(+), 238 deletions(-) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c -index f1a441ab..48483ab 100644 +index 4b604086b..3db3f8e36 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c -@@ -737,6 +737,34 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) - EXPORT_SYMBOL_GPL(dma_request_chan); +@@ -58,6 +58,65 @@ static DEFINE_IDA(dma_ida); + static LIST_HEAD(dma_device_list); + static long dmaengine_ref_count; + ++/* --- debugfs implementation --- */ ++#ifdef CONFIG_DEBUG_FS ++#include ++ ++static void dmaengine_dbg_summary_show(struct seq_file *s, ++ struct dma_device *dma_dev) ++{ ++ struct dma_chan *chan; ++ ++ list_for_each_entry(chan, &dma_dev->channels, device_node) { ++ if (chan->client_count) { ++ seq_printf(s, " %-13s| %s", dma_chan_name(chan), ++ chan->dbg_client_name ?: "in-use"); ++ ++ if (chan->router) ++ seq_printf(s, " (via router: %s)\n", ++ dev_name(chan->router->dev)); ++ else ++ seq_puts(s, "\n"); ++ } ++ } ++} ++ ++static int dmaengine_summary_show(struct seq_file *s, void *data) ++{ ++ struct dma_device *dma_dev = NULL; ++ ++ mutex_lock(&dma_list_mutex); ++ list_for_each_entry(dma_dev, &dma_device_list, global_node) { ++ seq_printf(s, "dma%d (%s): number of channels: %u\n", ++ dma_dev->dev_id, dev_name(dma_dev->dev), ++ dma_dev->chancnt); ++ ++ if (dma_dev->dbg_summary_show) ++ dma_dev->dbg_summary_show(s, dma_dev); ++ else ++ dmaengine_dbg_summary_show(s, dma_dev); ++ ++ if (!list_is_last(&dma_dev->global_node, &dma_device_list)) ++ seq_puts(s, "\n"); ++ } ++ mutex_unlock(&dma_list_mutex); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(dmaengine_summary); ++ ++static void __init dmaengine_debugfs_init(void) ++{ ++ struct dentry *rootdir = debugfs_create_dir("dmaengine", NULL); ++ ++ /* /sys/kernel/debug/dmaengine/summary */ ++ debugfs_create_file("summary", 0444, rootdir, NULL, ++ &dmaengine_summary_fops); ++} ++#else ++static inline void dmaengine_debugfs_init(void) { } ++#endif /* DEBUG_FS */ ++ + /* --- sysfs implementation --- */ /** +@@ -707,7 +766,7 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) + if (chan) { + /* Valid channel found or requester needs to be deferred */ + if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) +- return chan; ++ goto found; + } + + /* Try to find the channel via the DMA filter map(s) */ +@@ -728,10 +787,44 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) + } + mutex_unlock(&dma_list_mutex); + ++found: ++#ifdef CONFIG_DEBUG_FS ++ if (!IS_ERR_OR_NULL(chan)) ++ chan->dbg_client_name = kasprintf(GFP_KERNEL, "%s:%s", ++ dev_name(dev), name); ++#endif + return chan ? chan : ERR_PTR(-EPROBE_DEFER); + } + EXPORT_SYMBOL_GPL(dma_request_chan); + ++/** + * dma_request_chan_linked - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name @@ -46,11 +132,18 @@ index f1a441ab..48483ab 100644 +} +EXPORT_SYMBOL_GPL(dma_request_chan_linked); + -+/** + /** * dma_request_slave_channel - try to allocate an exclusive slave channel * @dev: pointer to client device structure - * @name: slave channel name -@@ -794,6 +822,13 @@ void dma_release_channel(struct dma_chan *chan) +@@ -786,10 +879,21 @@ void dma_release_channel(struct dma_chan *chan) + /* drop PRIVATE cap enabled by __dma_request_channel() */ + if (--chan->device->privatecnt == 0) + dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask); ++#ifdef CONFIG_DEBUG_FS ++ kfree(chan->dbg_client_name); ++ chan->dbg_client_name = NULL; ++#endif + mutex_unlock(&dma_list_mutex); } EXPORT_SYMBOL_GPL(dma_release_channel); @@ -64,11 +157,25 @@ index f1a441ab..48483ab 100644 /** * dmaengine_get - register interest in dma_channels */ +@@ -1372,7 +1476,12 @@ static int __init dma_bus_init(void) + + if (err) + return err; +- return class_register(&dma_devclass); ++ ++ err = class_register(&dma_devclass); ++ if (!err) ++ dmaengine_debugfs_init(); ++ ++ return err; + } + arch_initcall(dma_bus_init); + diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 4903a40..810420a 100644 +index 5989b0893..9ebcaadf4 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c -@@ -15,14 +15,18 @@ +@@ -14,11 +14,14 @@ #include #include #include @@ -83,11 +190,7 @@ index 4903a40..810420a 100644 #include #include #include -+#include - #include - #include - #include -@@ -116,8 +120,10 @@ +@@ -116,8 +119,10 @@ #define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01 #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02 #define STM32_DMA_FIFO_THRESHOLD_FULL 0x03 @@ -98,23 +201,23 @@ index 4903a40..810420a 100644 /* * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter * gather at boundary. Thus it's safer to round down this value on FIFO -@@ -135,6 +141,15 @@ +@@ -135,6 +140,15 @@ /* DMA Features */ #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) #define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK) -+#define STM32_DMA_MDMA_CHAIN_FTR_MASK BIT(2) -+#define STM32_DMA_MDMA_CHAIN_FTR_GET(n) (((n) & STM32_DMA_MDMA_CHAIN_FTR_MASK) \ -+ >> 2) -+#define STM32_DMA_MDMA_SRAM_SIZE_MASK GENMASK(4, 3) -+#define STM32_DMA_MDMA_SRAM_SIZE_GET(n) (((n) & STM32_DMA_MDMA_SRAM_SIZE_MASK) \ -+ >> 3) -+#define STM32_DMA_DIRECT_MODE_MASK BIT(5) ++#define STM32_DMA_DIRECT_MODE_MASK BIT(2) +#define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) \ -+ >> 5) ++ >> 2) ++#define STM32_DMA_MDMA_CHAIN_FTR_MASK BIT(31) ++#define STM32_DMA_MDMA_CHAIN_FTR_GET(n) (((n) & STM32_DMA_MDMA_CHAIN_FTR_MASK) \ ++ >> 31) ++#define STM32_DMA_MDMA_SRAM_SIZE_MASK GENMASK(30, 29) ++#define STM32_DMA_MDMA_SRAM_SIZE_GET(n) (((n) & STM32_DMA_MDMA_SRAM_SIZE_MASK) \ ++ >> 29) enum stm32_dma_width { STM32_DMA_BYTE, -@@ -176,15 +191,32 @@ struct stm32_dma_chan_reg { +@@ -176,15 +190,32 @@ struct stm32_dma_chan_reg { u32 dma_sfcr; }; @@ -148,7 +251,7 @@ index 4903a40..810420a 100644 struct stm32_dma_sg_req sg_req[]; }; -@@ -201,6 +233,10 @@ struct stm32_dma_chan { +@@ -201,15 +232,19 @@ struct stm32_dma_chan { u32 threshold; u32 mem_burst; u32 mem_width; @@ -159,15 +262,35 @@ index 4903a40..810420a 100644 }; struct stm32_dma_device { -@@ -210,6 +246,7 @@ struct stm32_dma_device { - struct reset_control *rst; + struct dma_device ddev; + void __iomem *base; + struct clk *clk; +- struct reset_control *rst; bool mem2mem; struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; + struct gen_pool *sram_pool; }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -287,6 +324,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -260,6 +295,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, + } + + static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, ++ dma_addr_t buf_addr, + u32 threshold) + { + enum dma_slave_buswidth max_width; +@@ -273,6 +309,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, + max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) + max_width = max_width >> 1; + ++ if (buf_addr % max_width) ++ max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ + return max_width; + } + +@@ -281,6 +320,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, { u32 remaining; @@ -177,7 +300,7 @@ index 4903a40..810420a 100644 if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { if (burst != 0) { /* -@@ -308,6 +348,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -302,6 +344,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) { @@ -188,24 +311,30 @@ index 4903a40..810420a 100644 /* * Buffer or period length has to be aligned on FIFO depth. * Otherwise bytes may be stuck within FIFO at buffer or period -@@ -428,7 +472,6 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) +@@ -422,29 +468,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) { struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); - unsigned long timeout = jiffies + msecs_to_jiffies(5000); - u32 dma_scr, id; +- u32 dma_scr, id; ++ u32 dma_scr, id, reg; id = chan->id; -@@ -438,19 +481,10 @@ static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) - dma_scr &= ~STM32_DMA_SCR_EN; - stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); +- dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); ++ reg = STM32_DMA_SCR(id); ++ dma_scr = stm32_dma_read(dmadev, reg); + if (dma_scr & STM32_DMA_SCR_EN) { + dma_scr &= ~STM32_DMA_SCR_EN; +- stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); +- - do { - dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); - dma_scr &= STM32_DMA_SCR_EN; - if (!dma_scr) - break; -- ++ stm32_dma_write(dmadev, reg, dma_scr); + - if (time_after_eq(jiffies, timeout)) { - dev_err(chan2dev(chan), "%s: timeout!\n", - __func__); @@ -213,14 +342,13 @@ index 4903a40..810420a 100644 - } - cond_resched(); - } while (1); -+ return readl_relaxed_poll_timeout_atomic( -+ dmadev->base + STM32_DMA_SCR(id), ++ return readl_relaxed_poll_timeout_atomic(dmadev->base + reg, + dma_scr, !(dma_scr & STM32_DMA_SCR_EN), + 10, 1000000); } return 0; -@@ -489,13 +523,23 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -483,13 +519,22 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) static int stm32_dma_terminate_all(struct dma_chan *c) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -229,9 +357,6 @@ index 4903a40..810420a 100644 LIST_HEAD(head); - spin_lock_irqsave(&chan->vchan.lock, flags); - -- if (chan->busy) { -- stm32_dma_stop(chan); + if (chan->use_mdma) { + spin_lock_irqsave_nested(&chan->vchan.lock, flags, + SINGLE_DEPTH_NESTING); @@ -239,7 +364,9 @@ index 4903a40..810420a 100644 + } else { + spin_lock_irqsave(&chan->vchan.lock, flags); + } -+ + +- if (chan->busy) { +- stm32_dma_stop(chan); + if (chan->desc) { + vchan_terminate_vdesc(&chan->desc->vdesc); + if (chan->busy) @@ -247,7 +374,7 @@ index 4903a40..810420a 100644 chan->desc = NULL; } -@@ -506,9 +550,96 @@ static int stm32_dma_terminate_all(struct dma_chan *c) +@@ -500,9 +545,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -274,6 +401,7 @@ index 4903a40..810420a 100644 + u32 mdma_residue, mdma_wrote, dma_to_write, len; + struct dma_tx_state state; + int ret; ++ unsigned long flags; + + /* DMA/MDMA chain: drain remaining data in SRAM */ + @@ -295,11 +423,16 @@ index 4903a40..810420a 100644 + /* Remaining data stuck in SRAM */ + dma_to_write = mchan->sram_period - stm32_dma_get_remaining_bytes(chan); + if (dma_to_write > 0) { ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, ++ SINGLE_DEPTH_NESTING); ++ ++ /* Terminate current MDMA to initiate a new one */ ++ dmaengine_terminate_async(mchan->chan); ++ + /* Stop DMA current operation */ + stm32_dma_disable_chan(chan); + -+ /* Terminate current MDMA to initiate a new one */ -+ dmaengine_terminate_all(mchan->chan); ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); + + /* Double buffer management */ + src_buf = mchan->sram_buf + @@ -320,7 +453,8 @@ index 4903a40..810420a 100644 + + status = dma_wait_for_async_tx(desc); + if (status != DMA_COMPLETE) { -+ dev_err(chan2dev(chan), "flush() dma_wait_for_async_tx error\n"); ++ dev_err(chan2dev(chan), ++ "%s dma_wait_for_async_tx error\n", __func__); + dmaengine_terminate_async(mchan->chan); + return -EBUSY; + } @@ -344,17 +478,14 @@ index 4903a40..810420a 100644 vchan_synchronize(&chan->vchan); } -@@ -531,62 +662,205 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -525,62 +664,213 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } -static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan); -- --static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) +static int stm32_dma_dummy_memcpy_xfer(struct stm32_dma_chan *chan) - { - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -- struct virt_dma_desc *vdesc; ++{ ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct dma_device *ddev = &dmadev->ddev; + struct stm32_dma_chan_reg reg; + u8 src_buf, dst_buf; @@ -372,7 +503,8 @@ index 4903a40..810420a 100644 + dev_err(chan2dev(chan), "Source buffer map failed\n"); + return ret; + } -+ + +-static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) + dma_dst_buf = dma_map_single(ddev->dev, &dst_buf, len, DMA_FROM_DEVICE); + ret = dma_mapping_error(ddev->dev, dma_dst_buf); + if (ret < 0) { @@ -435,7 +567,9 @@ index 4903a40..810420a 100644 +} + +static int stm32_dma_mdma_flush_remaining(struct stm32_dma_chan *chan) -+{ + { + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); +- struct virt_dma_desc *vdesc; + struct stm32_dma_mdma *mchan = &chan->mchan; struct stm32_dma_sg_req *sg_req; - struct stm32_dma_chan_reg *reg; @@ -444,26 +578,29 @@ index 4903a40..810420a 100644 + struct dma_async_tx_descriptor *desc = NULL; + enum dma_status status; + dma_addr_t src_buf, dst_buf; -+ u32 residue, remain, len; ++ u32 residue, remain, len, dma_scr; int ret; - ret = stm32_dma_disable_chan(chan); - if (ret < 0) - return; -+ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; ++ residue = stm32_dma_get_remaining_bytes(chan); ++ if (!residue) ++ return 0; - if (!chan->desc) { - vdesc = vchan_next_desc(&chan->vchan); - if (!vdesc) - return; -+ residue = stm32_dma_get_remaining_bytes(chan); ++ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); ++ if (!(dma_scr & STM32_DMA_SCR_EN)) ++ return -EPERM; ++ ++ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; + len = sg_dma_len(&sg_req->stm32_sgl_req); + remain = len % mchan->sram_period; - -- chan->desc = to_stm32_dma_desc(vdesc); -- chan->next_sg = 0; -+ if (residue > 0 && len > mchan->sram_period && -+ ((len % mchan->sram_period) != 0)) { ++ ++ if (len > mchan->sram_period && ((len % mchan->sram_period) != 0)) { + unsigned long dma_sync_wait_timeout = + jiffies + msecs_to_jiffies(5000); + @@ -471,15 +608,17 @@ index 4903a40..810420a 100644 + residue > (mchan->sram_period - remain)) { + if (time_after_eq(jiffies, dma_sync_wait_timeout)) { + dev_err(chan2dev(chan), -+ "%s timeout waiting for last bytes\n", -+ __func__); ++ "%s timeout pending last %d bytes\n", ++ __func__, residue); + return -EBUSY; + } + cpu_relax(); + residue = stm32_dma_get_remaining_bytes(chan); + } + stm32_dma_disable_chan(chan); -+ + +- chan->desc = to_stm32_dma_desc(vdesc); +- chan->next_sg = 0; + src_buf = mchan->sram_buf + ((len / mchan->sram_period) & 0x1) + * mchan->sram_period; + dst_buf = sg_dma_address(&sg_req->stm32_sgl_req) + len - @@ -523,12 +662,14 @@ index 4903a40..810420a 100644 + const struct dmaengine_result *result) +{ + struct stm32_dma_chan *chan = param; ++ int ret; - chan->next_sg++; + chan->busy = false; + if (result->result == DMA_TRANS_NOERROR) { -+ if (stm32_dma_mdma_flush_remaining(chan)) { -+ dev_err(chan2dev(chan), "Can't flush DMA\n"); ++ ret = stm32_dma_mdma_flush_remaining(chan); ++ if (ret) { ++ dev_err(chan2dev(chan), "Can't flush DMA: %d\n", ret); + return; + } @@ -588,7 +729,7 @@ index 4903a40..810420a 100644 } static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) -@@ -618,35 +892,147 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) +@@ -612,23 +902,134 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) } } @@ -734,30 +875,16 @@ index 4903a40..810420a 100644 } static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) - { - struct stm32_dma_chan *chan = devid; - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -- u32 status, scr; -+ u32 status, scr, sfcr; - - spin_lock(&chan->vchan.lock); - - status = stm32_dma_irq_status(chan); +@@ -643,26 +1044,37 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); -+ sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); + sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); - if (status & STM32_DMA_TCI) { - stm32_dma_irq_clear(chan, STM32_DMA_TCI); -@@ -661,10 +1047,19 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) - if (status & STM32_DMA_FEI) { - stm32_dma_irq_clear(chan, STM32_DMA_FEI); - status &= ~STM32_DMA_FEI; -- if (!(scr & STM32_DMA_SCR_EN)) -- dev_err(chan2dev(chan), "FIFO Error\n"); -- else -- dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); ++ if (status & STM32_DMA_FEI) { ++ stm32_dma_irq_clear(chan, STM32_DMA_FEI); ++ status &= ~STM32_DMA_FEI; + if (sfcr & STM32_DMA_SFCR_FEIE) { -+ if (!(scr & STM32_DMA_SCR_EN)) ++ if (!(scr & STM32_DMA_SCR_EN) && ++ !(status & STM32_DMA_TCI)) + dev_err(chan2dev(chan), "FIFO Error\n"); + else + dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); @@ -769,10 +896,34 @@ index 4903a40..810420a 100644 + if (sfcr & STM32_DMA_SCR_DMEIE) { + dev_dbg(chan2dev(chan), "Direct mode overrun\n"); + } ++ } ++ + if (status & STM32_DMA_TCI) { + stm32_dma_irq_clear(chan, STM32_DMA_TCI); + if (scr & STM32_DMA_SCR_TCIE) + stm32_dma_handle_chan_done(chan); + status &= ~STM32_DMA_TCI; } ++ + if (status & STM32_DMA_HTI) { + stm32_dma_irq_clear(chan, STM32_DMA_HTI); + status &= ~STM32_DMA_HTI; + } +- if (status & STM32_DMA_FEI) { +- stm32_dma_irq_clear(chan, STM32_DMA_FEI); +- status &= ~STM32_DMA_FEI; +- if (sfcr & STM32_DMA_SFCR_FEIE) { +- if (!(scr & STM32_DMA_SCR_EN)) +- dev_err(chan2dev(chan), "FIFO Error\n"); +- else +- dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); +- } +- } ++ if (status) { stm32_dma_irq_clear(chan, status); -@@ -683,12 +1078,17 @@ static void stm32_dma_issue_pending(struct dma_chan *c) + dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); +@@ -680,31 +1092,37 @@ static void stm32_dma_issue_pending(struct dma_chan *c) struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; @@ -786,13 +937,19 @@ index 4903a40..810420a 100644 if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) { dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan); stm32_dma_start_transfer(chan); -- + } + spin_unlock_irqrestore(&chan->vchan.lock, flags); } -@@ -701,13 +1101,13 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + enum dma_transfer_direction direction, + enum dma_slave_buswidth *buswidth, +- u32 buf_len) ++ u32 buf_len, dma_addr_t buf_addr) + { + enum dma_slave_buswidth src_addr_width, dst_addr_width; int src_bus_width, dst_bus_width; int src_burst_size, dst_burst_size; u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst; @@ -808,7 +965,7 @@ index 4903a40..810420a 100644 switch (direction) { case DMA_MEM_TO_DEV: -@@ -719,7 +1119,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -716,7 +1134,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, /* Set device burst size */ dst_best_burst = stm32_dma_get_best_burst(buf_len, dst_maxburst, @@ -817,16 +974,17 @@ index 4903a40..810420a 100644 dst_addr_width); dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); -@@ -727,7 +1127,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -724,7 +1142,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return dst_burst_size; /* Set memory data size */ - src_addr_width = stm32_dma_get_max_width(buf_len, threshold); -+ src_addr_width = stm32_dma_get_max_width(buf_len, fifoth); ++ src_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, ++ fifoth); chan->mem_width = src_addr_width; src_bus_width = stm32_dma_get_width(chan, src_addr_width); if (src_bus_width < 0) -@@ -737,7 +1137,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -734,7 +1153,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, src_maxburst = STM32_DMA_MAX_BURST; src_best_burst = stm32_dma_get_best_burst(buf_len, src_maxburst, @@ -835,7 +993,7 @@ index 4903a40..810420a 100644 src_addr_width); src_burst_size = stm32_dma_get_burst(chan, src_best_burst); if (src_burst_size < 0) -@@ -751,7 +1151,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -748,7 +1167,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, /* Set FIFO threshold */ chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; @@ -845,7 +1003,7 @@ index 4903a40..810420a 100644 /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; -@@ -767,7 +1168,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -764,7 +1184,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, /* Set device burst size */ src_best_burst = stm32_dma_get_best_burst(buf_len, src_maxburst, @@ -854,16 +1012,17 @@ index 4903a40..810420a 100644 src_addr_width); chan->mem_burst = src_best_burst; src_burst_size = stm32_dma_get_burst(chan, src_best_burst); -@@ -775,7 +1176,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -772,7 +1192,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return src_burst_size; /* Set memory data size */ - dst_addr_width = stm32_dma_get_max_width(buf_len, threshold); -+ dst_addr_width = stm32_dma_get_max_width(buf_len, fifoth); ++ dst_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, ++ fifoth); chan->mem_width = dst_addr_width; dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); if (dst_bus_width < 0) -@@ -785,7 +1186,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -782,7 +1203,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, dst_maxburst = STM32_DMA_MAX_BURST; dst_best_burst = stm32_dma_get_best_burst(buf_len, dst_maxburst, @@ -872,7 +1031,7 @@ index 4903a40..810420a 100644 dst_addr_width); chan->mem_burst = dst_best_burst; dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); -@@ -800,7 +1201,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -797,7 +1218,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, /* Set FIFO threshold */ chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; @@ -882,7 +1041,7 @@ index 4903a40..810420a 100644 /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; -@@ -828,16 +1230,169 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) +@@ -825,6 +1247,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } @@ -1014,7 +1173,8 @@ index 4903a40..810420a 100644 + + for_each_sg(sgl, sg, sg_len, i) { + ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, -+ sg_dma_len(sg)); ++ sg_dma_len(sg), ++ sg_dma_address(sg)); + if (ret < 0) + return ret; + @@ -1044,10 +1204,9 @@ index 4903a40..810420a 100644 static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, u32 sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) +@@ -832,9 +1410,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); -+ struct stm32_dma_desc *desc; - struct scatterlist *sg; - enum dma_slave_buswidth buswidth; @@ -1055,7 +1214,7 @@ index 4903a40..810420a 100644 int i, ret; if (!chan->config_init) { -@@ -860,48 +1415,141 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -857,48 +1432,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1129,7 +1288,6 @@ index 4903a40..810420a 100644 + desc->dma_buf_size); + } kfree(desc); -+ return NULL; } @@ -1217,7 +1375,17 @@ index 4903a40..810420a 100644 int i, ret; if (!buf_len || !period_len) { -@@ -949,28 +1597,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -927,7 +1594,8 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( + return NULL; + } + +- ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len); ++ ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len, ++ buf_addr); + if (ret < 0) + return NULL; + +@@ -946,28 +1614,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( /* Clear periph ctrl if client set it */ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1227,7 +1395,7 @@ index 4903a40..810420a 100644 + else + num_periods = buf_len / period_len; - desc = stm32_dma_alloc_desc(num_periods); + desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT); if (!desc) return NULL; @@ -1235,10 +1403,10 @@ index 4903a40..810420a 100644 - desc->sg_req[i].len = period_len; + desc->num_sgs = num_periods; + desc->cyclic = true; - ++ + if (chan->use_mdma) { + chan->mchan.dir = direction; -+ + + ret = stm32_dma_mdma_prep_dma_cyclic(chan, buf_addr, buf_len, + period_len, desc); + if (ret < 0) @@ -1279,7 +1447,7 @@ index 4903a40..810420a 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1011,13 +1680,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1008,13 +1697,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1295,108 +1463,55 @@ index 4903a40..810420a 100644 } desc->num_sgs = num_sgs; -@@ -1026,16 +1695,28 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1023,18 +1712,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) -+static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) - { +-{ - u32 dma_scr, width, ndtr; - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -+ struct stm32_dma_sg_req *sg_req; -+ u32 dma_scr, dma_smar, id; - +- struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); +- - dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); - width = STM32_DMA_SCR_PSIZE_GET(dma_scr); - ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); -+ id = chan->id; -+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); - +- - return ndtr << width; -+ if (!(dma_scr & STM32_DMA_SCR_DBM)) -+ return true; -+ -+ sg_req = &chan->desc->sg_req[chan->next_sg]; -+ -+ if (dma_scr & STM32_DMA_SCR_CT) { -+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)); -+ return (dma_smar == sg_req->chan_reg.dma_sm0ar); -+ } -+ -+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)); -+ -+ return (dma_smar == sg_req->chan_reg.dma_sm1ar); - } - - static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, -@@ -1043,28 +1724,52 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, - u32 next_sg) - { - u32 modulo, burst_size; -- u32 residue = 0; -+ u32 residue; -+ u32 n_sg = next_sg; -+ struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; +-} +- + /** + * stm32_dma_is_current_sg - check that expected sg_req is currently transferred + * @chan: dma channel +@@ -1081,6 +1758,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, + struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; int i; + /* Drain case */ + if (chan->residue_after_drain) + return chan->residue_after_drain; -+ -+ residue = stm32_dma_get_remaining_bytes(chan); + /* -- * In cyclic mode, for the last period, residue = remaining bytes from -- * NDTR -+ * Calculate the residue means compute the descriptors -+ * information: -+ * - the sg currently transferred -+ * - the remaining position in this sg (NDTR). -+ * -+ * The issue is that a race condition can occur if DMA is -+ * running. DMA can have started to transfer the next sg before -+ * the position in sg is read. In this case the remaing position -+ * can correspond to the new sg position. -+ * The strategy implemented in the stm32 driver is to check the -+ * sg transition. If detected we can not trust the SxNDTR register value -+ * this register can not be up to date during the transition. -+ * in this case we can assume that the dma is at the beginning of next -+ * sg so we calculate the residue in consequence. - */ -- if (chan->desc->cyclic && next_sg == 0) { -- residue = stm32_dma_get_remaining_bytes(chan); -- goto end; -+ -+ if (!stm32_dma_is_current_sg(chan)) { -+ n_sg++; -+ if (n_sg == chan->desc->num_sgs) -+ n_sg = 0; + * Calculate the residue means compute the descriptors + * information: +@@ -1112,7 +1793,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, + n_sg++; + if (n_sg == chan->desc->num_sgs) + n_sg = 0; +- residue = sg_req->len; + residue = sg_dma_len(&sg_req->stm32_sgl_req); } /* -- * For all other periods in cyclic mode, and in sg mode, -- * residue = remaining bytes from NDTR + remaining periods/sg to be -- * transferred -+ * In cyclic mode, for the last period, residue = remaining bytes -+ * from NDTR -+ * else for all other periods in cyclic mode, and in sg mode, -+ * residue = remaining bytes from NDTR + remaining -+ * periods/sg to be transferred +@@ -1124,7 +1805,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, */ -- for (i = next_sg; i < desc->num_sgs; i++) -- residue += desc->sg_req[i].len; -- residue += stm32_dma_get_remaining_bytes(chan); -+ if (!chan->desc->cyclic || n_sg != 0) -+ for (i = n_sg; i < desc->num_sgs; i++) + if (!chan->desc->cyclic || n_sg != 0) + for (i = n_sg; i < desc->num_sgs; i++) +- residue += desc->sg_req[i].len; + residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req); --end: if (!chan->mem_burst) return residue; - -@@ -1081,11 +1786,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, +@@ -1142,11 +1823,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, struct dma_tx_state *state) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -1420,34 +1535,14 @@ index 4903a40..810420a 100644 status = dma_cookie_status(c, cookie, state); if (status == DMA_COMPLETE || !state) return status; -@@ -1112,15 +1829,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) - int ret; - - chan->config_init = false; -- ret = clk_prepare_enable(dmadev->clk); -- if (ret < 0) { -- dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret); -+ -+ ret = pm_runtime_get_sync(dmadev->ddev.dev); -+ if (ret < 0) - return ret; -- } - - ret = stm32_dma_disable_chan(chan); - if (ret < 0) -- clk_disable_unprepare(dmadev->clk); -+ pm_runtime_put(dmadev->ddev.dev); - - return ret; - } -@@ -1140,28 +1856,50 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) - spin_unlock_irqrestore(&chan->vchan.lock, flags); - } - -- clk_disable_unprepare(dmadev->clk); -+ pm_runtime_put(dmadev->ddev.dev); +@@ -1203,25 +1896,51 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) + pm_runtime_put(dmadev->ddev.dev); vchan_free_chan_resources(to_virt_chan(c)); ++ stm32_dma_clear_reg(&chan->chan_reg); ++ chan->threshold = 0; ++ chan->use_mdma = false; ++ chan->sram_size = 0; } static void stm32_dma_desc_free(struct virt_dma_desc *vdesc) @@ -1497,7 +1592,7 @@ index 4903a40..810420a 100644 } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, -@@ -1199,6 +1937,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1259,6 +1978,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1507,7 +1602,7 @@ index 4903a40..810420a 100644 return c; } -@@ -1211,10 +1952,12 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1271,10 +1993,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1516,25 +1611,41 @@ index 4903a40..810420a 100644 struct dma_device *dd; const struct of_device_id *match; struct resource *res; ++ struct reset_control *rst; + char name[4]; int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1240,6 +1983,12 @@ static int stm32_dma_probe(struct platform_device *pdev) - return PTR_ERR(dmadev->clk); +@@ -1296,8 +2021,10 @@ static int stm32_dma_probe(struct platform_device *pdev) + + dmadev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dmadev->clk)) { +- dev_err(&pdev->dev, "Error: Missing controller clock\n"); +- return PTR_ERR(dmadev->clk); ++ ret = PTR_ERR(dmadev->clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Can't get clock\n"); ++ return ret; } -+ ret = clk_prepare_enable(dmadev->clk); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); -+ return ret; -+ } -+ + ret = clk_prepare_enable(dmadev->clk); +@@ -1309,13 +2036,26 @@ static int stm32_dma_probe(struct platform_device *pdev) dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, "st,mem2mem"); -@@ -1250,6 +1999,15 @@ static int stm32_dma_probe(struct platform_device *pdev) - reset_control_deassert(dmadev->rst); +- dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (!IS_ERR(dmadev->rst)) { +- reset_control_assert(dmadev->rst); ++ rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_clk; ++ } else { ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(dmadev->rst); ++ reset_control_deassert(rst); } + dmadev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); @@ -1549,7 +1660,7 @@ index 4903a40..810420a 100644 dma_cap_set(DMA_SLAVE, dd->cap_mask); dma_cap_set(DMA_PRIVATE, dd->cap_mask); dma_cap_set(DMA_CYCLIC, dd->cap_mask); -@@ -1270,7 +2028,9 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1336,7 +2076,9 @@ static int stm32_dma_probe(struct platform_device *pdev) BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; @@ -1559,7 +1670,7 @@ index 4903a40..810420a 100644 dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); -@@ -1285,21 +2045,34 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1351,11 +2093,27 @@ static int stm32_dma_probe(struct platform_device *pdev) chan->id = i; chan->vchan.desc_free = stm32_dma_desc_free; vchan_init(&chan->vchan, dd); @@ -1567,85 +1678,44 @@ index 4903a40..810420a 100644 + mchan = &chan->mchan; + if (dmadev->sram_pool) { + snprintf(name, sizeof(name), "ch%d", chan->id); -+ mchan->chan = dma_request_slave_channel(dd->dev, name); -+ if (!mchan->chan) ++ mchan->chan = dma_request_chan(dd->dev, name); ++ if (IS_ERR(mchan->chan)) { ++ ret = PTR_ERR(mchan->chan); ++ mchan->chan = NULL; ++ if (ret == -EPROBE_DEFER) ++ goto err_dma; ++ + dev_info(&pdev->dev, + "can't request MDMA chan for %s\n", + name); ++ } + } } ret = dma_async_device_register(dd); if (ret) -- return ret; -+ goto clk_free; +- goto clk_free; ++ goto err_dma; for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; -- res = platform_get_resource(pdev, IORESOURCE_IRQ, i); -- if (!res) { -- ret = -EINVAL; -- dev_err(&pdev->dev, "No irq resource for chan %d\n", i); -+ chan->irq = platform_get_irq(pdev, i); -+ ret = platform_get_irq(pdev, i); -+ if (ret < 0) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, -+ "No irq resource for chan %d\n", i); - goto err_unregister; - } -- chan->irq = res->start; -+ chan->irq = ret; -+ - ret = devm_request_irq(&pdev->dev, chan->irq, - stm32_dma_chan_irq, 0, - dev_name(chan2dev(chan)), chan); -@@ -1321,20 +2094,95 @@ static int stm32_dma_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, dmadev); - -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_put(&pdev->dev); -+ - dev_info(&pdev->dev, "STM32 DMA driver registered\n"); - - return 0; +@@ -1396,7 +2154,11 @@ static int stm32_dma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); -+clk_free: -+ clk_disable_unprepare(dmadev->clk); +-clk_free: ++err_dma: ++ for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) ++ if (dmadev->chan[i].mchan.chan) ++ dma_release_channel(dmadev->chan[i].mchan.chan); ++err_clk: + clk_disable_unprepare(dmadev->clk); return ret; +@@ -1427,7 +2189,44 @@ static int stm32_dma_runtime_resume(struct device *dev) } + #endif -+#ifdef CONFIG_PM -+static int stm32_dma_runtime_suspend(struct device *dev) -+{ -+ struct stm32_dma_device *dmadev = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(dmadev->clk); -+ -+ return 0; -+} -+ -+static int stm32_dma_runtime_resume(struct device *dev) -+{ -+ struct stm32_dma_device *dmadev = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_prepare_enable(dmadev->clk); -+ if (ret) { -+ dev_err(dev, "failed to prepare_enable clock\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ +#ifdef CONFIG_PM_SLEEP +static int stm32_dma_suspend(struct device *dev) +{ @@ -1682,39 +1752,36 @@ index 4903a40..810420a 100644 +} +#endif + -+static const struct dev_pm_ops stm32_dma_pm_ops = { + static const struct dev_pm_ops stm32_dma_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_suspend, stm32_dma_resume) -+ SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, -+ stm32_dma_runtime_resume, NULL) -+}; -+ - static struct platform_driver stm32_dma_driver = { - .driver = { - .name = "stm32-dma", + SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, + stm32_dma_runtime_resume, NULL) + }; +@@ -1438,10 +2237,11 @@ static struct platform_driver stm32_dma_driver = { .of_match_table = stm32_dma_of_match, -+ .pm = &stm32_dma_pm_ops, + .pm = &stm32_dma_pm_ops, }, ++ .probe = stm32_dma_probe, }; -@@ -1342,4 +2190,4 @@ static int __init stm32_dma_init(void) + static int __init stm32_dma_init(void) { - return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); +- return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); ++ return platform_driver_register(&stm32_dma_driver); } -subsys_initcall(stm32_dma_init); +device_initcall(stm32_dma_init); diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c -index b922db9..a878b7c 100644 +index 3c89bd39e..bbfa14100 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -51,6 +52,9 @@ struct stm32_dmamux_data { +@@ -35,12 +35,14 @@ struct stm32_dmamux { + struct stm32_dmamux_data { + struct dma_router dmarouter; + struct clk *clk; +- struct reset_control *rst; + void __iomem *iomem; + u32 dma_requests; /* Number of DMA requests connected to DMAMUX */ u32 dmamux_requests; /* Number of DMA requests routed toward DMAs */ spinlock_t lock; /* Protects register access */ unsigned long *dma_inuse; /* Used DMA channel */ @@ -1724,98 +1791,85 @@ index b922db9..a878b7c 100644 u32 dma_reqs[]; /* Number of DMA Request per DMA masters. * [0] holds number of DMA Masters. * To be kept at very end end of this structure -@@ -79,8 +83,7 @@ static void stm32_dmamux_free(struct device *dev, void *route_data) - stm32_dmamux_write(dmamux->iomem, STM32_DMAMUX_CCR(mux->chan_id), 0); - clear_bit(mux->chan_id, dmamux->dma_inuse); +@@ -179,6 +181,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) + struct stm32_dmamux_data *stm32_dmamux; + struct resource *res; + void __iomem *iomem; ++ struct reset_control *rst; + int i, count, ret; + u32 dma_req; -- if (!IS_ERR(dmamux->clk)) -- clk_disable(dmamux->clk); -+ pm_runtime_put_sync(dev); - - spin_unlock_irqrestore(&dmamux->lock, flags); - -@@ -146,13 +149,10 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, - - /* Set dma request */ - spin_lock_irqsave(&dmamux->lock, flags); -- if (!IS_ERR(dmamux->clk)) { -- ret = clk_enable(dmamux->clk); -- if (ret < 0) { -- spin_unlock_irqrestore(&dmamux->lock, flags); -- dev_err(&pdev->dev, "clk_prep_enable issue: %d\n", ret); -- goto error; -- } -+ ret = pm_runtime_get_sync(&pdev->dev); -+ if (ret < 0) { -+ spin_unlock_irqrestore(&dmamux->lock, flags); -+ goto error; - } - spin_unlock_irqrestore(&dmamux->lock, flags); - -@@ -254,6 +254,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) - dev_warn(&pdev->dev, "DMAMUX defaulting on %u requests\n", - stm32_dmamux->dmamux_requests); - } -+ pm_runtime_get_noresume(&pdev->dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap_resource(&pdev->dev, res); -@@ -282,6 +283,8 @@ static int stm32_dmamux_probe(struct platform_device *pdev) - stm32_dmamux->dmarouter.route_free = stm32_dmamux_free; - - platform_set_drvdata(pdev, stm32_dmamux); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); - - if (!IS_ERR(stm32_dmamux->clk)) { - ret = clk_prepare_enable(stm32_dmamux->clk); -@@ -291,17 +294,101 @@ static int stm32_dmamux_probe(struct platform_device *pdev) - } - } - -+ pm_runtime_get_noresume(&pdev->dev); -+ - /* Reset the dmamux */ - for (i = 0; i < stm32_dmamux->dma_requests; i++) - stm32_dmamux_write(stm32_dmamux->iomem, STM32_DMAMUX_CCR(i), 0); - -- if (!IS_ERR(stm32_dmamux->clk)) -- clk_disable(stm32_dmamux->clk); -+ pm_runtime_put(&pdev->dev); - - return of_dma_router_register(node, stm32_dmamux_route_allocate, - &stm32_dmamux->dmarouter); - } - -+#ifdef CONFIG_PM -+static int stm32_dmamux_runtime_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = -+ container_of(dev, struct platform_device, dev); -+ struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(stm32_dmamux->clk); -+ -+ return 0; -+} -+ -+static int stm32_dmamux_runtime_resume(struct device *dev) -+{ -+ struct platform_device *pdev = -+ container_of(dev, struct platform_device, dev); -+ struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev); -+ int ret; -+ -+ ret = clk_prepare_enable(stm32_dmamux->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to prepare_enable clock\n"); +@@ -251,16 +254,26 @@ static int stm32_dmamux_probe(struct platform_device *pdev) + stm32_dmamux->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(stm32_dmamux->clk)) { + ret = PTR_ERR(stm32_dmamux->clk); +- if (ret == -EPROBE_DEFER) +- dev_info(&pdev->dev, "Missing controller clock\n"); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Missing clock controller\n"); + return ret; + } + -+ return 0; -+} -+#endif ++ ret = clk_prepare_enable(stm32_dmamux->clk); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); + return ret; + } + +- stm32_dmamux->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (!IS_ERR(stm32_dmamux->rst)) { +- reset_control_assert(stm32_dmamux->rst); ++ rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_clk; ++ } else { ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(stm32_dmamux->rst); ++ reset_control_deassert(rst); + } + + stm32_dmamux->iomem = iomem; +@@ -271,14 +284,6 @@ static int stm32_dmamux_probe(struct platform_device *pdev) + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- if (!IS_ERR(stm32_dmamux->clk)) { +- ret = clk_prepare_enable(stm32_dmamux->clk); +- if (ret < 0) { +- dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); +- return ret; +- } +- } +- + pm_runtime_get_noresume(&pdev->dev); + + /* Reset the dmamux */ +@@ -287,8 +292,17 @@ static int stm32_dmamux_probe(struct platform_device *pdev) + + pm_runtime_put(&pdev->dev); + +- return of_dma_router_register(node, stm32_dmamux_route_allocate, ++ ret = of_dma_router_register(node, stm32_dmamux_route_allocate, + &stm32_dmamux->dmarouter); ++ if (ret) ++ goto err_clk; + ++ return 0; ++ ++err_clk: ++ clk_disable_unprepare(stm32_dmamux->clk); ++ ++ return ret; + } + + #ifdef CONFIG_PM +@@ -318,7 +332,56 @@ static int stm32_dmamux_runtime_resume(struct device *dev) + } + #endif + +#ifdef CONFIG_PM_SLEEP +static int stm32_dmamux_suspend(struct device *dev) +{ @@ -1864,36 +1918,16 @@ index b922db9..a878b7c 100644 +} +#endif + -+static const struct dev_pm_ops stm32_dmamux_pm_ops = { + static const struct dev_pm_ops stm32_dmamux_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_dmamux_suspend, stm32_dmamux_resume) -+ SET_RUNTIME_PM_OPS(stm32_dmamux_runtime_suspend, -+ stm32_dmamux_runtime_resume, NULL) -+}; -+ - static const struct of_device_id stm32_dmamux_match[] = { - { .compatible = "st,stm32h7-dmamux" }, - {}, -@@ -312,6 +399,7 @@ static struct platform_driver stm32_dmamux_driver = { - .driver = { - .name = "stm32-dmamux", - .of_match_table = stm32_dmamux_match, -+ .pm = &stm32_dmamux_pm_ops, - }, + SET_RUNTIME_PM_OPS(stm32_dmamux_runtime_suspend, + stm32_dmamux_runtime_resume, NULL) }; - diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 8c3c3e5..759d0ab 100644 +index 5838311cf..856421335 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c -@@ -37,6 +37,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -209,7 +210,9 @@ +@@ -199,7 +199,9 @@ #define STM32_MDMA_MAX_CHANNELS 63 #define STM32_MDMA_MAX_REQUESTS 256 #define STM32_MDMA_MAX_BURST 128 @@ -1904,7 +1938,7 @@ index 8c3c3e5..759d0ab 100644 enum stm32_mdma_trigger_mode { STM32_MDMA_BUFFER, -@@ -237,6 +240,7 @@ struct stm32_mdma_chan_config { +@@ -227,6 +229,7 @@ struct stm32_mdma_chan_config { u32 transfer_config; u32 mask_addr; u32 mask_data; @@ -1912,7 +1946,7 @@ index 8c3c3e5..759d0ab 100644 }; struct stm32_mdma_hwdesc { -@@ -262,6 +266,7 @@ struct stm32_mdma_desc { +@@ -252,6 +255,7 @@ struct stm32_mdma_desc { u32 ccr; bool cyclic; u32 count; @@ -1920,7 +1954,15 @@ index 8c3c3e5..759d0ab 100644 struct stm32_mdma_desc_node node[]; }; -@@ -577,13 +582,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, +@@ -273,7 +277,6 @@ struct stm32_mdma_device { + void __iomem *base; + struct clk *clk; + int irq; +- struct reset_control *rst; + u32 nr_channels; + u32 nr_requests; + u32 nr_ahb_addr_masks; +@@ -567,13 +570,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, dst_addr = chan->dma_config.dst_addr; /* Set device data size */ @@ -1946,7 +1988,7 @@ index 8c3c3e5..759d0ab 100644 dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, dst_maxburst, dst_addr_width); -@@ -626,13 +643,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, +@@ -616,13 +631,25 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, src_addr = chan->dma_config.src_addr; /* Set device data size */ @@ -1972,7 +2014,7 @@ index 8c3c3e5..759d0ab 100644 src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, src_maxburst, src_addr_width); -@@ -740,6 +769,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -730,6 +757,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; @@ -1980,7 +2022,7 @@ index 8c3c3e5..759d0ab 100644 struct scatterlist *sg; dma_addr_t src_addr, dst_addr; u32 ccr, ctcr, ctbr; -@@ -762,6 +792,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -752,6 +780,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, } else { src_addr = dma_config->src_addr; dst_addr = sg_dma_address(sg); @@ -1989,7 +2031,7 @@ index 8c3c3e5..759d0ab 100644 ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr, dst_addr, sg_dma_len(sg)); -@@ -780,8 +812,6 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, +@@ -770,8 +800,6 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, /* Enable interrupts */ ccr &= ~STM32_MDMA_CCR_IRQ_MASK; ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE; @@ -1998,7 +2040,7 @@ index 8c3c3e5..759d0ab 100644 desc->ccr = ccr; return 0; -@@ -793,7 +823,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, +@@ -783,7 +811,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, unsigned long flags, void *context) { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); @@ -2008,7 +2050,7 @@ index 8c3c3e5..759d0ab 100644 int i, ret; /* -@@ -815,6 +847,20 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, +@@ -805,6 +835,20 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, if (ret < 0) goto xfer_setup_err; @@ -2029,7 +2071,7 @@ index 8c3c3e5..759d0ab 100644 desc->cyclic = false; return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -@@ -836,9 +882,10 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -826,9 +870,10 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; @@ -2041,7 +2083,7 @@ index 8c3c3e5..759d0ab 100644 int i, ret; /* -@@ -892,12 +939,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -882,12 +927,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, desc->ccr = ccr; /* Configure hwdesc list */ @@ -2073,7 +2115,7 @@ index 8c3c3e5..759d0ab 100644 dst_addr = buf_addr + i * period_len; } -@@ -907,6 +971,7 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, +@@ -897,6 +959,7 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, } desc->cyclic = true; @@ -2081,7 +2123,7 @@ index 8c3c3e5..759d0ab 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -@@ -1137,6 +1202,8 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan) +@@ -1127,6 +1190,8 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan) return; } @@ -2090,7 +2132,7 @@ index 8c3c3e5..759d0ab 100644 chan->desc = to_stm32_mdma_desc(vdesc); hwdesc = chan->desc->node[0].hwdesc; chan->curr_hwdesc = 0; -@@ -1252,8 +1319,10 @@ static int stm32_mdma_terminate_all(struct dma_chan *c) +@@ -1242,8 +1307,10 @@ static int stm32_mdma_terminate_all(struct dma_chan *c) LIST_HEAD(head); spin_lock_irqsave(&chan->vchan.lock, flags); @@ -2103,7 +2145,7 @@ index 8c3c3e5..759d0ab 100644 chan->desc = NULL; } vchan_get_all_descriptors(&chan->vchan, &head); -@@ -1287,14 +1356,28 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, +@@ -1277,14 +1344,28 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct stm32_mdma_hwdesc *hwdesc = desc->node[0].hwdesc; @@ -2135,7 +2177,7 @@ index 8c3c3e5..759d0ab 100644 cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); residue += cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK; -@@ -1314,24 +1397,39 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, +@@ -1304,24 +1385,39 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, struct dma_tx_state *state) { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); @@ -2180,7 +2222,7 @@ index 8c3c3e5..759d0ab 100644 dma_set_residue(state, residue); spin_unlock_irqrestore(&chan->vchan.lock, flags); -@@ -1341,7 +1439,6 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, +@@ -1331,7 +1427,6 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, static void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan) { @@ -2188,35 +2230,117 @@ index 8c3c3e5..759d0ab 100644 vchan_cookie_complete(&chan->desc->vdesc); chan->desc = NULL; chan->busy = false; -@@ -1456,15 +1553,13 @@ static int stm32_mdma_alloc_chan_resources(struct dma_chan *c) - return -ENOMEM; +@@ -1344,7 +1439,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) + { + struct stm32_mdma_device *dmadev = devid; + struct stm32_mdma_chan *chan = devid; +- u32 reg, id, ien, status, flag; ++ u32 reg, id, ccr, ien, status; + + /* Find out which channel generates the interrupt */ + status = readl_relaxed(dmadev->base + STM32_MDMA_GISR0); +@@ -1366,67 +1461,71 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) + + chan = &dmadev->chan[id]; + if (!chan) { +- dev_dbg(mdma2dev(dmadev), "MDMA channel not initialized\n"); +- goto exit; ++ dev_warn(mdma2dev(dmadev), "MDMA channel not initialized\n"); ++ return IRQ_NONE; } -- ret = clk_prepare_enable(dmadev->clk); -- if (ret < 0) { -- dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret); -+ ret = pm_runtime_get_sync(dmadev->ddev.dev); -+ if (ret < 0) - return ret; -- } + /* Handle interrupt for the channel */ + spin_lock(&chan->vchan.lock); +- status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id)); +- ien = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)); +- ien &= STM32_MDMA_CCR_IRQ_MASK; +- ien >>= 1; ++ status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(id)); ++ /* Mask Channel ReQuest Active bit which can be set in case of MEM2MEM */ ++ status &= ~STM32_MDMA_CISR_CRQA; ++ ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(id)); ++ ien = (ccr & STM32_MDMA_CCR_IRQ_MASK) >> 1; - ret = stm32_mdma_disable_chan(chan); - if (ret < 0) -- clk_disable_unprepare(dmadev->clk); -+ pm_runtime_put(dmadev->ddev.dev); + if (!(status & ien)) { + spin_unlock(&chan->vchan.lock); +- dev_dbg(chan2dev(chan), +- "spurious it (status=0x%04x, ien=0x%04x)\n", +- status, ien); ++ dev_warn(chan2dev(chan), ++ "spurious it (status=0x%04x, ien=0x%04x)\n", ++ status, ien); + return IRQ_NONE; + } - return ret; +- flag = __ffs(status & ien); +- reg = STM32_MDMA_CIFCR(chan->id); ++ reg = STM32_MDMA_CIFCR(id); + +- switch (1 << flag) { +- case STM32_MDMA_CISR_TEIF: +- id = chan->id; +- status = readl_relaxed(dmadev->base + STM32_MDMA_CESR(id)); +- dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n", status); ++ if (status & STM32_MDMA_CISR_TEIF) { ++ dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n", ++ readl_relaxed(dmadev->base + STM32_MDMA_CESR(id))); + stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CTEIF); +- break; ++ status &= ~STM32_MDMA_CISR_TEIF; ++ } + +- case STM32_MDMA_CISR_CTCIF: ++ if (status & STM32_MDMA_CISR_CTCIF) { + stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CCTCIF); ++ status &= ~STM32_MDMA_CISR_CTCIF; + stm32_mdma_xfer_end(chan); +- break; ++ } + +- case STM32_MDMA_CISR_BRTIF: ++ if (status & STM32_MDMA_CISR_BRTIF) { + stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBRTIF); +- break; ++ status &= ~STM32_MDMA_CISR_BRTIF; ++ } + +- case STM32_MDMA_CISR_BTIF: ++ if (status & STM32_MDMA_CISR_BTIF) { + stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBTIF); ++ status &= ~STM32_MDMA_CISR_BTIF; + chan->curr_hwdesc++; + if (chan->desc && chan->desc->cyclic) { + if (chan->curr_hwdesc == chan->desc->count) + chan->curr_hwdesc = 0; + vchan_cyclic_callback(&chan->desc->vdesc); + } +- break; ++ } + +- case STM32_MDMA_CISR_TCIF: ++ if (status & STM32_MDMA_CISR_TCIF) { + stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CLTCIF); +- break; ++ status &= ~STM32_MDMA_CISR_TCIF; ++ } + +- default: +- dev_err(chan2dev(chan), "it %d unhandled (status=0x%04x)\n", +- 1 << flag, status); ++ if (status) { ++ stm32_mdma_set_bits(dmadev, reg, status); ++ dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); ++ if (!(ccr & STM32_MDMA_CCR_EN)) ++ dev_err(chan2dev(chan), "chan disabled by HW\n"); + } + + spin_unlock(&chan->vchan.lock); + +-exit: + return IRQ_HANDLED; } -@@ -1484,7 +1579,7 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c) - spin_unlock_irqrestore(&chan->vchan.lock, flags); - } -- clk_disable_unprepare(dmadev->clk); -+ pm_runtime_put(dmadev->ddev.dev); - vchan_free_chan_resources(to_virt_chan(c)); - dmam_pool_destroy(chan->desc_pool); - chan->desc_pool = NULL; -@@ -1498,7 +1593,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1486,7 +1585,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, struct dma_chan *c; struct stm32_mdma_chan_config config; @@ -2225,7 +2349,7 @@ index 8c3c3e5..759d0ab 100644 dev_err(mdma2dev(dmadev), "Bad number of args\n"); return NULL; } -@@ -1508,6 +1603,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1496,6 +1595,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, config.transfer_config = dma_spec->args[2]; config.mask_addr = dma_spec->args[3]; config.mask_data = dma_spec->args[4]; @@ -2233,20 +2357,46 @@ index 8c3c3e5..759d0ab 100644 if (config.request >= dmadev->nr_requests) { dev_err(mdma2dev(dmadev), "Bad request line\n"); -@@ -1597,6 +1693,12 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1532,6 +1632,7 @@ static int stm32_mdma_probe(struct platform_device *pdev) + struct dma_device *dd; + struct device_node *of_node; + struct resource *res; ++ struct reset_control *rst; + u32 nr_channels, nr_requests; + int i, count, ret; + +@@ -1579,8 +1680,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) + dmadev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dmadev->clk)) { + ret = PTR_ERR(dmadev->clk); +- if (ret == -EPROBE_DEFER) +- dev_info(&pdev->dev, "Missing controller clock\n"); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Missing clock controller\n"); return ret; } -+ ret = clk_prepare_enable(dmadev->clk); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); -+ return ret; -+ } -+ - dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); - if (!IS_ERR(dmadev->rst)) { - reset_control_assert(dmadev->rst); -@@ -1621,6 +1723,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1590,11 +1691,15 @@ static int stm32_mdma_probe(struct platform_device *pdev) + return ret; + } + +- dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (!IS_ERR(dmadev->rst)) { +- reset_control_assert(dmadev->rst); ++ rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_clk; ++ } else { ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(dmadev->rst); ++ reset_control_deassert(rst); + } + + dd = &dmadev->ddev; +@@ -1614,6 +1719,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) dd->device_resume = stm32_mdma_resume; dd->device_terminate_all = stm32_mdma_terminate_all; dd->device_synchronize = stm32_mdma_synchronize; @@ -2255,76 +2405,56 @@ index 8c3c3e5..759d0ab 100644 dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | -@@ -1646,19 +1750,20 @@ static int stm32_mdma_probe(struct platform_device *pdev) - dmadev->irq = platform_get_irq(pdev, 0); - if (dmadev->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); -- return dmadev->irq; -+ ret = dmadev->irq; -+ goto clk_free; +@@ -1637,25 +1744,27 @@ static int stm32_mdma_probe(struct platform_device *pdev) } + dmadev->irq = platform_get_irq(pdev, 0); +- if (dmadev->irq < 0) +- return dmadev->irq; ++ if (dmadev->irq < 0) { ++ ret = dmadev->irq; ++ goto err_clk; ++ } + ret = devm_request_irq(&pdev->dev, dmadev->irq, stm32_mdma_irq_handler, 0, dev_name(&pdev->dev), dmadev); if (ret) { dev_err(&pdev->dev, "failed to request IRQ\n"); - return ret; -+ goto clk_free; ++ goto err_clk; } - ret = dma_async_device_register(dd); + ret = dmaenginem_async_device_register(dd); if (ret) - return ret; -+ goto clk_free; ++ goto err_clk; ret = of_dma_controller_register(of_node, stm32_mdma_of_xlate, dmadev); if (ret < 0) { -@@ -1668,6 +1773,10 @@ static int stm32_mdma_probe(struct platform_device *pdev) + dev_err(&pdev->dev, + "STM32 MDMA DMA OF registration failed %d\n", ret); +- goto err_unregister; ++ goto err_dmaengine; } platform_set_drvdata(pdev, dmadev); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_put(&pdev->dev); +@@ -1668,7 +1777,11 @@ static int stm32_mdma_probe(struct platform_device *pdev) - dev_info(&pdev->dev, "STM32 MDMA driver registered\n"); + return 0; -@@ -1675,15 +1784,86 @@ static int stm32_mdma_probe(struct platform_device *pdev) - - err_unregister: - dma_async_device_unregister(dd); -+clk_free: +-err_unregister: ++err_dmaengine: ++ dma_async_device_unregister(dd); ++err_clk: + clk_disable_unprepare(dmadev->clk); - ++ return ret; } -+#ifdef CONFIG_PM -+static int stm32_mdma_runtime_suspend(struct device *dev) -+{ -+ struct stm32_mdma_device *dmadev = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(dmadev->clk); -+ -+ return 0; -+} -+ -+static int stm32_mdma_runtime_resume(struct device *dev) -+{ -+ struct stm32_mdma_device *dmadev = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_prepare_enable(dmadev->clk); -+ if (ret) { -+ dev_err(dev, "failed to prepare_enable clock\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ +@@ -1697,7 +1810,45 @@ static int stm32_mdma_runtime_resume(struct device *dev) + } + #endif + +#ifdef CONFIG_PM_SLEEP +static int stm32_mdma_pw_suspend(struct device *dev) +{ @@ -2362,26 +2492,37 @@ index 8c3c3e5..759d0ab 100644 +} +#endif + -+static const struct dev_pm_ops stm32_mdma_pm_ops = { + static const struct dev_pm_ops stm32_mdma_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_mdma_pw_suspend, stm32_mdma_pw_resume) -+ SET_RUNTIME_PM_OPS(stm32_mdma_runtime_suspend, -+ stm32_mdma_runtime_resume, NULL) -+}; -+ - static struct platform_driver stm32_mdma_driver = { - .probe = stm32_mdma_probe, - .driver = { - .name = "stm32-mdma", - .of_match_table = stm32_mdma_of_match, -+ .pm = &stm32_mdma_pm_ops, - }, + SET_RUNTIME_PM_OPS(stm32_mdma_runtime_suspend, + stm32_mdma_runtime_resume, NULL) }; - diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h -index 0647f43..942c707 100644 +index 801356275..07f6e1136 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h -@@ -1318,9 +1318,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, +@@ -258,6 +258,9 @@ struct dma_chan { + /* sysfs */ + int chan_id; + struct dma_chan_dev *dev; ++#ifdef CONFIG_DEBUG_FS ++ char *dbg_client_name; ++#endif + + struct list_head device_node; + struct dma_chan_percpu __percpu *local; +@@ -802,6 +805,10 @@ struct dma_device { + dma_cookie_t cookie, + struct dma_tx_state *txstate); + void (*device_issue_pending)(struct dma_chan *chan); ++ /* debugfs support */ ++#ifdef CONFIG_DEBUG_FS ++ void (*dbg_summary_show)(struct seq_file *s, struct dma_device *dev); ++#endif + }; + + static inline int dmaengine_slave_config(struct dma_chan *chan, +@@ -1309,9 +1316,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); struct dma_chan *dma_request_chan(struct device *dev, const char *name); @@ -2393,7 +2534,7 @@ index 0647f43..942c707 100644 int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps); #else static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) -@@ -1353,6 +1355,11 @@ static inline struct dma_chan *dma_request_chan(struct device *dev, +@@ -1346,6 +1355,11 @@ static inline struct dma_chan *dma_request_chan(struct device *dev, { return ERR_PTR(-ENODEV); } @@ -2405,7 +2546,7 @@ index 0647f43..942c707 100644 static inline struct dma_chan *dma_request_chan_by_mask( const dma_cap_mask_t *mask) { -@@ -1361,6 +1368,10 @@ static inline struct dma_chan *dma_request_chan_by_mask( +@@ -1354,6 +1368,10 @@ static inline struct dma_chan *dma_request_chan_by_mask( static inline void dma_release_channel(struct dma_chan *chan) { } @@ -2417,5 +2558,5 @@ index 0647f43..942c707 100644 struct dma_slave_caps *caps) { -- -2.7.4 +2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch new file mode 100644 index 0000000..b3fb45f --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch @@ -0,0 +1,1314 @@ +From 29a46aadaab8285eafc89b86fb6db1b092979589 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:41:19 +0200 +Subject: [PATCH 07/23] ARM-stm32mp1-r1-DRM + +--- + drivers/gpu/drm/bridge/sii902x.c | 145 +++++++++- + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 160 +++++++++-- + drivers/gpu/drm/drm_modes.c | 19 +- + .../gpu/drm/panel/panel-orisetech-otm8009a.c | 20 +- + drivers/gpu/drm/panel/panel-raydium-rm68200.c | 14 +- + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 9 +- + drivers/gpu/drm/stm/ltdc.c | 270 +++++++++++------- + drivers/gpu/drm/stm/ltdc.h | 1 + + drivers/input/touchscreen/edt-ft5x06.c | 18 +- + drivers/input/touchscreen/goodix.c | 16 ++ + include/uapi/drm/drm_mode.h | 6 + + 11 files changed, 512 insertions(+), 166 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c +index 38f75ac58..92299884f 100644 +--- a/drivers/gpu/drm/bridge/sii902x.c ++++ b/drivers/gpu/drm/bridge/sii902x.c +@@ -16,8 +16,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + + #include + #include +@@ -160,6 +162,11 @@ + + #define SII902X_AUDIO_PORT_INDEX 3 + ++/* CEC device */ ++#define SII902X_CEC_I2C_ADDR 0x30 ++ ++#define SII902X_CEC_SETUP 0x8e ++ + struct sii902x { + struct i2c_client *i2c; + struct regmap *regmap; +@@ -167,6 +174,7 @@ struct sii902x { + struct drm_connector connector; + struct gpio_desc *reset_gpio; + struct i2c_mux_core *i2cmux; ++ struct edid *edid; + /* + * Mutex protects audio and video functions from interfering + * each other, by keeping their i2c command sequences atomic. +@@ -177,6 +185,7 @@ struct sii902x { + struct clk *mclk; + u32 i2s_fifo_sequence[4]; + } audio; ++ struct regulator_bulk_data supplies[2]; + }; + + static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) +@@ -277,6 +286,8 @@ static int sii902x_get_modes(struct drm_connector *connector) + + mutex_lock(&sii902x->mutex); + ++ kfree(sii902x->edid); ++ sii902x->edid = NULL; + edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); + drm_connector_update_edid_property(connector, edid); + if (edid) { +@@ -284,7 +295,7 @@ static int sii902x_get_modes(struct drm_connector *connector) + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; + + num = drm_add_edid_modes(connector, edid); +- kfree(edid); ++ sii902x->edid = edid; + } + + ret = drm_display_info_set_bus_formats(&connector->display_info, +@@ -334,6 +345,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) + static void sii902x_bridge_enable(struct drm_bridge *bridge) + { + struct sii902x *sii902x = bridge_to_sii902x(bridge); ++ u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; + + mutex_lock(&sii902x->mutex); + +@@ -343,6 +355,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) + regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_PWR_DWN, 0); + ++ if (sii902x->edid) { ++ if (drm_detect_hdmi_monitor(sii902x->edid)) ++ output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; ++ } ++ ++ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, ++ SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); ++ + mutex_unlock(&sii902x->mutex); + } + +@@ -952,6 +972,13 @@ static int sii902x_probe(struct i2c_client *client, + struct device *dev = &client->dev; + unsigned int status = 0; + struct sii902x *sii902x; ++ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; ++ struct i2c_msg msg = { ++ .addr = SII902X_CEC_I2C_ADDR << 1, ++ .flags = 0, ++ .len = 2, ++ .buf = data, ++ }; + u8 chipid[4]; + int ret; + +@@ -980,40 +1007,66 @@ static int sii902x_probe(struct i2c_client *client, + } + + mutex_init(&sii902x->mutex); ++ sii902x->supplies[0].supply = "iovcc"; ++ sii902x->supplies[1].supply = "cvcc12"; ++ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ if (ret) { ++ if(ret != -EPROBE_DEFER) ++ dev_err(dev, "regulator_bulk_get failed\n"); ++ return ret; ++ } ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ if (ret) { ++ dev_err(dev, "regulator_bulk_enable failed\n"); ++ return ret; ++ } + + sii902x_reset(sii902x); + + ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); + if (ret) +- return ret; ++ goto err_disable_regulator; + + ret = regmap_bulk_read(sii902x->regmap, SII902X_REG_CHIPID(0), + &chipid, 4); + if (ret) { + dev_err(dev, "regmap_read failed %d\n", ret); +- return ret; ++ goto err_disable_regulator; + } + + if (chipid[0] != 0xb0) { + dev_err(dev, "Invalid chipid: %02x (expecting 0xb0)\n", + chipid[0]); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_disable_regulator; + } + ++ /* ++ * By default, CEC must be disabled to allow other CEC devives ++ * to bypass the bridge. ++ */ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret < 0) ++ dev_warn(&client->dev, "Failed to disable CEC device!\n"); ++ + /* Clear all pending interrupts */ + regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); + regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); + + if (client->irq > 0) { +- regmap_write(sii902x->regmap, SII902X_INT_ENABLE, +- SII902X_HOTPLUG_EVENT); ++ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, ++ SII902X_HOTPLUG_EVENT, ++ SII902X_HOTPLUG_EVENT); + + ret = devm_request_threaded_irq(dev, client->irq, NULL, + sii902x_interrupt, + IRQF_ONESHOT, dev_name(dev), + sii902x); + if (ret) +- return ret; ++ goto err_disable_regulator; + } + + sii902x->bridge.funcs = &sii902x_bridge_funcs; +@@ -1033,7 +1086,20 @@ static int sii902x_probe(struct i2c_client *client, + return -ENOMEM; + + sii902x->i2cmux->priv = sii902x; +- return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); ++ ++ ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); ++ if (ret) { ++ dev_err(dev, "Couldn't add i2c mux adapter\n"); ++ return ret; ++ } ++ ++ return 0; ++ ++err_disable_regulator: ++ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ ++ return ret; + } + + static int sii902x_remove(struct i2c_client *client) +@@ -1044,9 +1110,71 @@ static int sii902x_remove(struct i2c_client *client) + i2c_mux_del_adapters(sii902x->i2cmux); + drm_bridge_remove(&sii902x->bridge); + ++ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ ++ return 0; ++} ++ ++static int sii902x_pm_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sii902x *sii902x = i2c_get_clientdata(client); ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ if (sii902x->reset_gpio) ++ gpiod_set_value(sii902x->reset_gpio, 1); ++ ++ regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ ++ return 0; ++} ++ ++static int sii902x_pm_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sii902x *sii902x = i2c_get_clientdata(client); ++ unsigned char data[2] = { SII902X_CEC_SETUP, 0}; ++ struct i2c_msg msg = { ++ .addr = SII902X_CEC_I2C_ADDR << 1, ++ .flags = 0, ++ .len = 2, ++ .buf = data, ++ }; ++ int ret; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), ++ sii902x->supplies); ++ if (ret) { ++ DRM_ERROR("regulator_bulk_enable failed\n"); ++ return ret; ++ } ++ ++ if (sii902x->reset_gpio) ++ gpiod_set_value(sii902x->reset_gpio, 0); ++ ++ regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); ++ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret < 0) ++ DRM_ERROR("Failed to disable CEC device!\n"); ++ ++ if (client->irq > 0) ++ regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, ++ SII902X_HOTPLUG_EVENT, ++ SII902X_HOTPLUG_EVENT); ++ + return 0; + } + ++static const struct dev_pm_ops sii902x_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) ++}; ++ + static const struct of_device_id sii902x_dt_ids[] = { + { .compatible = "sil,sii9022", }, + { } +@@ -1065,6 +1193,7 @@ static struct i2c_driver sii902x_driver = { + .driver = { + .name = "sii902x", + .of_match_table = sii902x_dt_ids, ++ .pm = &sii902x_pm_ops, + }, + .id_table = sii902x_i2c_ids, + }; +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +index 675442bfc..1389bbfa0 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -90,6 +90,7 @@ + #define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 + #define VID_MODE_TYPE_BURST 0x2 + #define VID_MODE_TYPE_MASK 0x3 ++#define ENABLE_LOW_POWER_CMD BIT(15) + #define VID_MODE_VPG_ENABLE BIT(16) + #define VID_MODE_VPG_HORIZONTAL BIT(24) + +@@ -212,6 +213,20 @@ + + #define DSI_INT_ST0 0xbc + #define DSI_INT_ST1 0xc0 ++#define GPRXE BIT(12) ++#define GPRDE BIT(11) ++#define GPTXE BIT(10) ++#define GPWRE BIT(9) ++#define GCWRE BIT(8) ++#define DPIPLDWE BIT(7) ++#define EOTPE BIT(6) ++#define PSE BIT(5) ++#define CRCE BIT(4) ++#define ECCME BIT(3) ++#define ECCSE BIT(2) ++#define TOLPRX BIT(1) ++#define TOHSTX BIT(0) ++ + #define DSI_INT_MSK0 0xc4 + #define DSI_INT_MSK1 0xc8 + +@@ -297,7 +312,13 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; + struct drm_bridge *bridge; + struct drm_panel *panel; +- int ret; ++ int i, nb_endpoints; ++ int ret = -ENODEV; ++ ++ /* Get number of endpoints */ ++ nb_endpoints = of_graph_get_endpoint_count(host->dev->of_node); ++ if (!nb_endpoints) ++ return -ENODEV; + + if (device->lanes > dsi->plat_data->max_data_lanes) { + dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", +@@ -310,8 +331,16 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; + +- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, +- &panel, &bridge); ++ for (i = 1; i < nb_endpoints; i++) { ++ ret = drm_of_find_panel_or_bridge(host->dev->of_node, i, 0, ++ &panel, &bridge); ++ if (!ret) ++ break; ++ else if (ret == -EPROBE_DEFER) ++ return ret; ++ } ++ ++ /* check if an error is returned >> no panel or bridge detected */ + if (ret) + return ret; + +@@ -360,13 +389,32 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, + bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; + u32 val = 0; + ++ /* ++ * In lpm mode, we maybe can compute the packet size dependig on ++ * message lenght. ++ */ ++ /* ++ * 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(16) ++ | INVACT_LPCMD_TIME(4)); ++ + 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); ++ ++ val = dsi_read(dsi, DSI_VID_MODE_CFG); ++ if (lpm) ++ val |= ENABLE_LOW_POWER_CMD; ++ else ++ val &= ~ENABLE_LOW_POWER_CMD; ++ dsi_write(dsi, DSI_VID_MODE_CFG, val); + } + + static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) +@@ -396,6 +444,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) + return 0; + } + ++static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi) ++{ ++ u32 val; ++ ++ val = dsi_read(dsi, DSI_INT_ST1); ++ ++ if (val & GPRXE) ++ DRM_DEBUG_DRIVER("DSI Generic payload receive error\n"); ++ if (val & GPRDE) ++ DRM_DEBUG_DRIVER("DSI Generic payload read error\n"); ++ if (val & GPTXE) ++ DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n"); ++ if (val & GPWRE) ++ DRM_DEBUG_DRIVER("DSI Generic payload write error\n"); ++ if (val & GCWRE) ++ DRM_DEBUG_DRIVER("DSI Generic command write error\n"); ++ if (val & DPIPLDWE) ++ DRM_DEBUG_DRIVER("DSI DPI payload write error\n"); ++ if (val & EOTPE) ++ DRM_DEBUG_DRIVER("DSI EoTp error\n"); ++ if (val & PSE) ++ DRM_DEBUG_DRIVER("DSI Packet size error\n"); ++ if (val & CRCE) ++ DRM_DEBUG_DRIVER("DSI CRC error\n"); ++ if (val & ECCME) ++ DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n"); ++ if (val & ECCSE) ++ DRM_DEBUG_DRIVER("DSI ECC single-bit error\n"); ++ if (val & TOLPRX) ++ DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n"); ++ if (val & TOHSTX) ++ DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n"); ++ ++ return val; ++} ++ + static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_packet *packet) + { +@@ -425,6 +509,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + "failed to get available write payload FIFO\n"); + return ret; + } ++ ++ val = dw_mipi_dsi_read_status(dsi); ++ if (val) { ++ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); ++ return -EINVAL; ++ } + } + + word = 0; +@@ -458,6 +548,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, + return ret; + } + ++ val = dw_mipi_dsi_read_status(dsi); ++ if (val) { ++ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); ++ return -EINVAL; ++ } ++ + val = dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j = 0; j < 4 && j + i < len; j++) + buf[i + j] = val >> (8 * j); +@@ -472,6 +568,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + struct dw_mipi_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + int ret, nb_bytes; ++ int retry = 3; + + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { +@@ -483,24 +580,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + if (dsi->slave) + dw_mipi_message_config(dsi->slave, msg); + +- ret = dw_mipi_dsi_write(dsi, &packet); +- if (ret) +- return ret; +- if (dsi->slave) { +- ret = dw_mipi_dsi_write(dsi->slave, &packet); ++ while (retry--) { ++ ret = dw_mipi_dsi_write(dsi, &packet); + if (ret) +- return ret; +- } ++ continue; + +- 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; ++ if (dsi->slave) { ++ ret = dw_mipi_dsi_write(dsi->slave, &packet); ++ if (ret) ++ continue; ++ } ++ ++ if (msg->rx_buf && msg->rx_len) { ++ ret = dw_mipi_dsi_read(dsi, msg); ++ if (ret) ++ continue; ++ nb_bytes = msg->rx_len; ++ break; ++ } else { ++ nb_bytes = packet.size; ++ break; ++ } + } + ++ if (ret) ++ return ret; ++ + return nb_bytes; + } + +@@ -541,16 +646,22 @@ 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) + { ++ u32 val; ++ + 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); + } + ++ val = PHY_TXREQUESTCLKHS; ++ if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ++ val |= AUTO_CLKLANE_CTRL; ++ dsi_write(dsi, DSI_LPCLK_CTRL, val); ++ + dsi_write(dsi, DSI_PWR_UP, POWERUP); + } + +@@ -611,14 +722,6 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, + 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) +@@ -814,7 +917,8 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) + * This needs to be fixed in the drm_bridge framework and the API + * needs to be updated to manage our own call chains... + */ +- dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); ++ if (dsi->panel_bridge->funcs->post_disable) ++ dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); + + if (dsi->slave) { + dw_mipi_dsi_disable(dsi->slave); +diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c +index 3fd35e6b9..80de2fb7e 100644 +--- a/drivers/gpu/drm/drm_modes.c ++++ b/drivers/gpu/drm/drm_modes.c +@@ -127,7 +127,7 @@ EXPORT_SYMBOL(drm_mode_probed_add); + * according to the hdisplay, vdisplay, vrefresh. + * It is based from the VESA(TM) Coordinated Video Timing Generator by + * Graham Loveridge April 9, 2003 available at +- * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls ++ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls + * + * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. + * What I have done is to translate it by using integer calculation. +@@ -614,6 +614,15 @@ void drm_display_mode_from_videomode(const struct videomode *vm, + dmode->flags |= DRM_MODE_FLAG_DBLSCAN; + if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) + dmode->flags |= DRM_MODE_FLAG_DBLCLK; ++ if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) ++ dmode->flags |= DRM_MODE_FLAG_PPIXDATA; ++ else if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ++ dmode->flags |= DRM_MODE_FLAG_NPIXDATA; ++ if (vm->flags & DISPLAY_FLAGS_DE_HIGH) ++ dmode->flags |= DRM_MODE_FLAG_PDE; ++ else if (vm->flags & DISPLAY_FLAGS_DE_LOW) ++ dmode->flags |= DRM_MODE_FLAG_NDE; ++ + drm_mode_set_name(dmode); + } + EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); +@@ -655,6 +664,14 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, + vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; + if (dmode->flags & DRM_MODE_FLAG_DBLCLK) + vm->flags |= DISPLAY_FLAGS_DOUBLECLK; ++ if (dmode->flags & DRM_MODE_FLAG_PPIXDATA) ++ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; ++ else if (dmode->flags & DRM_MODE_FLAG_NPIXDATA) ++ vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; ++ if (dmode->flags & DRM_MODE_FLAG_PDE) ++ vm->flags |= DISPLAY_FLAGS_DE_HIGH; ++ else if (dmode->flags & DRM_MODE_FLAG_NDE) ++ vm->flags |= DISPLAY_FLAGS_DE_LOW; + } + EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); + +diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +index c7b48df88..2fdf9d183 100644 +--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c ++++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +@@ -101,20 +101,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, + DRM_WARN("mipi dsi dcs write buffer failed\n"); + } + +-static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, +- size_t len) +-{ +- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +- +- /* data will be sent in dsi hs mode (ie. no lpm) */ +- dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; +- +- otm8009a_dcs_write_buf(ctx, data, len); +- +- /* restore back the dsi lpm mode */ +- dsi->mode_flags |= MIPI_DSI_MODE_LPM; +-} +- + #define dcs_write_seq(ctx, seq...) \ + ({ \ + static const u8 d[] = { seq }; \ +@@ -401,7 +387,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) + */ + data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; + data[1] = bd->props.brightness; +- otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); ++ otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); + + /* set Brightness Control & Backlight on */ + data[1] = 0x24; +@@ -413,7 +399,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) + + /* Update Brightness Control & Backlight */ + data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; +- otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); ++ otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); + + return 0; + } +@@ -453,7 +439,7 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) + 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; ++ MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; + + drm_panel_init(&ctx->panel); + ctx->panel.dev = dev; +diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c +index ba889625a..b20e26666 100644 +--- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c ++++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c +@@ -84,15 +84,15 @@ struct rm68200 { + }; + + static const struct drm_display_mode default_mode = { +- .clock = 52582, ++ .clock = 54000, + .hdisplay = 720, +- .hsync_start = 720 + 38, +- .hsync_end = 720 + 38 + 8, +- .htotal = 720 + 38 + 8 + 38, ++ .hsync_start = 720 + 48, ++ .hsync_end = 720 + 48 + 9, ++ .htotal = 720 + 48 + 9 + 48, + .vdisplay = 1280, + .vsync_start = 1280 + 12, +- .vsync_end = 1280 + 12 + 4, +- .vtotal = 1280 + 12 + 4 + 12, ++ .vsync_end = 1280 + 12 + 5, ++ .vtotal = 1280 + 12 + 5 + 12, + .vrefresh = 50, + .flags = 0, + .width_mm = 68, +@@ -402,7 +402,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) + 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; ++ MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; + + drm_panel_init(&ctx->panel); + ctx->panel.dev = dev; +diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +index a03a642c1..d1689758f 100644 +--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c ++++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +@@ -260,8 +260,11 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, + /* Compute requested pll out */ + bpp = mipi_dsi_pixel_format_to_bpp(format); + pll_out_khz = mode->clock * 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 (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ++ pll_out_khz = (pll_out_khz * 12) / 10; ++ + if (pll_out_khz > dsi->lane_max_kbps) { + pll_out_khz = dsi->lane_max_kbps; + DRM_WARN("Warning max phy mbps is used\n"); +@@ -361,7 +364,9 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) + dsi->pllref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(dsi->pllref_clk)) { + ret = PTR_ERR(dsi->pllref_clk); +- DRM_ERROR("Unable to get pll reference clock: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Unable to get pll reference clock: %d\n", ++ ret); + goto err_clk_get; + } + +diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c +index 3ab4fbf8e..1f7836be2 100644 +--- a/drivers/gpu/drm/stm/ltdc.c ++++ b/drivers/gpu/drm/stm/ltdc.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -39,10 +40,6 @@ + #define NB_CRTC 1 + #define CRTC_MASK GENMASK(NB_CRTC - 1, 0) + +-#define MAX_IRQ 4 +- +-#define MAX_ENDPOINTS 2 +- + #define HWVER_10200 0x010200 + #define HWVER_10300 0x010300 + #define HWVER_20101 0x020101 +@@ -436,9 +433,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, + /* Commit shadow registers = update planes at next vblank */ + reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); + +- /* Enable LTDC */ +- reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); +- + drm_crtc_vblank_on(crtc); + } + +@@ -452,9 +446,6 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, + + drm_crtc_vblank_off(crtc); + +- /* disable LTDC */ +- reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); +- + /* disable IRQ */ + reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); + +@@ -653,9 +644,14 @@ static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { + static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc) + { + struct ltdc_device *ldev = crtc_to_ltdc(crtc); ++ struct drm_crtc_state *state = crtc->state; + + DRM_DEBUG_DRIVER("\n"); +- reg_set(ldev->regs, LTDC_IER, IER_LIE); ++ ++ if (state->enable) ++ reg_set(ldev->regs, LTDC_IER, IER_LIE); ++ else ++ return -EPERM; + + return 0; + } +@@ -735,22 +731,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) + { + struct drm_framebuffer *fb = state->fb; +- u32 src_w, src_h; ++ struct drm_crtc_state *crtc_state; ++ struct drm_rect *src = &state->src; ++ struct drm_rect *dst = &state->dst; + + DRM_DEBUG_DRIVER("\n"); + + if (!fb) + return 0; + +- /* convert src_ from 16:16 format */ +- src_w = state->src_w >> 16; +- src_h = state->src_h >> 16; ++ /* convert src from 16:16 format */ ++ src->x1 = state->src_x >> 16; ++ src->y1 = state->src_y >> 16; ++ src->x2 = (state->src_w >> 16) + src->x1 - 1; ++ src->y2 = (state->src_h >> 16) + src->y1 - 1; + +- /* Reject scaling */ +- if (src_w != state->crtc_w || src_h != state->crtc_h) { +- DRM_ERROR("Scaling is not supported"); ++ dst->x1 = state->crtc_x; ++ dst->y1 = state->crtc_y; ++ dst->x2 = state->crtc_w + dst->x1 - 1; ++ dst->y2 = state->crtc_h + dst->y1 - 1; ++ ++ DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", ++ plane->base.id, fb->base.id, ++ src->x2 - src->x1 + 1, src->y2 - src->y1 + 1, ++ src->x1, src->y1, ++ dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1, ++ dst->x1, dst->y1); ++ ++ crtc_state = drm_atomic_get_existing_crtc_state(state->state, ++ state->crtc); ++ /* destination coordinates do not have to exceed display sizes */ ++ if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || ++ crtc_state->mode.vdisplay <= dst->y2)) ++ return -EINVAL; ++ ++ /* source sizes do not have to exceed destination sizes */ ++ if (dst->x2 - dst->x1 < src->x2 - src->x1 || ++ dst->y2 - dst->y1 < src->y2 - src->y1) + return -EINVAL; +- } + + return 0; + } +@@ -760,44 +778,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, + { + struct ltdc_device *ldev = plane_to_ltdc(plane); + struct drm_plane_state *state = plane->state; ++ struct drm_rect *src = &state->src; ++ struct drm_rect *dst = &state->dst; + struct drm_framebuffer *fb = state->fb; + u32 lofs = plane->index * LAY_OFS; +- u32 x0 = state->crtc_x; +- u32 x1 = state->crtc_x + state->crtc_w - 1; +- u32 y0 = state->crtc_y; +- u32 y1 = state->crtc_y + state->crtc_h - 1; +- u32 src_x, src_y, src_w, src_h; + u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; + enum ltdc_pix_fmt pf; ++ struct drm_rect dr; + + if (!state->crtc || !fb) { + DRM_DEBUG_DRIVER("fb or crtc NULL"); + return; + } + +- /* convert src_ from 16:16 format */ +- src_x = state->src_x >> 16; +- src_y = state->src_y >> 16; +- src_w = state->src_w >> 16; +- src_h = state->src_h >> 16; +- +- DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", +- plane->base.id, fb->base.id, +- src_w, src_h, src_x, src_y, +- state->crtc_w, state->crtc_h, +- state->crtc_x, state->crtc_y); ++ /* compute final coordinates of frame buffer */ ++ dr.x1 = src->x1 + dst->x1; ++ dr.y1 = src->y1 + dst->y1; ++ dr.x2 = src->x2 + dst->x1; ++ dr.y2 = src->y2 + dst->y1; + + bpcr = reg_read(ldev->regs, LTDC_BPCR); + ahbp = (bpcr & BPCR_AHBP) >> 16; + avbp = bpcr & BPCR_AVBP; + + /* Configures the horizontal start and stop position */ +- val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); ++ val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp); + reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, + LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); + + /* Configures the vertical start and stop position */ +- val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); ++ val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp); + reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, + LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); + +@@ -816,8 +826,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, + + /* Configures the color frame buffer pitch in bytes & line length */ + pitch_in_bytes = fb->pitches[0]; +- line_length = fb->format->cpp[0] * +- (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; ++ line_length = fb->format->cpp[0] * (dr.x2 - dr.x1 + 1) + ++ (ldev->caps.bus_width >> 3) - 1; + val = ((pitch_in_bytes << 16) | line_length); + reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, + LXCFBLR_CFBLL | LXCFBLR_CFBP, val); +@@ -840,7 +850,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, + LXBFCR_BF2 | LXBFCR_BF1, val); + + /* Configures the frame buffer line number */ +- val = y1 - y0 + 1; ++ val = dr.y2 - dr.y1 + 1; + reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); + + /* Sets the FB address */ +@@ -1040,6 +1050,54 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = { + .destroy = drm_encoder_cleanup, + }; + ++static void ltdc_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct drm_device *ddev = encoder->dev; ++ struct ltdc_device *ldev = ddev->dev_private; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* Disable LTDC */ ++ reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); ++ ++ /* Set to sleep state the pinctrl whatever type of encoder */ ++ pinctrl_pm_select_sleep_state(ddev->dev); ++} ++ ++static void ltdc_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct drm_device *ddev = encoder->dev; ++ struct ltdc_device *ldev = ddev->dev_private; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* Enable LTDC */ ++ reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); ++} ++ ++static void ltdc_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct drm_device *ddev = encoder->dev; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* ++ * Set to default state the pinctrl only with DPI type. ++ * Others types like DSI, don't need pinctrl due to ++ * internal bridge (the signals do not come out of the chipset). ++ */ ++ if (encoder->encoder_type == DRM_MODE_ENCODER_DPI) ++ pinctrl_pm_select_default_state(ddev->dev); ++} ++ ++static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = { ++ .disable = ltdc_encoder_disable, ++ .enable = ltdc_encoder_enable, ++ .mode_set = ltdc_encoder_mode_set, ++}; ++ + static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) + { + struct drm_encoder *encoder; +@@ -1055,6 +1113,8 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) + drm_encoder_init(ddev, encoder, <dc_encoder_funcs, + DRM_MODE_ENCODER_DPI, NULL); + ++ drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs); ++ + ret = drm_bridge_attach(encoder, bridge, NULL); + if (ret) { + drm_encoder_cleanup(encoder); +@@ -1101,12 +1161,14 @@ static int ltdc_get_caps(struct drm_device *ddev) + ldev->caps.pad_max_freq_hz = 90000000; + if (ldev->caps.hw_version == HWVER_10200) + ldev->caps.pad_max_freq_hz = 65000000; ++ ldev->caps.nb_irq = 2; + break; + case HWVER_20101: + ldev->caps.reg_ofs = REG_OFS_4; + ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; + ldev->caps.non_alpha_only_l1 = false; + ldev->caps.pad_max_freq_hz = 150000000; ++ ldev->caps.nb_irq = 4; + break; + default: + return -ENODEV; +@@ -1145,36 +1207,20 @@ int ltdc_load(struct drm_device *ddev) + struct ltdc_device *ldev = ddev->dev_private; + struct device *dev = ddev->dev; + struct device_node *np = dev->of_node; +- struct drm_bridge *bridge[MAX_ENDPOINTS] = {NULL}; +- struct drm_panel *panel[MAX_ENDPOINTS] = {NULL}; ++ struct drm_bridge *bridge; ++ struct drm_panel *panel; + struct drm_crtc *crtc; + struct reset_control *rstc; + struct resource *res; +- int irq, ret, i, endpoint_not_ready = -ENODEV; ++ int irq, i, nb_endpoints; ++ int ret = -ENODEV; + + DRM_DEBUG_DRIVER("\n"); + +- /* Get endpoints if any */ +- for (i = 0; i < MAX_ENDPOINTS; i++) { +- ret = drm_of_find_panel_or_bridge(np, 0, i, &panel[i], +- &bridge[i]); +- +- /* +- * If at least one endpoint is -EPROBE_DEFER, defer probing, +- * else if at least one endpoint is ready, continue probing. +- */ +- if (ret == -EPROBE_DEFER) +- return ret; +- else if (!ret) +- endpoint_not_ready = 0; +- } +- +- if (endpoint_not_ready) +- return endpoint_not_ready; +- +- rstc = devm_reset_control_get_exclusive(dev, NULL); +- +- mutex_init(&ldev->err_lock); ++ /* Get number of endpoints */ ++ nb_endpoints = of_graph_get_endpoint_count(np); ++ if (!nb_endpoints) ++ return -ENODEV; + + ldev->pixel_clk = devm_clk_get(dev, "lcd"); + if (IS_ERR(ldev->pixel_clk)) { +@@ -1188,6 +1234,43 @@ int ltdc_load(struct drm_device *ddev) + return -ENODEV; + } + ++ /* Get endpoints if any */ ++ for (i = 0; i < nb_endpoints; i++) { ++ ret = drm_of_find_panel_or_bridge(np, 0, i, &panel, &bridge); ++ ++ /* ++ * If at least one endpoint is -ENODEV, continue probing, ++ * else if at least one endpoint returned an error ++ * (ie -EPROBE_DEFER) then stop probing. ++ */ ++ if (ret == -ENODEV) ++ continue; ++ else if (ret) ++ goto err; ++ ++ if (panel) { ++ bridge = drm_panel_bridge_add(panel, ++ DRM_MODE_CONNECTOR_DPI); ++ if (IS_ERR(bridge)) { ++ DRM_ERROR("panel-bridge endpoint %d\n", i); ++ ret = PTR_ERR(bridge); ++ goto err; ++ } ++ } ++ ++ if (bridge) { ++ ret = ltdc_encoder_init(ddev, bridge); ++ if (ret) { ++ DRM_ERROR("init encoder endpoint %d\n", i); ++ goto err; ++ } ++ } ++ } ++ ++ rstc = devm_reset_control_get_exclusive(dev, NULL); ++ ++ mutex_init(&ldev->err_lock); ++ + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + usleep_range(10, 20); +@@ -1206,24 +1289,6 @@ int ltdc_load(struct drm_device *ddev) + reg_clear(ldev->regs, LTDC_IER, + IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); + +- for (i = 0; i < MAX_IRQ; i++) { +- irq = platform_get_irq(pdev, i); +- if (irq == -EPROBE_DEFER) +- goto err; +- +- if (irq < 0) +- continue; +- +- ret = devm_request_threaded_irq(dev, irq, ltdc_irq, +- ltdc_irq_thread, IRQF_ONESHOT, +- dev_name(dev), ddev); +- if (ret) { +- DRM_ERROR("Failed to register LTDC interrupt\n"); +- goto err; +- } +- } +- +- + ret = ltdc_get_caps(ddev); + if (ret) { + DRM_ERROR("hardware identifier (0x%08x) not supported!\n", +@@ -1233,25 +1298,21 @@ int ltdc_load(struct drm_device *ddev) + + DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version); + +- /* Add endpoints panels or bridges if any */ +- for (i = 0; i < MAX_ENDPOINTS; i++) { +- if (panel[i]) { +- bridge[i] = drm_panel_bridge_add(panel[i], +- DRM_MODE_CONNECTOR_DPI); +- if (IS_ERR(bridge[i])) { +- DRM_ERROR("panel-bridge endpoint %d\n", i); +- ret = PTR_ERR(bridge[i]); +- goto err; +- } ++ for (i = 0; i < ldev->caps.nb_irq; i++) { ++ irq = platform_get_irq(pdev, i); ++ if (irq < 0) { ++ ret = irq; ++ goto err; + } + +- if (bridge[i]) { +- ret = ltdc_encoder_init(ddev, bridge[i]); +- if (ret) { +- DRM_ERROR("init encoder endpoint %d\n", i); +- goto err; +- } ++ ret = devm_request_threaded_irq(dev, irq, ltdc_irq, ++ ltdc_irq_thread, IRQF_ONESHOT, ++ dev_name(dev), ddev); ++ if (ret) { ++ DRM_ERROR("Failed to register LTDC interrupt\n"); ++ goto err; + } ++ + } + + crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); +@@ -1280,12 +1341,14 @@ int ltdc_load(struct drm_device *ddev) + + clk_disable_unprepare(ldev->pixel_clk); + ++ pinctrl_pm_select_sleep_state(ddev->dev); ++ + pm_runtime_enable(ddev->dev); + + return 0; + err: +- for (i = 0; i < MAX_ENDPOINTS; i++) +- drm_panel_bridge_remove(bridge[i]); ++ for (i = 0; i < nb_endpoints; i++) ++ drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); + + clk_disable_unprepare(ldev->pixel_clk); + +@@ -1294,11 +1357,14 @@ int ltdc_load(struct drm_device *ddev) + + void ltdc_unload(struct drm_device *ddev) + { +- int i; ++ struct device *dev = ddev->dev; ++ int nb_endpoints, i; + + DRM_DEBUG_DRIVER("\n"); + +- for (i = 0; i < MAX_ENDPOINTS; i++) ++ nb_endpoints = of_graph_get_endpoint_count(dev->of_node); ++ ++ for (i = 0; i < nb_endpoints; i++) + drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); + + pm_runtime_disable(ddev->dev); +diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h +index a1ad0ae3b..310e87f06 100644 +--- a/drivers/gpu/drm/stm/ltdc.h ++++ b/drivers/gpu/drm/stm/ltdc.h +@@ -19,6 +19,7 @@ struct ltdc_caps { + const u32 *pix_fmt_hw; /* supported pixel formats */ + bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ + int pad_max_freq_hz; /* max frequency supported by pad */ ++ int nb_irq; /* number of hardware interrupts */ + }; + + #define LTDC_MAX_LAYER 4 +diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c +index 240e8de24..66f790de8 100644 +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + #define WORK_REGISTER_THRESHOLD 0x00 + #define WORK_REGISTER_REPORT_RATE 0x08 +@@ -1042,6 +1044,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + const struct edt_i2c_chip_data *chip_data; + struct edt_ft5x06_ts_data *tsdata; + u8 buf[2] = { 0xfc, 0x00 }; ++ struct mipi_dsi_device *panel; ++ struct device_node *np; + struct input_dev *input; + unsigned long irq_flags; + int error; +@@ -1107,7 +1111,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + + error = edt_ft5x06_ts_identify(client, tsdata, fw_version); + if (error) { +- dev_err(&client->dev, "touchscreen probe failed\n"); ++ dev_dbg(&client->dev, "touchscreen probe failed\n"); + return error; + } + +@@ -1176,6 +1180,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + if (error) + return error; + ++ np = of_parse_phandle(client->dev.of_node, "panel", 0); ++ if (np) { ++ panel = of_find_mipi_dsi_device_by_node(np); ++ of_node_put(np); ++ if (!panel) ++ return -EPROBE_DEFER; ++ ++ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | ++ DL_FLAG_AUTOREMOVE_SUPPLIER); ++ put_device(&panel->dev); ++ } ++ + edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); + device_init_wakeup(&client->dev, 1); + +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 0403102e8..8816f2cd4 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -844,6 +845,8 @@ static int goodix_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { + struct goodix_ts_data *ts; ++ struct mipi_dsi_device *panel; ++ struct device_node *np; + int error; + + dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); +@@ -936,6 +939,17 @@ static int goodix_ts_probe(struct i2c_client *client, + return error; + } + ++ np = of_parse_phandle(client->dev.of_node, "panel", 0); ++ if (np) { ++ panel = of_find_mipi_dsi_device_by_node(np); ++ of_node_put(np); ++ if (!panel) ++ return -EPROBE_DEFER; ++ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | ++ DL_FLAG_AUTOREMOVE_SUPPLIER); ++ put_device(&panel->dev); ++ } ++ + return 0; + } + +@@ -990,6 +1004,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) + * sooner, delay 58ms here. + */ + msleep(58); ++ + return 0; + } + +@@ -1054,6 +1069,7 @@ static const struct of_device_id goodix_of_match[] = { + { .compatible = "goodix,gt9271" }, + { .compatible = "goodix,gt928" }, + { .compatible = "goodix,gt967" }, ++ { .compatible = "goodix,gt9147",}, + { } + }; + MODULE_DEVICE_TABLE(of, goodix_of_match); +diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h +index 735c8cfda..28a9ea94e 100644 +--- a/include/uapi/drm/drm_mode.h ++++ b/include/uapi/drm/drm_mode.h +@@ -97,6 +97,12 @@ extern "C" { + #define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) + #define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) + ++/* flags for polarity clock & data enable polarities */ ++#define DRM_MODE_FLAG_PPIXDATA (1 << 19) ++#define DRM_MODE_FLAG_NPIXDATA (1 << 20) ++#define DRM_MODE_FLAG_PDE (1 << 21) ++#define DRM_MODE_FLAG_NDE (1 << 22) ++ + /* Picture aspect ratio options */ + #define DRM_MODE_PICTURE_ASPECT_NONE 0 + #define DRM_MODE_PICTURE_ASPECT_4_3 1 +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch new file mode 100644 index 0000000..584ccd6 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch @@ -0,0 +1,253 @@ +From 9e9f45cd3d4887d9af58da15e627443838da1645 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:41:46 +0200 +Subject: [PATCH 08/23] ARM-stm32mp1-r1-HWSPINLOCK + +--- + Documentation/hwspinlock.txt | 10 ++- + drivers/hwspinlock/hwspinlock_core.c | 82 ++++++++++++++++++------ + drivers/hwspinlock/hwspinlock_internal.h | 2 + + 3 files changed, 73 insertions(+), 21 deletions(-) + +diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt +index 6f03713b7..605bd2dc8 100644 +--- a/Documentation/hwspinlock.txt ++++ b/Documentation/hwspinlock.txt +@@ -54,9 +54,11 @@ Should be called from a process context (might sleep). + struct hwspinlock *hwspin_lock_request_specific(unsigned int id); + + Assign a specific hwspinlock id and return its address, or NULL +-if that hwspinlock is already in use. Usually board code will +-be calling this function in order to reserve specific hwspinlock +-ids for predefined purposes. ++if that hwspinlock is already in use and not shared. If that specific ++hwspinlock is declared as shared, it can be requested and used by ++several users. ++Usually board code will be calling this function in order to reserve ++specific hwspinlock ids for predefined purposes. + + Should be called from a process context (might sleep). + +@@ -449,11 +451,13 @@ of which represents a single hardware lock:: + * struct hwspinlock - this struct represents a single hwspinlock instance + * @bank: the hwspinlock_device structure which owns this lock + * @lock: initialized and used by hwspinlock core ++ * @refcount: number of users (when shared) + * @priv: private data, owned by the underlying platform-specific hwspinlock drv + */ + struct hwspinlock { + struct hwspinlock_device *bank; + spinlock_t lock; ++ unsigned int refcount; + void *priv; + }; + +diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c +index 8862445aa..ac76631c7 100644 +--- a/drivers/hwspinlock/hwspinlock_core.c ++++ b/drivers/hwspinlock/hwspinlock_core.c +@@ -29,6 +29,8 @@ + + /* radix tree tags */ + #define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused */ ++#define HWSPINLOCK_EXCLUSIVE (1) /* tags an hwspinlock as exclusive */ ++#define HWSPINLOCK_SHARED (2) /* tags an hwspinlock as shared */ + + /* + * A radix tree is used to maintain the available hwspinlock instances. +@@ -308,7 +310,7 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock); + * @hwlock_spec: hwlock specifier as found in the device tree + * + * This is a simple translation function, suitable for hwspinlock platform +- * drivers that only has a lock specifier length of 1. ++ * drivers that only has a lock specifier length of 1 or 2. + * + * Returns a relative index of the lock within a specified bank on success, + * or -EINVAL on invalid specifier cell count. +@@ -316,7 +318,8 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock); + static inline int + of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) + { +- if (WARN_ON(hwlock_spec->args_count != 1)) ++ if (WARN_ON(hwlock_spec->args_count != 1 && ++ hwlock_spec->args_count != 2)) + return -EINVAL; + + return hwlock_spec->args[0]; +@@ -339,11 +342,12 @@ of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) + int of_hwspin_lock_get_id(struct device_node *np, int index) + { + struct of_phandle_args args; +- struct hwspinlock *hwlock; ++ struct hwspinlock *hwlock, *tmp; + struct radix_tree_iter iter; + void **slot; + int id; + int ret; ++ unsigned int tag; + + ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, + &args); +@@ -383,6 +387,37 @@ int of_hwspin_lock_get_id(struct device_node *np, int index) + } + id += hwlock->bank->base_id; + ++ /* Set the EXCLUSIVE / SHARED tag */ ++ if (args.args_count == 2 && args.args[1]) { ++ /* Tag SHARED unless already tagged EXCLUSIVE */ ++ if (radix_tree_tag_get(&hwspinlock_tree, id, ++ HWSPINLOCK_EXCLUSIVE)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ tag = HWSPINLOCK_SHARED; ++ } else { ++ /* Tag EXCLUSIVE unless already tagged SHARED */ ++ if (radix_tree_tag_get(&hwspinlock_tree, id, ++ HWSPINLOCK_SHARED)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ tag = HWSPINLOCK_EXCLUSIVE; ++ } ++ ++ /* mark this hwspinlock */ ++ hwlock = radix_tree_lookup(&hwspinlock_tree, id); ++ if (!hwlock) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ tmp = radix_tree_tag_set(&hwspinlock_tree, id, tag); ++ ++ /* self-sanity check which should never fail */ ++ WARN_ON(tmp != hwlock); ++ + out: + of_node_put(args.np); + return ret ? ret : id; +@@ -505,6 +540,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, + + spin_lock_init(&hwlock->lock); + hwlock->bank = bank; ++ hwlock->refcount = 0; + + ret = hwspin_lock_register_single(hwlock, base_id + i); + if (ret) +@@ -647,7 +683,7 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock) + { + struct device *dev = hwlock->bank->dev; + struct hwspinlock *tmp; +- int ret; ++ int ret, id; + + /* prevent underlying implementation from being removed */ + if (!try_module_get(dev->driver->owner)) { +@@ -664,13 +700,18 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock) + return ret; + } + ++ /* update shareable refcount */ ++ id = hwlock_to_id(hwlock); ++ if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && ++ hwlock->refcount++) ++ goto out; ++ + /* mark hwspinlock as used, should not fail */ +- tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock), +- HWSPINLOCK_UNUSED); ++ tmp = radix_tree_tag_clear(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); + + /* self-sanity check that should never fail */ + WARN_ON(tmp != hwlock); +- ++out: + return ret; + } + +@@ -764,9 +805,9 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) + /* sanity check (this shouldn't happen) */ + WARN_ON(hwlock_to_id(hwlock) != id); + +- /* make sure this hwspinlock is unused */ +- ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); +- if (ret == 0) { ++ /* make sure this hwspinlock is unused or shareable */ ++ if (!radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && ++ !radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED)) { + pr_warn("hwspinlock %u is already in use\n", id); + hwlock = NULL; + goto out; +@@ -799,7 +840,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock) + { + struct device *dev; + struct hwspinlock *tmp; +- int ret; ++ int ret, id; + + if (!hwlock) { + pr_err("invalid hwlock\n"); +@@ -810,30 +851,35 @@ int hwspin_lock_free(struct hwspinlock *hwlock) + mutex_lock(&hwspinlock_tree_lock); + + /* make sure the hwspinlock is used */ +- ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock), +- HWSPINLOCK_UNUSED); ++ id = hwlock_to_id(hwlock); ++ ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); + if (ret == 1) { + dev_err(dev, "%s: hwlock is already free\n", __func__); + dump_stack(); + ret = -EINVAL; +- goto out; ++ goto unlock; + } + + /* notify the underlying device that power is not needed */ + ret = pm_runtime_put(dev); + if (ret < 0) +- goto out; ++ goto unlock; ++ ++ /* update shareable refcount */ ++ if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && ++ --hwlock->refcount) ++ goto put; + + /* mark this hwspinlock as available */ +- tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock), +- HWSPINLOCK_UNUSED); ++ tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); + + /* sanity check (this shouldn't happen) */ + WARN_ON(tmp != hwlock); + ++put: + module_put(dev->driver->owner); + +-out: ++unlock: + mutex_unlock(&hwspinlock_tree_lock); + return ret; + } +diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h +index 9eb6bd020..c808e116c 100644 +--- a/drivers/hwspinlock/hwspinlock_internal.h ++++ b/drivers/hwspinlock/hwspinlock_internal.h +@@ -35,11 +35,13 @@ struct hwspinlock_ops { + * struct hwspinlock - this struct represents a single hwspinlock instance + * @bank: the hwspinlock_device structure which owns this lock + * @lock: initialized and used by hwspinlock core ++ * @refcount: number of users (when shared) + * @priv: private data, owned by the underlying platform-specific hwspinlock drv + */ + struct hwspinlock { + struct hwspinlock_device *bank; + spinlock_t lock; ++ unsigned int refcount; + void *priv; + }; + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch new file mode 100644 index 0000000..b221098 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch @@ -0,0 +1,3427 @@ +From 60d0b197857cc6e26cc8521986b4a85d912fd201 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:42:27 +0200 +Subject: [PATCH 09/23] ARM-stm32mp1-r1-I2C-IIO-IRQCHIP + +--- + drivers/i2c/busses/Kconfig | 1 + + drivers/i2c/busses/i2c-stm32.c | 19 +- + drivers/i2c/busses/i2c-stm32f4.c | 4 +- + drivers/i2c/busses/i2c-stm32f7.c | 644 ++++++++++++++++++---- + drivers/iio/adc/sd_adc_modulator.c | 84 ++- + drivers/iio/adc/stm32-adc-core.c | 84 +-- + drivers/iio/adc/stm32-adc-core.h | 9 + + drivers/iio/adc/stm32-adc.c | 129 ++++- + drivers/iio/adc/stm32-dfsdm-adc.c | 157 +++++- + drivers/iio/dac/stm32-dac-core.c | 153 +++-- + drivers/iio/dac/stm32-dac.c | 94 +++- + drivers/iio/trigger/stm32-timer-trigger.c | 164 +++++- + drivers/irqchip/irq-stm32-exti.c | 255 ++++++--- + 13 files changed, 1464 insertions(+), 333 deletions(-) + +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index 146ce40d8..19f05c44f 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -1008,6 +1008,7 @@ config I2C_STM32F7 + tristate "STMicroelectronics STM32F7 I2C support" + depends on ARCH_STM32 || COMPILE_TEST + select I2C_SLAVE ++ select I2C_SMBUS + help + Enable this option to add support for STM32 I2C controller embedded + in STM32F7 SoCs. +diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c +index 1da347e6a..448c0df71 100644 +--- a/drivers/i2c/busses/i2c-stm32.c ++++ b/drivers/i2c/busses/i2c-stm32.c +@@ -25,9 +25,11 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + /* Request and configure I2C TX dma channel */ + dma->chan_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(dma->chan_tx)) { +- dev_dbg(dev, "can't request DMA tx channel\n"); + ret = PTR_ERR(dma->chan_tx); +- goto fail_al; ++ if ((ret != -EPROBE_DEFER) && (ret != -ENODEV)) ++ dev_err(dev, "can't request DMA tx channel: %d\n", ret); ++ ++ goto fail_mem; + } + + memset(&dma_sconfig, 0, sizeof(dma_sconfig)); +@@ -37,15 +39,17 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); + if (ret < 0) { +- dev_err(dev, "can't configure tx channel\n"); ++ dev_err(dev, "can't configure tx channel: %d\n", ret); + goto fail_tx; + } + + /* Request and configure I2C RX dma channel */ + dma->chan_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(dma->chan_rx)) { +- dev_err(dev, "can't request DMA rx channel\n"); + ret = PTR_ERR(dma->chan_rx); ++ if ((ret != -EPROBE_DEFER) && (ret != -ENODEV)) ++ dev_err(dev, "can't request DMA rx channel: %d\n", ret); ++ + goto fail_tx; + } + +@@ -56,7 +60,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); + if (ret < 0) { +- dev_err(dev, "can't configure rx channel\n"); ++ dev_err(dev, "can't configure rx channel: %d\n", ret); + goto fail_rx; + } + +@@ -71,9 +75,10 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_release_channel(dma->chan_rx); + fail_tx: + dma_release_channel(dma->chan_tx); +-fail_al: ++fail_mem: + devm_kfree(dev, dma); +- dev_info(dev, "can't use DMA\n"); ++ if (ret == -ENODEV) ++ dev_info(dev, "doesn't use DMA\n"); + + return ERR_PTR(ret); + } +diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c +index ba600d77a..1b8cad506 100644 +--- a/drivers/i2c/busses/i2c-stm32f4.c ++++ b/drivers/i2c/busses/i2c-stm32f4.c +@@ -797,8 +797,10 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) + + rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(rst)) { +- dev_err(&pdev->dev, "Error: Missing controller reset\n"); + ret = PTR_ERR(rst); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Error: Missing reset ctrl\n"); ++ + goto clk_free; + } + reset_control_assert(rst); +diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c +index b2634afe0..8a82e331e 100644 +--- a/drivers/i2c/busses/i2c-stm32f7.c ++++ b/drivers/i2c/busses/i2c-stm32f7.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -29,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -49,6 +51,9 @@ + + /* STM32F7 I2C control 1 */ + #define STM32F7_I2C_CR1_PECEN BIT(23) ++#define STM32F7_I2C_CR1_ALERTEN BIT(22) ++#define STM32F7_I2C_CR1_SMBHEN BIT(20) ++#define STM32F7_I2C_CR1_WUPEN BIT(18) + #define STM32F7_I2C_CR1_SBC BIT(16) + #define STM32F7_I2C_CR1_RXDMAEN BIT(15) + #define STM32F7_I2C_CR1_TXDMAEN BIT(14) +@@ -119,6 +124,7 @@ + (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) + #define STM32F7_I2C_ISR_DIR BIT(16) + #define STM32F7_I2C_ISR_BUSY BIT(15) ++#define STM32F7_I2C_ISR_ALERT BIT(13) + #define STM32F7_I2C_ISR_PECERR BIT(11) + #define STM32F7_I2C_ISR_ARLO BIT(9) + #define STM32F7_I2C_ISR_BERR BIT(8) +@@ -132,6 +138,7 @@ + #define STM32F7_I2C_ISR_TXE BIT(0) + + /* STM32F7 I2C Interrupt Clear */ ++#define STM32F7_I2C_ICR_ALERTCF BIT(13) + #define STM32F7_I2C_ICR_PECCF BIT(11) + #define STM32F7_I2C_ICR_ARLOCF BIT(9) + #define STM32F7_I2C_ICR_BERRCF BIT(8) +@@ -148,7 +155,7 @@ + + #define STM32F7_I2C_MAX_LEN 0xff + #define STM32F7_I2C_DMA_LEN_MIN 0x16 +-#define STM32F7_I2C_MAX_SLAVE 0x2 ++#define STM32F7_I2C_MAX_SLAVE 0x3 + + #define STM32F7_I2C_DNF_DEFAULT 0 + #define STM32F7_I2C_DNF_MAX 16 +@@ -168,11 +175,25 @@ + + #define STM32F7_AUTOSUSPEND_DELAY (HZ / 100) + ++/** ++ * struct stm32f7_i2c_regs - i2c f7 registers backup ++ * @cr1: Control register 1 ++ * @cr2: Control register 2 ++ * @oar1: Own address 1 register ++ * @oar2: Own address 2 register ++ * @tmgr: Timing register ++ */ ++struct stm32f7_i2c_regs { ++ u32 cr1; ++ u32 cr2; ++ u32 oar1; ++ u32 oar2; ++ u32 tmgr; ++}; ++ + /** + * struct stm32f7_i2c_spec - private i2c specification timing + * @rate: I2C bus speed (Hz) +- * @rate_min: 80% of I2C bus speed (Hz) +- * @rate_max: 100% of I2C bus speed (Hz) + * @fall_max: Max fall time of both SDA and SCL signals (ns) + * @rise_max: Max rise time of both SDA and SCL signals (ns) + * @hddat_min: Min data hold time (ns) +@@ -183,8 +204,6 @@ + */ + struct stm32f7_i2c_spec { + u32 rate; +- u32 rate_min; +- u32 rate_max; + u32 fall_max; + u32 rise_max; + u32 hddat_min; +@@ -196,22 +215,22 @@ struct stm32f7_i2c_spec { + + /** + * struct stm32f7_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) + * @fall_time: Fall time (ns) + * @dnf: Digital filter coefficient (0-16) + * @analog_filter: Analog filter delay (On/Off) ++ * @fmp_clr_offset: Fast Mode Plus clear register offset from set register + */ + struct stm32f7_i2c_setup { +- enum stm32_i2c_speed speed; + u32 speed_freq; + u32 clock_src; + u32 rise_time; + u32 fall_time; + u8 dnf; + bool analog_filter; ++ u32 fmp_clr_offset; + }; + + /** +@@ -260,14 +279,38 @@ struct stm32f7_i2c_msg { + u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); + }; + ++/** ++ * struct stm32f7_i2c_host - SMBus host specific data ++ * @client: I2C slave device that represents SMBus host ++ * @notify_start: indicate that this is the start of the notify transaction ++ * @addr: device address of SMBus device that initiate SMBus host protocol ++ */ ++struct stm32f7_i2c_host { ++ struct i2c_client *client; ++ bool notify_start; ++ u8 addr; ++}; ++ ++/** ++ * struct stm32f7_i2c_alert - SMBus alert specific data ++ * @setup: platform data for the smbus_alert i2c client ++ * @ara: I2C slave device used to respond to the SMBus Alert with Alert ++ * Response Address ++ */ ++struct stm32f7_i2c_alert { ++ struct i2c_smbus_alert_setup setup; ++ struct i2c_client *ara; ++}; ++ + /** + * struct stm32f7_i2c_dev - private data of the controller + * @adap: I2C adapter for this controller + * @dev: device for this controller ++ * @irq_event: interrupt event line for the controller + * @base: virtual memory area + * @complete: completion of I2C message + * @clk: hw i2c clock +- * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+ ++ * @bus_rate: I2C clock frequency of the controller. + * @msg: Pointer to data to be written + * @msg_num: number of I2C messages to be executed + * @msg_id: message identifiant +@@ -276,20 +319,28 @@ struct stm32f7_i2c_msg { + * @timing: I2C computed timings + * @slave: list of slave devices registered on the I2C bus + * @slave_running: slave device currently used ++ * @regs: registers backup for suspend/resume + * @slave_dir: transfer direction for the current slave device + * @master_mode: boolean to know in which mode the I2C is running (master or + * slave) + * @dma: dma data + * @use_dma: boolean to know if dma is used in the current transfer + * @regmap: holds SYSCFG phandle for Fast Mode Plus bits ++ * @regmap_sreg: register address for setting Fast Mode Plus bits ++ * @regmap_creg: register address for clearing Fast Mode Plus bits ++ * @regmap_mask: mask for Fast Mode Plus bits ++ * @host: SMBus host protocol specific data ++ * @alert: SMBus alert specific data ++ * @wakeup_src: boolean to know if the device is a wakeup source + */ + struct stm32f7_i2c_dev { + struct i2c_adapter adap; + struct device *dev; + void __iomem *base; ++ int irq_event; + struct completion complete; + struct clk *clk; +- int speed; ++ unsigned int bus_rate; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_id; +@@ -298,11 +349,18 @@ struct stm32f7_i2c_dev { + struct stm32f7_i2c_timings timing; + struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; + struct i2c_client *slave_running; ++ struct stm32f7_i2c_regs regs; + u32 slave_dir; + bool master_mode; + struct stm32_i2c_dma *dma; + bool use_dma; + struct regmap *regmap; ++ u32 regmap_sreg; ++ u32 regmap_creg; ++ u32 regmap_mask; ++ struct stm32f7_i2c_host *host; ++ struct stm32f7_i2c_alert *alert; ++ bool wakeup_src; + }; + + /* +@@ -312,11 +370,13 @@ struct stm32f7_i2c_dev { + * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast, + * and Fast-mode Plus I2C-bus devices + */ ++#define I2C_STD_RATE 100000 ++#define I2C_FAST_RATE 400000 ++#define I2C_FASTPLUS_RATE 1000000 + static struct stm32f7_i2c_spec i2c_specs[] = { +- [STM32_I2C_SPEED_STANDARD] = { +- .rate = 100000, +- .rate_min = 80000, +- .rate_max = 100000, ++ /* Standard - 100KHz */ ++ { ++ .rate = I2C_STD_RATE, + .fall_max = 300, + .rise_max = 1000, + .hddat_min = 0, +@@ -325,10 +385,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { + .l_min = 4700, + .h_min = 4000, + }, +- [STM32_I2C_SPEED_FAST] = { +- .rate = 400000, +- .rate_min = 320000, +- .rate_max = 400000, ++ /* Fast - 400KHz */ ++ { ++ .rate = I2C_FAST_RATE, + .fall_max = 300, + .rise_max = 300, + .hddat_min = 0, +@@ -337,10 +396,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { + .l_min = 1300, + .h_min = 600, + }, +- [STM32_I2C_SPEED_FAST_PLUS] = { +- .rate = 1000000, +- .rate_min = 800000, +- .rate_max = 1000000, ++ /* FastPlus - 1MHz */ ++ { ++ .rate = I2C_FASTPLUS_RATE, + .fall_max = 100, + .rise_max = 120, + .hddat_min = 0, +@@ -358,6 +416,14 @@ static const struct stm32f7_i2c_setup stm32f7_setup = { + .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, + }; + ++static const struct stm32f7_i2c_setup stm32mp15_setup = { ++ .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, ++ .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, ++ .dnf = STM32F7_I2C_DNF_DEFAULT, ++ .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, ++ .fmp_clr_offset = 0x40, ++}; ++ + static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask) + { + writel_relaxed(readl_relaxed(reg) | mask, reg); +@@ -373,10 +439,24 @@ static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); + } + ++static struct stm32f7_i2c_spec *get_specs(u32 rate) ++{ ++ 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); ++} ++ ++#define RATE_MIN(rate) (rate / 100 * 80) + static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + struct stm32f7_i2c_setup *setup, + struct stm32f7_i2c_timings *output) + { ++ struct stm32f7_i2c_spec *specs; + u32 p_prev = STM32F7_PRESC_MAX; + u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, + setup->clock_src); +@@ -394,18 +474,19 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + u16 p, l, a, h; + int ret = 0; + +- if (setup->speed >= STM32_I2C_SPEED_END) { +- dev_err(i2c_dev->dev, "speed out of bound {%d/%d}\n", +- setup->speed, STM32_I2C_SPEED_END - 1); ++ specs = get_specs(setup->speed_freq); ++ if (specs == ERR_PTR(-EINVAL)) { ++ dev_err(i2c_dev->dev, "speed out of bound {%d}\n", ++ 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)) { + dev_err(i2c_dev->dev, + "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", +- 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; + } + +@@ -416,12 +497,6 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + return -EINVAL; + } + +- if (setup->speed_freq > i2c_specs[setup->speed].rate) { +- dev_err(i2c_dev->dev, "ERROR: Freq {%d/%d}\n", +- setup->speed_freq, i2c_specs[setup->speed].rate); +- return -EINVAL; +- } +- + /* Analog and Digital Filters */ + af_delay_min = + (setup->analog_filter ? +@@ -431,13 +506,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); + dnf_delay = setup->dnf * i2cclk; + +- 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; +@@ -492,8 +567,8 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + + tsync = af_delay_min + dnf_delay + (2 * i2cclk); + s = NULL; +- clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; +- clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; ++ clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq); ++ clk_min = NSEC_PER_SEC / setup->speed_freq; + + /* + * Among Prescaler possibilities discovered above figures out SCL Low +@@ -511,7 +586,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + for (l = 0; l < STM32F7_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; +@@ -523,7 +598,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + 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)) { + int clk_error = tscl - i2cbus; + +@@ -569,13 +644,23 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + return ret; + } + ++static u32 get_lower_rate(u32 rate) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) ++ if (i2c_specs[i].rate < rate) ++ return i2c_specs[i].rate; ++ ++ return i2c_specs[0].rate; ++} ++ + static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + struct stm32f7_i2c_setup *setup) + { + int ret = 0; + +- setup->speed = i2c_dev->speed; +- setup->speed_freq = i2c_specs[setup->speed].rate; ++ setup->speed_freq = i2c_dev->bus_rate; + setup->clock_src = clk_get_rate(i2c_dev->clk); + + if (!setup->clock_src) { +@@ -589,14 +674,12 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + if (ret) { + dev_err(i2c_dev->dev, + "failed to compute I2C timings.\n"); +- if (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) { +- i2c_dev->speed--; +- setup->speed = i2c_dev->speed; ++ if (setup->speed_freq > I2C_STD_RATE) { + setup->speed_freq = +- i2c_specs[setup->speed].rate; ++ get_lower_rate(setup->speed_freq); + dev_warn(i2c_dev->dev, + "downgrade I2C Speed Freq to (%i)\n", +- i2c_specs[setup->speed].rate); ++ setup->speed_freq); + } else { + break; + } +@@ -608,13 +691,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + return ret; + } + +- dev_dbg(i2c_dev->dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n", +- setup->speed, setup->speed_freq, setup->clock_src); ++ dev_dbg(i2c_dev->dev, "I2C Freq(%i), Clk Source(%i)\n", ++ setup->speed_freq, setup->clock_src); + dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", + setup->rise_time, setup->fall_time); + dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", + (setup->analog_filter ? "On" : "Off"), setup->dnf); + ++ i2c_dev->bus_rate = setup->speed_freq; ++ + return 0; + } + +@@ -1264,11 +1349,21 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + int i; + + /* +- * slave[0] supports 7-bit and 10-bit slave address +- * slave[1] supports 7-bit slave address only ++ * slave[0] support only SMBus Host address (0x8) ++ * slave[1] supports 7-bit and 10-bit slave address ++ * slave[2] supports 7-bit slave address only + */ +- for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) { +- if (i == 1 && (slave->flags & I2C_CLIENT_TEN)) ++ if (i2c_dev->host) { ++ if (slave->addr == 0x08) { ++ if (i2c_dev->slave[0]) ++ goto fail; ++ *id = 0; ++ return 0; ++ } ++ } ++ ++ for (i = STM32F7_I2C_MAX_SLAVE - 1; i > 0; i--) { ++ if (i == 2 && (slave->flags & I2C_CLIENT_TEN)) + continue; + if (!i2c_dev->slave[i]) { + *id = i; +@@ -1276,6 +1371,7 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + } + } + ++fail: + dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); + + return -EINVAL; +@@ -1407,7 +1503,8 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) + + /* NACK received */ + if (status & STM32F7_I2C_ISR_NACKF) { +- dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__); ++ dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", ++ __func__, f7_msg->addr); + writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); + f7_msg->result = -ENXIO; + } +@@ -1528,6 +1625,13 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) + f7_msg->result = -EINVAL; + } + ++ if (status & STM32F7_I2C_ISR_ALERT) { ++ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); ++ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); ++ i2c_handle_smbus_alert(i2c_dev->alert->ara); ++ return IRQ_HANDLED; ++ } ++ + if (!i2c_dev->slave_running) { + u32 mask; + /* Disable interrupts */ +@@ -1671,6 +1775,9 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + return ret; + } + ++static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, ++ bool enable); ++ + static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + { + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); +@@ -1697,7 +1804,16 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + if (ret < 0) + return ret; + +- if (id == 0) { ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) ++ stm32f7_i2c_enable_wakeup(i2c_dev, true); ++ ++ switch (id) { ++ case 0: ++ /* Slave SMBus Host */ ++ i2c_dev->slave[id] = slave; ++ break; ++ ++ case 1: + /* Configure Own Address 1 */ + oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); + oar1 &= ~STM32F7_I2C_OAR1_MASK; +@@ -1710,7 +1826,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + oar1 |= STM32F7_I2C_OAR1_OA1EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); +- } else if (id == 1) { ++ break; ++ ++ case 2: + /* Configure Own Address 2 */ + oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); + oar2 &= ~STM32F7_I2C_OAR2_MASK; +@@ -1723,7 +1841,10 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + oar2 |= STM32F7_I2C_OAR2_OA2EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); +- } else { ++ break; ++ ++ default: ++ dev_err(dev, "I2C slave id not supported\n"); + ret = -ENODEV; + goto pm_free; + } +@@ -1738,6 +1859,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + + ret = 0; + pm_free: ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) ++ stm32f7_i2c_enable_wakeup(i2c_dev, false); ++ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1761,18 +1885,20 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) + if (ret < 0) + return ret; + +- if (id == 0) { ++ if (id == 1) { + mask = STM32F7_I2C_OAR1_OA1EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); +- } else { ++ } else if (id == 2) { + mask = STM32F7_I2C_OAR2_OA2EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); + } + + i2c_dev->slave[id] = NULL; + +- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); ++ stm32f7_i2c_enable_wakeup(i2c_dev, false); ++ } + + pm_runtime_mark_last_busy(i2c_dev->dev); + pm_runtime_put_autosuspend(i2c_dev->dev); +@@ -1780,6 +1906,31 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) + return 0; + } + ++static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev, ++ bool enable) ++{ ++ int ret; ++ ++ if (i2c_dev->bus_rate <= I2C_FAST_RATE || ++ IS_ERR_OR_NULL(i2c_dev->regmap)) { ++ /* Optional */ ++ return 0; ++ } ++ ++ if (i2c_dev->regmap_sreg == i2c_dev->regmap_creg) ++ ret = regmap_update_bits(i2c_dev->regmap, ++ i2c_dev->regmap_sreg, ++ i2c_dev->regmap_mask, ++ enable ? i2c_dev->regmap_mask : 0); ++ else ++ ret = regmap_write(i2c_dev->regmap, ++ enable ? i2c_dev->regmap_sreg : ++ i2c_dev->regmap_creg, ++ i2c_dev->regmap_mask); ++ ++ return ret; ++} ++ + static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev, + struct stm32f7_i2c_dev *i2c_dev) + { +@@ -1801,7 +1952,137 @@ static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev, + if (ret) + return ret; + +- return regmap_update_bits(i2c_dev->regmap, reg, mask, mask); ++ i2c_dev->regmap_sreg = reg; ++ i2c_dev->regmap_creg = reg + i2c_dev->setup.fmp_clr_offset; ++ i2c_dev->regmap_mask = mask; ++ ++ return stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); ++} ++ ++static int stm32f7_i2c_smbus_host_cb(struct i2c_client *client, ++ enum i2c_slave_event event, ++ u8 *val) ++{ ++ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(client->adapter); ++ struct stm32f7_i2c_host *host = i2c_dev->host; ++ int ret; ++ ++ switch (event) { ++ case I2C_SLAVE_WRITE_REQUESTED: ++ host->notify_start = true; ++ break; ++ case I2C_SLAVE_WRITE_RECEIVED: ++ /* We only retrieve the first byte received (addr) ++ * From Documentation/i2c/smbus-protocol: ++ * There is currently no way to retrieve the data parameter ++ * from the client. ++ */ ++ if (!host->notify_start) ++ break; ++ host->addr = *val; ++ host->notify_start = false; ++ break; ++ case I2C_SLAVE_STOP: ++ ret = i2c_handle_smbus_host_notify(client->adapter, ++ host->addr); ++ if (ret < 0) { ++ dev_dbg(i2c_dev->dev, "failed to handle host_notify (%d)\n", ++ ret); ++ return ret; ++ } ++ break; ++ default: ++ dev_err(i2c_dev->dev, "slave event not supported\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_host *host; ++ struct i2c_adapter *adap = &i2c_dev->adap; ++ struct device *dev = i2c_dev->dev; ++ void __iomem *base = i2c_dev->base; ++ struct i2c_board_info host_notify_board_info = { ++ I2C_BOARD_INFO("smbus_host_notify", 0x8), ++ .flags = I2C_CLIENT_SLAVE, ++ }; ++ int ret; ++ ++ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); ++ if (!host) ++ return -ENOMEM; ++ ++ host->client = i2c_new_client_device(adap, &host_notify_board_info); ++ if (IS_ERR(host->client)) ++ return PTR_ERR(host->client); ++ ++ i2c_dev->host = host; ++ ++ ret = i2c_slave_register(host->client, stm32f7_i2c_smbus_host_cb); ++ if (ret) { ++ i2c_dev->host = NULL; ++ i2c_unregister_device(host->client); ++ return ret; ++ } ++ ++ /* Enable SMBus Host address */ ++ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN); ++ ++ return 0; ++} ++ ++static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ void __iomem *base = i2c_dev->base; ++ struct stm32f7_i2c_host *host = i2c_dev->host; ++ ++ if (host) { ++ /* Disable SMBus Host address */ ++ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_SMBHEN); ++ i2c_slave_unregister(host->client); ++ i2c_dev->host = NULL; ++ i2c_unregister_device(host->client); ++ } ++} ++ ++static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_alert *alert; ++ struct i2c_adapter *adap = &i2c_dev->adap; ++ struct device *dev = i2c_dev->dev; ++ void __iomem *base = i2c_dev->base; ++ ++ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL); ++ if (!alert) ++ return -ENOMEM; ++ ++ alert->ara = i2c_setup_smbus_alert(adap, &alert->setup); ++ if (!alert->ara) ++ return -ENOMEM; ++ ++ i2c_dev->alert = alert; ++ ++ /* Enable SMBus Alert */ ++ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN); ++ ++ return 0; ++} ++ ++static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_alert *alert = i2c_dev->alert; ++ void __iomem *base = i2c_dev->base; ++ ++ if (alert) { ++ /* Disable SMBus Alert */ ++ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_ALERTEN); ++ i2c_unregister_device(alert->ara); ++ } + } + + static u32 stm32f7_i2c_func(struct i2c_adapter *adap) +@@ -1811,7 +2092,7 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap) + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC | +- I2C_FUNC_SMBUS_I2C_BLOCK; ++ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HOST_NOTIFY; + } + + static const struct i2c_algorithm stm32f7_i2c_algo = { +@@ -1827,11 +2108,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + struct stm32f7_i2c_dev *i2c_dev; + const struct stm32f7_i2c_setup *setup; + struct resource *res; +- u32 clk_rate, rise_time, fall_time; ++ u32 rise_time, fall_time; + struct i2c_adapter *adap; + struct reset_control *rst; + dma_addr_t phy_addr; +- int irq_error, irq_event, ret; ++ int irq_error, ret; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) +@@ -1843,12 +2124,12 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + return PTR_ERR(i2c_dev->base); + phy_addr = (dma_addr_t)res->start; + +- irq_event = platform_get_irq(pdev, 0); +- if (irq_event <= 0) { +- if (irq_event != -EPROBE_DEFER) ++ i2c_dev->irq_event = platform_get_irq(pdev, 0); ++ if (i2c_dev->irq_event <= 0) { ++ if (i2c_dev->irq_event != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", +- irq_event); +- return irq_event ? : -ENOENT; ++ i2c_dev->irq_event); ++ return i2c_dev->irq_event ? : -ENOENT; + } + + irq_error = platform_get_irq(pdev, 1); +@@ -1859,9 +2140,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + return irq_error ? : -ENOENT; + } + ++ i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, ++ "wakeup-source"); ++ + i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c_dev->clk)) { +- dev_err(&pdev->dev, "Error: Missing controller clock\n"); ++ if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get controller clock\n"); + return PTR_ERR(i2c_dev->clk); + } + +@@ -1871,24 +2156,23 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + return ret; + } + +- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; + ret = device_property_read_u32(&pdev->dev, "clock-frequency", +- &clk_rate); +- if (!ret && clk_rate >= 1000000) { +- i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS; +- ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); +- if (ret) +- goto clk_free; +- } else if (!ret && clk_rate >= 400000) { +- i2c_dev->speed = STM32_I2C_SPEED_FAST; +- } else if (!ret && clk_rate >= 100000) { +- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; ++ &i2c_dev->bus_rate); ++ if (ret) ++ i2c_dev->bus_rate = I2C_STD_RATE; ++ ++ if (i2c_dev->bus_rate > I2C_FASTPLUS_RATE) { ++ dev_err(&pdev->dev, "Invalid bus speed (%i>%i)\n", ++ i2c_dev->bus_rate, I2C_FASTPLUS_RATE); ++ return -EINVAL; + } + + rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(rst)) { +- dev_err(&pdev->dev, "Error: Missing controller reset\n"); + ret = PTR_ERR(rst); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Error: Missing reset ctrl\n"); ++ + goto clk_free; + } + reset_control_assert(rst); +@@ -1897,14 +2181,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + + i2c_dev->dev = &pdev->dev; + +- ret = devm_request_threaded_irq(&pdev->dev, irq_event, ++ ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event, + stm32f7_i2c_isr_event, + stm32f7_i2c_isr_event_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq event %i\n", +- irq_event); ++ i2c_dev->irq_event); + goto clk_free; + } + +@@ -1938,6 +2222,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + if (ret) + goto clk_free; + ++ /* Setup Fast mode plus if necessary */ ++ if (i2c_dev->bus_rate > I2C_FAST_RATE) { ++ ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); ++ if (ret) ++ goto clk_free; ++ } ++ + adap = &i2c_dev->adap; + i2c_set_adapdata(adap, i2c_dev); + snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)", +@@ -1959,10 +2250,17 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + i2c_dev->dma = NULL; + else if (IS_ERR(i2c_dev->dma)) { + ret = PTR_ERR(i2c_dev->dma); +- if (ret != -EPROBE_DEFER) +- dev_err(&pdev->dev, +- "Failed to request dma error %i\n", ret); +- goto clk_free; ++ goto fmp_clear; ++ } ++ ++ if (i2c_dev->wakeup_src) { ++ device_set_wakeup_capable(i2c_dev->dev, true); ++ ++ ret = dev_pm_set_wake_irq(i2c_dev->dev, i2c_dev->irq_event); ++ if (ret) { ++ dev_err(i2c_dev->dev, "Failed to set wake up irq\n"); ++ goto clr_wakeup_capable; ++ } + } + + platform_set_drvdata(pdev, i2c_dev); +@@ -1981,6 +2279,26 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + if (ret) + goto pm_disable; + ++ if (device_property_read_bool(&pdev->dev, "st,smbus-host-notify")) { ++ ret = stm32f7_i2c_enable_smbus_host(i2c_dev); ++ if (ret) { ++ dev_err(i2c_dev->dev, ++ "failed to enable SMBus host notify (%d)\n", ++ ret); ++ goto i2c_adapter_remove; ++ } ++ } ++ ++ if (device_property_read_bool(&pdev->dev, "st,smbus-alert")) { ++ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev); ++ if (ret) { ++ dev_err(i2c_dev->dev, ++ "failed to enable SMBus alert protocol (%d)\n", ++ ret); ++ goto host_notify_disable; ++ } ++ } ++ + dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); + + pm_runtime_mark_last_busy(i2c_dev->dev); +@@ -1988,17 +2306,33 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + + return 0; + ++host_notify_disable: ++ stm32f7_i2c_disable_smbus_host(i2c_dev); ++ ++i2c_adapter_remove: ++ i2c_del_adapter(adap); ++ + pm_disable: + pm_runtime_put_noidle(i2c_dev->dev); + pm_runtime_disable(i2c_dev->dev); + pm_runtime_set_suspended(i2c_dev->dev); + pm_runtime_dont_use_autosuspend(i2c_dev->dev); + ++ if (i2c_dev->wakeup_src) ++ dev_pm_clear_wake_irq(i2c_dev->dev); ++ ++clr_wakeup_capable: ++ if (i2c_dev->wakeup_src) ++ device_set_wakeup_capable(i2c_dev->dev, false); ++ + if (i2c_dev->dma) { + stm32_i2c_dma_free(i2c_dev->dma); + i2c_dev->dma = NULL; + } + ++fmp_clear: ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); ++ + clk_free: + clk_disable_unprepare(i2c_dev->clk); + +@@ -2009,9 +2343,22 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) + { + struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + ++ stm32f7_i2c_disable_smbus_alert(i2c_dev); ++ ++ stm32f7_i2c_disable_smbus_host(i2c_dev); ++ + i2c_del_adapter(&i2c_dev->adap); + pm_runtime_get_sync(i2c_dev->dev); + ++ if (i2c_dev->wakeup_src) { ++ dev_pm_clear_wake_irq(i2c_dev->dev); ++ /* ++ * enforce that wakeup is disabled and that the device ++ * is marked as non wakeup capable ++ */ ++ device_init_wakeup(i2c_dev->dev, false); ++ } ++ + pm_runtime_put_noidle(i2c_dev->dev); + pm_runtime_disable(i2c_dev->dev); + pm_runtime_set_suspended(i2c_dev->dev); +@@ -2022,13 +2369,14 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) + i2c_dev->dma = NULL; + } + ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); ++ + clk_disable_unprepare(i2c_dev->clk); + + return 0; + } + +-#ifdef CONFIG_PM +-static int stm32f7_i2c_runtime_suspend(struct device *dev) ++static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) + { + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + +@@ -2038,7 +2386,7 @@ static int stm32f7_i2c_runtime_suspend(struct device *dev) + return 0; + } + +-static int stm32f7_i2c_runtime_resume(struct device *dev) ++static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) + { + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + int ret; +@@ -2053,15 +2401,125 @@ static int stm32f7_i2c_runtime_resume(struct device *dev) + + return 0; + } +-#endif ++ ++static int __maybe_unused ++stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ int ret; ++ ++ ret = pm_runtime_get_sync(i2c_dev->dev); ++ if (ret < 0) ++ return ret; ++ ++ i2c_dev->regs.cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); ++ i2c_dev->regs.cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); ++ i2c_dev->regs.oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); ++ i2c_dev->regs.oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); ++ i2c_dev->regs.tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR); ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); ++ ++ pm_runtime_put_sync(i2c_dev->dev); ++ ++ return ret; ++} ++ ++static int __maybe_unused ++stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ u32 cr1; ++ int ret; ++ ++ ret = pm_runtime_get_sync(i2c_dev->dev); ++ if (ret < 0) ++ return ret; ++ ++ cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); ++ if (cr1 & STM32F7_I2C_CR1_PE) ++ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_PE); ++ ++ writel_relaxed(i2c_dev->regs.tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR); ++ writel_relaxed(i2c_dev->regs.cr1 & ~STM32F7_I2C_CR1_PE, ++ i2c_dev->base + STM32F7_I2C_CR1); ++ if (i2c_dev->regs.cr1 & STM32F7_I2C_CR1_PE) ++ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_PE); ++ writel_relaxed(i2c_dev->regs.cr2, i2c_dev->base + STM32F7_I2C_CR2); ++ writel_relaxed(i2c_dev->regs.oar1, i2c_dev->base + STM32F7_I2C_OAR1); ++ writel_relaxed(i2c_dev->regs.oar2, i2c_dev->base + STM32F7_I2C_OAR2); ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); ++ ++ pm_runtime_put_sync(i2c_dev->dev); ++ ++ return ret; ++} ++ ++static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, ++ bool enable) ++{ ++ void __iomem *base = i2c_dev->base; ++ u32 mask = STM32F7_I2C_CR1_WUPEN; ++ ++ if (!i2c_dev->wakeup_src) ++ return; ++ ++ if (enable) { ++ device_set_wakeup_enable(i2c_dev->dev, true); ++ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); ++ readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); ++ } else { ++ device_set_wakeup_enable(i2c_dev->dev, false); ++ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); ++ } ++} ++ ++static int __maybe_unused stm32f7_i2c_suspend(struct device *dev) ++{ ++ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ i2c_mark_adapter_suspended(&i2c_dev->adap); ++ ret = stm32f7_i2c_regs_backup(i2c_dev); ++ if (ret < 0) ++ return ret; ++ ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { ++ pinctrl_pm_select_sleep_state(dev); ++ pm_runtime_force_suspend(dev); ++ } ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32f7_i2c_resume(struct device *dev) ++{ ++ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { ++ ret = pm_runtime_force_resume(dev); ++ if (ret < 0) ++ return ret; ++ pinctrl_pm_select_default_state(dev); ++ } ++ ++ ret = stm32f7_i2c_regs_restore(i2c_dev); ++ if (ret < 0) ++ return ret; ++ i2c_mark_adapter_resumed(&i2c_dev->adap); ++ ++ return 0; ++} + + static const struct dev_pm_ops stm32f7_i2c_pm_ops = { + SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, + stm32f7_i2c_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume) + }; + + static const struct of_device_id stm32f7_i2c_match[] = { + { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, ++ { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup}, + {}, + }; + MODULE_DEVICE_TABLE(of, stm32f7_i2c_match); +diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c +index 560d8c7d9..c0a6e89cd 100644 +--- a/drivers/iio/adc/sd_adc_modulator.c ++++ b/drivers/iio/adc/sd_adc_modulator.c +@@ -10,8 +10,7 @@ + #include + #include + #include +- +-static const struct iio_info iio_sd_mod_iio_info; ++#include + + static const struct iio_chan_spec iio_sd_mod_ch = { + .type = IIO_VOLTAGE, +@@ -21,36 +20,99 @@ static const struct iio_chan_spec iio_sd_mod_ch = { + .realbits = 1, + .shift = 0, + }, ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), ++}; ++ ++static const struct iio_chan_spec iio_sd_mod_ch_ads = { ++ .type = IIO_VOLTAGE, ++ .indexed = 1, ++ .scan_type = { ++ .sign = 'u', ++ .realbits = 1, ++ .shift = 0, ++ }, ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), ++ .differential = 1, ++}; ++ ++struct iio_sd_mod_priv { ++ int vref_mv; ++}; ++ ++static const struct of_device_id sd_adc_of_match[] = { ++ { .compatible = "sd-modulator", .data = &iio_sd_mod_ch }, ++ { .compatible = "ads1201", .data = &iio_sd_mod_ch_ads }, ++ { } ++}; ++ ++static int iio_sd_mod_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int *val, ++ int *val2, long mask) ++{ ++ struct iio_sd_mod_priv *priv = iio_priv(indio_dev); ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SCALE: ++ *val = priv->vref_mv; ++ *val2 = chan->scan_type.realbits; ++ return IIO_VAL_INT; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct iio_info iio_sd_mod_iio_info = { ++ .read_raw = iio_sd_mod_read_raw, + }; + + static int iio_sd_mod_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct iio_sd_mod_priv *priv; ++ struct regulator *vref; + struct iio_dev *iio; ++ int ret; + +- iio = devm_iio_device_alloc(dev, 0); ++ iio = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!iio) + return -ENOMEM; + ++ iio->channels = (const struct iio_chan_spec *) ++ of_match_device(sd_adc_of_match, &pdev->dev)->data; ++ ++ priv = iio_priv(iio); ++ + iio->dev.parent = dev; + iio->dev.of_node = dev->of_node; + iio->name = dev_name(dev); + iio->info = &iio_sd_mod_iio_info; + iio->modes = INDIO_BUFFER_HARDWARE; +- + iio->num_channels = 1; +- iio->channels = &iio_sd_mod_ch; + +- platform_set_drvdata(pdev, iio); ++ vref = devm_regulator_get_optional(dev, "vref"); ++ if (IS_ERR(vref)) { ++ ret = PTR_ERR(vref); ++ if (ret != -ENODEV) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "vref get failed, %d\n", ret); ++ return ret; ++ } ++ } ++ ++ if (!IS_ERR(vref)) { ++ ret = regulator_get_voltage(vref); ++ if (ret < 0) { ++ dev_err(dev, "vref get failed, %d\n", ret); ++ return ret; ++ } ++ ++ priv->vref_mv = ret / 1000; ++ dev_dbg(dev, "vref+=%dmV\n", priv->vref_mv); ++ } + + return devm_iio_device_register(&pdev->dev, iio); + } + +-static const struct of_device_id sd_adc_of_match[] = { +- { .compatible = "sd-modulator" }, +- { .compatible = "ads1201" }, +- { } +-}; + MODULE_DEVICE_TABLE(of, sd_adc_of_match); + + static struct platform_driver iio_sd_mod_adc = { +diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c +index 93a096a91..0e2068ec0 100644 +--- a/drivers/iio/adc/stm32-adc-core.c ++++ b/drivers/iio/adc/stm32-adc-core.c +@@ -38,12 +38,12 @@ + #define HAS_ANASWVDD BIT(1) + + /** +- * stm32_adc_common_regs - stm32 common registers, compatible dependent data ++ * struct stm32_adc_common_regs - stm32 common registers + * @csr: common status register offset + * @ccr: common control register offset +- * @eoc1: adc1 end of conversion flag in @csr +- * @eoc2: adc2 end of conversion flag in @csr +- * @eoc3: adc3 end of conversion flag in @csr ++ * @eoc1_msk: adc1 end of conversion flag in @csr ++ * @eoc2_msk: adc2 end of conversion flag in @csr ++ * @eoc3_msk: adc3 end of conversion flag in @csr + * @ier: interrupt enable register offset for each adc + * @eocie_msk: end of conversion interrupt enable mask in @ier + */ +@@ -60,17 +60,19 @@ struct stm32_adc_common_regs { + struct stm32_adc_priv; + + /** +- * stm32_adc_priv_cfg - stm32 core compatible configuration data ++ * struct stm32_adc_priv_cfg - stm32 core compatible configuration data + * @regs: common registers for all instances + * @clk_sel: clock selection routine + * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) + * @has_syscfg: SYSCFG capability flags ++ * @num_irqs: number of interrupt lines + */ + struct stm32_adc_priv_cfg { + const struct stm32_adc_common_regs *regs; + int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); + u32 max_clk_rate_hz; + unsigned int has_syscfg; ++ unsigned int num_irqs; + }; + + /** +@@ -79,6 +81,7 @@ struct stm32_adc_priv_cfg { + * @domain: irq domain reference + * @aclk: clock reference for the analog circuitry + * @bclk: bus clock common for all ADCs, depends on part used ++ * @max_clk_rate: desired maximum clock rate + * @booster: booster supply reference + * @vdd: vdd supply reference + * @vdda: vdda analog supply reference +@@ -95,6 +98,7 @@ struct stm32_adc_priv { + struct irq_domain *domain; + struct clk *aclk; + struct clk *bclk; ++ u32 max_clk_rate; + struct regulator *booster; + struct regulator *vdd; + struct regulator *vdda; +@@ -117,6 +121,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8}; + + /** + * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler ++ * @pdev: platform device + * @priv: stm32 ADC core private data + * Select clock prescaler used for analog conversions, before using ADC. + */ +@@ -140,7 +145,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, + } + + for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { +- if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz) ++ if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate) + break; + } + if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { +@@ -229,7 +234,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + if (ckmode) + continue; + +- if ((rate / div) <= priv->cfg->max_clk_rate_hz) ++ if ((rate / div) <= priv->max_clk_rate) + goto out; + } + } +@@ -249,7 +254,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + if (!ckmode) + continue; + +- if ((rate / div) <= priv->cfg->max_clk_rate_hz) ++ if ((rate / div) <= priv->max_clk_rate) + goto out; + } + +@@ -277,21 +282,21 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { + .csr = STM32F4_ADC_CSR, + .ccr = STM32F4_ADC_CCR, +- .eoc1_msk = STM32F4_EOC1, +- .eoc2_msk = STM32F4_EOC2, +- .eoc3_msk = STM32F4_EOC3, ++ .eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1, ++ .eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2, ++ .eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3, + .ier = STM32F4_ADC_CR1, +- .eocie_msk = STM32F4_EOCIE, ++ .eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE, + }; + + /* STM32H7 common registers definitions */ + static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { + .csr = STM32H7_ADC_CSR, + .ccr = STM32H7_ADC_CCR, +- .eoc1_msk = STM32H7_EOC_MST, +- .eoc2_msk = STM32H7_EOC_SLV, ++ .eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST, ++ .eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV, + .ier = STM32H7_ADC_IER, +- .eocie_msk = STM32H7_EOCIE, ++ .eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE, + }; + + static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = { +@@ -372,21 +377,15 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, + struct device_node *np = pdev->dev.of_node; + unsigned int i; + +- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { ++ /* ++ * Interrupt(s) must be provided, depending on the compatible: ++ * - stm32f4/h7 shares a common interrupt line. ++ * - stm32mp1, has one line per ADC ++ */ ++ for (i = 0; i < priv->cfg->num_irqs; i++) { + priv->irq[i] = platform_get_irq(pdev, i); +- if (priv->irq[i] < 0) { +- /* +- * At least one interrupt must be provided, make others +- * optional: +- * - stm32f4/h7 shares a common interrupt. +- * - stm32mp1, has one line per ADC (either for ADC1, +- * ADC2 or both). +- */ +- if (i && priv->irq[i] == -ENXIO) +- continue; +- ++ if (priv->irq[i] < 0) + return priv->irq[i]; +- } + } + + priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, +@@ -397,9 +396,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, + return -ENOMEM; + } + +- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { +- if (priv->irq[i] < 0) +- continue; ++ for (i = 0; i < priv->cfg->num_irqs; i++) { + irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler); + irq_set_handler_data(priv->irq[i], priv); + } +@@ -417,11 +414,8 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, + irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); + irq_domain_remove(priv->domain); + +- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { +- if (priv->irq[i] < 0) +- continue; ++ for (i = 0; i < priv->cfg->num_irqs; i++) + irq_set_chained_handler(priv->irq[i], NULL); +- } + } + + static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv, +@@ -654,6 +648,7 @@ static int stm32_adc_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct resource *res; ++ u32 max_rate; + int ret; + + if (!pdev->dev.of_node) +@@ -684,7 +679,8 @@ static int stm32_adc_probe(struct platform_device *pdev) + priv->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(priv->vref)) { + ret = PTR_ERR(priv->vref); +- dev_err(&pdev->dev, "vref get failed, %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "vref get failed, %d\n", ret); + return ret; + } + +@@ -692,7 +688,8 @@ static int stm32_adc_probe(struct platform_device *pdev) + if (IS_ERR(priv->aclk)) { + ret = PTR_ERR(priv->aclk); + if (ret != -ENOENT) { +- dev_err(&pdev->dev, "Can't get 'adc' clock\n"); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Can't get 'adc' clock\n"); + return ret; + } + priv->aclk = NULL; +@@ -702,7 +699,8 @@ static int stm32_adc_probe(struct platform_device *pdev) + if (IS_ERR(priv->bclk)) { + ret = PTR_ERR(priv->bclk); + if (ret != -ENOENT) { +- dev_err(&pdev->dev, "Can't get 'bus' clock\n"); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Can't get 'bus' clock\n"); + return ret; + } + priv->bclk = NULL; +@@ -730,6 +728,13 @@ static int stm32_adc_probe(struct platform_device *pdev) + priv->common.vref_mv = ret / 1000; + dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); + ++ ret = of_property_read_u32(pdev->dev.of_node, "st,max-clk-rate-hz", ++ &max_rate); ++ if (!ret) ++ priv->max_clk_rate = min(max_rate, priv->cfg->max_clk_rate_hz); ++ else ++ priv->max_clk_rate = priv->cfg->max_clk_rate_hz; ++ + ret = priv->cfg->clk_sel(pdev, priv); + if (ret < 0) + goto err_hw_stop; +@@ -803,6 +808,7 @@ static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { + .regs = &stm32f4_adc_common_regs, + .clk_sel = stm32f4_adc_clk_sel, + .max_clk_rate_hz = 36000000, ++ .num_irqs = 1, + }; + + static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { +@@ -810,6 +816,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { + .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 36000000, + .has_syscfg = HAS_VBOOSTER, ++ .num_irqs = 1, + }; + + static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { +@@ -817,6 +824,7 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { + .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 40000000, + .has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD, ++ .num_irqs = 2, + }; + + static const struct of_device_id stm32_adc_of_match[] = { +diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h +index 2579d514c..2322809bf 100644 +--- a/drivers/iio/adc/stm32-adc-core.h ++++ b/drivers/iio/adc/stm32-adc-core.h +@@ -51,10 +51,12 @@ + #define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) + + /* STM32F4_ADC_SR - bit fields */ ++#define STM32F4_OVR BIT(5) + #define STM32F4_STRT BIT(4) + #define STM32F4_EOC BIT(1) + + /* STM32F4_ADC_CR1 - bit fields */ ++#define STM32F4_OVRIE BIT(26) + #define STM32F4_RES_SHIFT 24 + #define STM32F4_RES_MASK GENMASK(25, 24) + #define STM32F4_SCAN BIT(8) +@@ -72,8 +74,11 @@ + #define STM32F4_ADON BIT(0) + + /* STM32F4_ADC_CSR - bit fields */ ++#define STM32F4_OVR3 BIT(21) + #define STM32F4_EOC3 BIT(17) ++#define STM32F4_OVR2 BIT(13) + #define STM32F4_EOC2 BIT(9) ++#define STM32F4_OVR1 BIT(5) + #define STM32F4_EOC1 BIT(1) + + /* STM32F4_ADC_CCR - bit fields */ +@@ -103,10 +108,12 @@ + + /* STM32H7_ADC_ISR - bit fields */ + #define STM32MP1_VREGREADY BIT(12) ++#define STM32H7_OVR BIT(4) + #define STM32H7_EOC BIT(2) + #define STM32H7_ADRDY BIT(0) + + /* STM32H7_ADC_IER - bit fields */ ++#define STM32H7_OVRIE STM32H7_OVR + #define STM32H7_EOCIE STM32H7_EOC + + /* STM32H7_ADC_CR - bit fields */ +@@ -155,7 +162,9 @@ enum stm32h7_adc_dmngt { + #define STM32H7_LINCALFACT_MASK GENMASK(29, 0) + + /* STM32H7_ADC_CSR - bit fields */ ++#define STM32H7_OVR_SLV BIT(20) + #define STM32H7_EOC_SLV BIT(18) ++#define STM32H7_OVR_MST BIT(4) + #define STM32H7_EOC_MST BIT(2) + + /* STM32H7_ADC_CCR - bit fields */ +diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c +index 73aee5949..de0ecad66 100644 +--- a/drivers/iio/adc/stm32-adc.c ++++ b/drivers/iio/adc/stm32-adc.c +@@ -102,7 +102,7 @@ struct stm32_adc_calib { + }; + + /** +- * stm32_adc_regs - stm32 ADC misc registers & bitfield desc ++ * struct stm32_adc_regs - stm32 ADC misc registers & bitfield desc + * @reg: register offset + * @mask: bitfield mask + * @shift: left shift +@@ -114,10 +114,12 @@ struct stm32_adc_regs { + }; + + /** +- * stm32_adc_regspec - stm32 registers definition, compatible dependent data ++ * struct stm32_adc_regspec - stm32 registers definition + * @dr: data register offset + * @ier_eoc: interrupt enable register & eocie bitfield ++ * @ier_ovr: interrupt enable register & overrun bitfield + * @isr_eoc: interrupt status register & eoc bitfield ++ * @isr_ovr: interrupt status register & overrun bitfield + * @sqr: reference to sequence registers array + * @exten: trigger control register & bitfield + * @extsel: trigger selection register & bitfield +@@ -128,7 +130,9 @@ struct stm32_adc_regs { + struct stm32_adc_regspec { + const u32 dr; + const struct stm32_adc_regs ier_eoc; ++ const struct stm32_adc_regs ier_ovr; + const struct stm32_adc_regs isr_eoc; ++ const struct stm32_adc_regs isr_ovr; + const struct stm32_adc_regs *sqr; + const struct stm32_adc_regs exten; + const struct stm32_adc_regs extsel; +@@ -140,7 +144,7 @@ struct stm32_adc_regspec { + struct stm32_adc; + + /** +- * stm32_adc_cfg - stm32 compatible configuration data ++ * struct stm32_adc_cfg - stm32 compatible configuration data + * @regs: registers descriptions + * @adc_info: per instance input channels definitions + * @trigs: external trigger sources +@@ -183,8 +187,8 @@ struct stm32_adc_cfg { + * @rx_buf: dma rx buffer cpu address + * @rx_dma_buf: dma rx buffer bus address + * @rx_buf_sz: dma rx buffer size +- * @difsel bitmask to set single-ended/differential channel +- * @pcsel bitmask to preselect channels on some devices ++ * @difsel: bitmask to set single-ended/differential channel ++ * @pcsel: bitmask to preselect channels on some devices + * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) + * @cal: optional calibration data on some devices + * @chan_name: channel name array +@@ -254,7 +258,7 @@ static const struct stm32_adc_info stm32h7_adc_info = { + .num_res = ARRAY_SIZE(stm32h7_adc_resolutions), + }; + +-/** ++/* + * stm32f4_sq - describe regular sequence registers + * - L: sequence len (register & bit field) + * - SQ1..SQ16: sequence entries (register & bit field) +@@ -301,7 +305,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { + {}, /* sentinel */ + }; + +-/** ++/* + * stm32f4_smp_bits[] - describe sampling time register index & bit fields + * Sorted so it can be indexed by channel number. + */ +@@ -337,7 +341,9 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { + static const struct stm32_adc_regspec stm32f4_adc_regspec = { + .dr = STM32F4_ADC_DR, + .ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE }, ++ .ier_ovr = { STM32F4_ADC_CR1, STM32F4_OVRIE }, + .isr_eoc = { STM32F4_ADC_SR, STM32F4_EOC }, ++ .isr_ovr = { STM32F4_ADC_SR, STM32F4_OVR }, + .sqr = stm32f4_sq, + .exten = { STM32F4_ADC_CR2, STM32F4_EXTEN_MASK, STM32F4_EXTEN_SHIFT }, + .extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK, +@@ -392,7 +398,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { + {}, + }; + +-/** ++/* + * stm32h7_smp_bits - describe sampling time register index & bit fields + * Sorted so it can be indexed by channel number. + */ +@@ -429,7 +435,9 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { + static const struct stm32_adc_regspec stm32h7_adc_regspec = { + .dr = STM32H7_ADC_DR, + .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, ++ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE }, + .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC }, ++ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR }, + .sqr = stm32h7_sq, + .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT }, + .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, +@@ -506,6 +514,18 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) + adc->cfg->regs->ier_eoc.mask); + } + ++static void stm32_adc_ovr_irq_enable(struct stm32_adc *adc) ++{ ++ stm32_adc_set_bits(adc, adc->cfg->regs->ier_ovr.reg, ++ adc->cfg->regs->ier_ovr.mask); ++} ++ ++static void stm32_adc_ovr_irq_disable(struct stm32_adc *adc) ++{ ++ stm32_adc_clr_bits(adc, adc->cfg->regs->ier_ovr.reg, ++ adc->cfg->regs->ier_ovr.mask); ++} ++ + static void stm32_adc_set_res(struct stm32_adc *adc) + { + const struct stm32_adc_regs *res = &adc->cfg->regs->res; +@@ -994,6 +1014,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, + + /** + * stm32_adc_get_trig_extsel() - Get external trigger selection ++ * @indio_dev: IIO device structure + * @trig: trigger + * + * Returns trigger extsel value, if trig matches, -EINVAL otherwise. +@@ -1156,6 +1177,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, + + stm32_adc_conv_irq_disable(adc); + ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1204,6 +1226,19 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, + } + } + ++static irqreturn_t stm32_adc_threaded_isr(int irq, void *data) ++{ ++ struct stm32_adc *adc = data; ++ struct iio_dev *indio_dev = iio_priv_to_dev(adc); ++ const struct stm32_adc_regspec *regs = adc->cfg->regs; ++ u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); ++ ++ if (status & regs->isr_ovr.mask) ++ dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n"); ++ ++ return IRQ_HANDLED; ++} ++ + static irqreturn_t stm32_adc_isr(int irq, void *data) + { + struct stm32_adc *adc = data; +@@ -1211,6 +1246,19 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) + const struct stm32_adc_regspec *regs = adc->cfg->regs; + u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); + ++ if (status & regs->isr_ovr.mask) { ++ /* ++ * Overrun occurred on regular conversions: data for wrong ++ * channel may be read. Unconditionally disable interrupts ++ * to stop processing data and print error message. ++ * Restarting the capture can be done by disabling, then ++ * re-enabling it (e.g. write 0, then 1 to buffer/enable). ++ */ ++ stm32_adc_ovr_irq_disable(adc); ++ stm32_adc_conv_irq_disable(adc); ++ return IRQ_WAKE_THREAD; ++ } ++ + if (status & regs->isr_eoc.mask) { + /* Reading DR also clears EOC status flag */ + adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr); +@@ -1277,6 +1325,7 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, + adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); + + ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1297,6 +1346,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev, + + /** + * stm32_adc_debugfs_reg_access - read or write register value ++ * @indio_dev: IIO device structure ++ * @reg: register offset ++ * @writeval: value to write ++ * @readval: value to read + * + * To read a value from an ADC register: + * echo [ADC reg offset] > direct_reg_access +@@ -1324,6 +1377,7 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, + else + *readval = stm32_adc_readl(adc, reg); + ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1367,8 +1421,30 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) + static void stm32_adc_dma_buffer_done(void *data) + { + struct iio_dev *indio_dev = data; ++ struct stm32_adc *adc = iio_priv(indio_dev); ++ int residue = stm32_adc_dma_residue(adc); ++ ++ /* ++ * In DMA mode the trigger services of IIO are not used ++ * (e.g. no call to iio_trigger_poll). ++ * Calling irq handler associated to the hardware trigger is not ++ * relevant as the conversions have already been done. Data ++ * transfers are performed directly in DMA callback instead. ++ * This implementation avoids to call trigger irq handler that ++ * may sleep, in an atomic context (DMA irq handler context). ++ */ ++ dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); ++ ++ while (residue >= indio_dev->scan_bytes) { ++ u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; ++ ++ iio_push_to_buffers(indio_dev, buffer); + +- iio_trigger_poll_chained(indio_dev->trig); ++ residue -= indio_dev->scan_bytes; ++ adc->bufi += indio_dev->scan_bytes; ++ if (adc->bufi >= adc->rx_buf_sz) ++ adc->bufi = 0; ++ } + } + + static int stm32_adc_dma_start(struct iio_dev *indio_dev) +@@ -1436,6 +1512,8 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) + /* Reset adc buffer index */ + adc->bufi = 0; + ++ stm32_adc_ovr_irq_enable(adc); ++ + if (!adc->dma_chan) + stm32_adc_conv_irq_enable(adc); + +@@ -1446,6 +1524,7 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) + err_clr_trig: + stm32_adc_set_trig(indio_dev, NULL); + err_pm_put: ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1476,12 +1555,15 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev) + if (!adc->dma_chan) + stm32_adc_conv_irq_disable(adc); + ++ stm32_adc_ovr_irq_disable(adc); ++ + if (adc->dma_chan) + dmaengine_terminate_sync(adc->dma_chan); + + if (stm32_adc_set_trig(indio_dev, NULL)) + dev_err(&indio_dev->dev, "Can't clear trigger\n"); + ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } +@@ -1741,9 +1823,21 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev) + struct dma_slave_config config; + int ret; + +- adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); +- if (!adc->dma_chan) ++ adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx"); ++ if (IS_ERR(adc->dma_chan)) { ++ ret = PTR_ERR(adc->dma_chan); ++ if (ret != -ENODEV) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&indio_dev->dev, ++ "DMA channel request failed with %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* DMA is optional: fall back to IRQ mode */ ++ adc->dma_chan = NULL; + return 0; ++ } + + adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, + STM32_DMA_BUFFER_SIZE, +@@ -1778,6 +1872,7 @@ static int stm32_adc_probe(struct platform_device *pdev) + { + struct iio_dev *indio_dev; + struct device *dev = &pdev->dev; ++ irqreturn_t (*handler)(int irq, void *p) = NULL; + struct stm32_adc *adc; + int ret; + +@@ -1813,8 +1908,9 @@ static int stm32_adc_probe(struct platform_device *pdev) + if (adc->irq < 0) + return adc->irq; + +- ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr, +- 0, pdev->name, adc); ++ ret = devm_request_threaded_irq(&pdev->dev, adc->irq, stm32_adc_isr, ++ stm32_adc_threaded_isr, ++ 0, pdev->name, adc); + if (ret) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + return ret; +@@ -1843,9 +1939,11 @@ static int stm32_adc_probe(struct platform_device *pdev) + if (ret < 0) + return ret; + ++ if (!adc->dma_chan) ++ handler = &stm32_adc_trigger_handler; ++ + ret = iio_triggered_buffer_setup(indio_dev, +- &iio_pollfunc_store_time, +- &stm32_adc_trigger_handler, ++ &iio_pollfunc_store_time, handler, + &stm32_adc_buffer_setup_ops); + if (ret) { + dev_err(&pdev->dev, "buffer setup failed\n"); +@@ -1869,6 +1967,7 @@ static int stm32_adc_probe(struct platform_device *pdev) + goto err_hw_stop; + } + ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c +index 3ae0366a7..160d952c2 100644 +--- a/drivers/iio/adc/stm32-dfsdm-adc.c ++++ b/drivers/iio/adc/stm32-dfsdm-adc.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -67,6 +68,13 @@ struct stm32_dfsdm_dev_data { + const struct regmap_config *regmap_cfg; + }; + ++struct stm32_dfsdm_sd_chan_info { ++ int scale_val; ++ int scale_val2; ++ int offset; ++ unsigned int differential; ++}; ++ + struct stm32_dfsdm_adc { + struct stm32_dfsdm *dfsdm; + const struct stm32_dfsdm_dev_data *dev_data; +@@ -79,6 +87,7 @@ struct stm32_dfsdm_adc { + struct iio_hw_consumer *hwc; + struct completion completion; + u32 *buffer; ++ struct stm32_dfsdm_sd_chan_info *sd_chan; + + /* Audio specific */ + unsigned int spi_freq; /* SPI bus clock frequency */ +@@ -1199,14 +1208,32 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, + unsigned int spi_freq; + int ret = -EINVAL; + ++ switch (ch->src) { ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: ++ spi_freq = adc->dfsdm->spi_master_freq; ++ break; ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: ++ spi_freq = adc->dfsdm->spi_master_freq / 2; ++ break; ++ default: ++ spi_freq = adc->spi_freq; ++ } ++ + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ++ + ret = stm32_dfsdm_compute_all_osrs(indio_dev, val); +- if (!ret) ++ if (!ret) { ++ dev_dbg(&indio_dev->dev, ++ "Sampling rate changed from (%u) to (%u)\n", ++ adc->sample_freq, spi_freq / val); + adc->oversamp = val; ++ adc->sample_freq = spi_freq / val; ++ } + iio_device_release_direct_mode(indio_dev); + return ret; + +@@ -1218,18 +1245,6 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, + if (ret) + return ret; + +- switch (ch->src) { +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: +- spi_freq = adc->dfsdm->spi_master_freq; +- break; +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: +- spi_freq = adc->dfsdm->spi_master_freq / 2; +- break; +- default: +- spi_freq = adc->spi_freq; +- } +- + ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq); + iio_device_release_direct_mode(indio_dev); + return ret; +@@ -1243,7 +1258,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, + int *val2, long mask) + { + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); +- int ret; ++ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; ++ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; ++ u32 max = flo->max << (flo->lshift - chan->scan_type.shift); ++ int ret, idx = chan->scan_index; + + switch (mask) { + case IIO_CHAN_INFO_RAW: +@@ -1279,6 +1297,39 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, + *val = adc->sample_freq; + + return IIO_VAL_INT; ++ ++ case IIO_CHAN_INFO_SCALE: ++ /* ++ * Scale is expressed in mV. ++ * When fast mode is disabled, actual resolution may be lower ++ * than 2^n, where n=realbits-1. ++ * This leads to underestimating input voltage. To ++ * compensate this deviation, the voltage reference can be ++ * corrected with a factor = realbits resolution / actual max ++ */ ++ *val = div_u64((u64)adc->sd_chan[idx].scale_val * ++ (u64)BIT(DFSDM_DATA_RES - 1), max); ++ *val2 = chan->scan_type.realbits; ++ if (adc->sd_chan[idx].differential) ++ *val *= 2; ++ return IIO_VAL_FRACTIONAL_LOG2; ++ ++ case IIO_CHAN_INFO_OFFSET: ++ /* ++ * DFSDM output data are in the range [-2^n,2^n-1], ++ * with n=realbits-1. ++ * - Differential modulator: ++ * Offset correspond to SD modulator offset. ++ * - Single ended modulator: ++ * Input is in [0V,Vref] range, where 0V corresponds to -2^n. ++ * Add 2^n to offset. (i.e. middle of input range) ++ * offset = offset(sd) * vref / res(sd) * max / vref. ++ */ ++ *val = div_u64((u64)max * adc->sd_chan[idx].offset, ++ BIT(adc->sd_chan[idx].scale_val2 - 1)); ++ if (!adc->sd_chan[idx].differential) ++ *val += max; ++ return IIO_VAL_INT; + } + + return -EINVAL; +@@ -1363,9 +1414,13 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) + { + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + +- adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); +- if (!adc->dma_chan) +- return -EINVAL; ++ adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx"); ++ if (IS_ERR(adc->dma_chan)) { ++ int ret = PTR_ERR(adc->dma_chan); ++ ++ adc->dma_chan = NULL; ++ return ret; ++ } + + adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, + DFSDM_DMA_BUFFER_SIZE, +@@ -1398,7 +1453,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, + * IIO_CHAN_INFO_RAW: used to compute regular conversion + * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling + */ +- ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); ++ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | ++ BIT(IIO_CHAN_INFO_SCALE) | ++ BIT(IIO_CHAN_INFO_OFFSET); + ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | + BIT(IIO_CHAN_INFO_SAMP_FREQ); + +@@ -1408,7 +1465,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, + ch->scan_type.shift = 8; + } + ch->scan_type.sign = 's'; +- ch->scan_type.realbits = 24; ++ ch->scan_type.realbits = DFSDM_DATA_RES; + ch->scan_type.storagebits = 32; + + return stm32_dfsdm_chan_configure(adc->dfsdm, +@@ -1449,8 +1506,10 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + { + struct iio_chan_spec *ch; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); ++ struct iio_channel *channels, *chan; ++ struct stm32_dfsdm_sd_chan_info *sd_chan; + int num_ch; +- int ret, chan_idx; ++ int ret, chan_idx, val2; + + adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; + ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); +@@ -1474,6 +1533,21 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + if (!ch) + return -ENOMEM; + ++ /* Get SD modulator channels */ ++ channels = iio_channel_get_all(&indio_dev->dev); ++ if (IS_ERR(channels)) { ++ dev_err(&indio_dev->dev, "Failed to get channel %ld\n", ++ PTR_ERR(channels)); ++ return PTR_ERR(channels); ++ } ++ chan = &channels[0]; ++ ++ adc->sd_chan = devm_kzalloc(&indio_dev->dev, ++ sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL); ++ if (!adc->sd_chan) ++ return -ENOMEM; ++ sd_chan = adc->sd_chan; ++ + for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { + ch[chan_idx].scan_index = chan_idx; + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); +@@ -1481,6 +1555,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + dev_err(&indio_dev->dev, "Channels init failed\n"); + return ret; + } ++ ++ if (!chan->indio_dev) ++ return -EINVAL; ++ ++ ret = iio_read_channel_scale(chan, &sd_chan->scale_val, ++ &sd_chan->scale_val2); ++ if (ret < 0) { ++ dev_err(&indio_dev->dev, ++ "Failed to get channel %d scale\n", chan_idx); ++ return ret; ++ } ++ ++ if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) { ++ ret = iio_read_channel_offset(chan, &sd_chan->offset, ++ &val2); ++ if (ret < 0) { ++ dev_err(&indio_dev->dev, ++ "Failed to get channel %d offset\n", ++ chan_idx); ++ return ret; ++ } ++ } ++ ++ sd_chan->differential = chan->channel->differential; ++ ++ dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d", ++ chan_idx, chan->channel->differential ? ++ "differential" : "single-ended", ++ sd_chan->scale_val, sd_chan->offset); ++ ++ chan++; ++ sd_chan++; + } + + indio_dev->num_channels = num_ch; +@@ -1489,7 +1595,16 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + init_completion(&adc->completion); + + /* Optionally request DMA */ +- if (stm32_dfsdm_dma_request(indio_dev)) { ++ ret = stm32_dfsdm_dma_request(indio_dev); ++ if (ret) { ++ if (ret != -ENODEV) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&indio_dev->dev, ++ "DMA channel request failed with %d\n", ++ ret); ++ return ret; ++ } ++ + dev_dbg(&indio_dev->dev, "No DMA support\n"); + return 0; + } +diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c +index d0fb3124d..7e5809ba0 100644 +--- a/drivers/iio/dac/stm32-dac-core.c ++++ b/drivers/iio/dac/stm32-dac-core.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -19,13 +20,11 @@ + /** + * struct stm32_dac_priv - stm32 DAC core private data + * @pclk: peripheral clock common for all DACs +- * @rst: peripheral reset control + * @vref: regulator reference + * @common: Common data for all DAC instances + */ + struct stm32_dac_priv { + struct clk *pclk; +- struct reset_control *rst; + struct regulator *vref; + struct stm32_dac_common common; + }; +@@ -50,6 +49,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = { + .max_register = 0x3fc, + }; + ++static int stm32_dac_core_hw_start(struct device *dev) ++{ ++ struct stm32_dac_common *common = dev_get_drvdata(dev); ++ struct stm32_dac_priv *priv = to_stm32_dac_priv(common); ++ int ret; ++ ++ ret = regulator_enable(priv->vref); ++ if (ret < 0) { ++ dev_err(dev, "vref enable failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(priv->pclk); ++ if (ret < 0) { ++ dev_err(dev, "pclk enable failed: %d\n", ret); ++ goto err_regulator_disable; ++ } ++ ++ return 0; ++ ++err_regulator_disable: ++ regulator_disable(priv->vref); ++ ++ return ret; ++} ++ ++static void stm32_dac_core_hw_stop(struct device *dev) ++{ ++ struct stm32_dac_common *common = dev_get_drvdata(dev); ++ struct stm32_dac_priv *priv = to_stm32_dac_priv(common); ++ ++ clk_disable_unprepare(priv->pclk); ++ regulator_disable(priv->vref); ++} ++ + static int stm32_dac_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -58,6 +92,7 @@ static int stm32_dac_probe(struct platform_device *pdev) + struct regmap *regmap; + struct resource *res; + void __iomem *mmio; ++ struct reset_control *rst; + int ret; + + if (!dev->of_node) +@@ -66,6 +101,8 @@ static int stm32_dac_probe(struct platform_device *pdev) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ platform_set_drvdata(pdev, &priv->common); ++ + cfg = (const struct stm32_dac_cfg *) + of_match_device(dev->driver->of_match_table, dev)->data; + +@@ -74,11 +111,19 @@ static int stm32_dac_probe(struct platform_device *pdev) + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + +- regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg); ++ regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio, ++ &stm32_dac_regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + priv->common.regmap = regmap; + ++ priv->pclk = devm_clk_get(dev, "pclk"); ++ if (IS_ERR(priv->pclk)) { ++ ret = PTR_ERR(priv->pclk); ++ dev_err(dev, "pclk get failed\n"); ++ return ret; ++ } ++ + priv->vref = devm_regulator_get(dev, "vref"); + if (IS_ERR(priv->vref)) { + ret = PTR_ERR(priv->vref); +@@ -86,38 +131,35 @@ static int stm32_dac_probe(struct platform_device *pdev) + return ret; + } + +- ret = regulator_enable(priv->vref); +- if (ret < 0) { +- dev_err(dev, "vref enable failed\n"); +- return ret; +- } ++ pm_runtime_get_noresume(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ ++ ret = stm32_dac_core_hw_start(dev); ++ if (ret) ++ goto err_pm_stop; + + ret = regulator_get_voltage(priv->vref); + if (ret < 0) { + dev_err(dev, "vref get voltage failed, %d\n", ret); +- goto err_vref; ++ goto err_hw_stop; + } + priv->common.vref_mv = ret / 1000; + dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv); + +- priv->pclk = devm_clk_get(dev, "pclk"); +- if (IS_ERR(priv->pclk)) { +- ret = PTR_ERR(priv->pclk); +- dev_err(dev, "pclk get failed\n"); +- goto err_vref; +- } ++ rst = devm_reset_control_get_optional_exclusive(dev, NULL); ++ if (rst) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "reset get failed, %d\n", ret); + +- ret = clk_prepare_enable(priv->pclk); +- if (ret < 0) { +- dev_err(dev, "pclk enable failed\n"); +- goto err_vref; +- } ++ goto err_hw_stop; ++ } + +- priv->rst = devm_reset_control_get_exclusive(dev, NULL); +- if (!IS_ERR(priv->rst)) { +- reset_control_assert(priv->rst); ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(priv->rst); ++ reset_control_deassert(rst); + } + + if (cfg && cfg->has_hfsel) { +@@ -128,39 +170,79 @@ static int stm32_dac_probe(struct platform_device *pdev) + priv->common.hfsel ? + STM32H7_DAC_CR_HFSEL : 0); + if (ret) +- goto err_pclk; ++ goto err_hw_stop; + } + +- platform_set_drvdata(pdev, &priv->common); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev); + if (ret < 0) { + dev_err(dev, "failed to populate DT children\n"); +- goto err_pclk; ++ goto err_hw_stop; + } + ++ pm_runtime_put(dev); ++ + return 0; + +-err_pclk: +- clk_disable_unprepare(priv->pclk); +-err_vref: +- regulator_disable(priv->vref); ++err_hw_stop: ++ stm32_dac_core_hw_stop(dev); ++err_pm_stop: ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); + + return ret; + } + + static int stm32_dac_remove(struct platform_device *pdev) + { +- struct stm32_dac_common *common = platform_get_drvdata(pdev); ++ pm_runtime_get_sync(&pdev->dev); ++ of_platform_depopulate(&pdev->dev); ++ stm32_dac_core_hw_stop(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_dac_core_resume(struct device *dev) ++{ ++ struct stm32_dac_common *common = dev_get_drvdata(dev); + struct stm32_dac_priv *priv = to_stm32_dac_priv(common); ++ int ret; + +- of_platform_depopulate(&pdev->dev); +- clk_disable_unprepare(priv->pclk); +- regulator_disable(priv->vref); ++ if (priv->common.hfsel) { ++ /* restore hfsel (maybe lost under low power state) */ ++ ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR, ++ STM32H7_DAC_CR_HFSEL, ++ STM32H7_DAC_CR_HFSEL); ++ if (ret) ++ return ret; ++ } ++ ++ return pm_runtime_force_resume(dev); ++} ++ ++static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev) ++{ ++ stm32_dac_core_hw_stop(dev); + + return 0; + } + ++static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev) ++{ ++ return stm32_dac_core_hw_start(dev); ++} ++ ++static const struct dev_pm_ops stm32_dac_core_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) ++ SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, ++ stm32_dac_core_runtime_resume, ++ NULL) ++}; ++ + static const struct stm32_dac_cfg stm32h7_dac_cfg = { + .has_hfsel = true, + }; +@@ -182,6 +264,7 @@ static struct platform_driver stm32_dac_driver = { + .driver = { + .name = "stm32-dac-core", + .of_match_table = stm32_dac_of_match, ++ .pm = &stm32_dac_core_pm_ops, + }, + }; + module_platform_driver(stm32_dac_driver); +diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c +index cce26a3a6..f22c1d912 100644 +--- a/drivers/iio/dac/stm32-dac.c ++++ b/drivers/iio/dac/stm32-dac.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "stm32-dac-core.h" + +@@ -20,6 +21,8 @@ + #define STM32_DAC_CHANNEL_2 2 + #define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1) + ++#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000 ++ + /** + * struct stm32_dac - private data of DAC driver + * @common: reference to DAC common data +@@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, + bool enable) + { + struct stm32_dac *dac = iio_priv(indio_dev); ++ struct device *dev = indio_dev->dev.parent; + u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2; + u32 en = enable ? msk : 0; + int ret; + ++ /* already enabled / disabled ? */ ++ mutex_lock(&indio_dev->mlock); ++ ret = stm32_dac_is_enabled(indio_dev, ch); ++ if (ret < 0 || enable == !!ret) { ++ mutex_unlock(&indio_dev->mlock); ++ return ret < 0 ? ret : 0; ++ } ++ ++ if (enable) { ++ ret = pm_runtime_get_sync(dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(dev); ++ mutex_unlock(&indio_dev->mlock); ++ return ret; ++ } ++ } ++ + ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en); ++ mutex_unlock(&indio_dev->mlock); + if (ret < 0) { + dev_err(&indio_dev->dev, "%s failed\n", en ? + "Enable" : "Disable"); +- return ret; ++ goto err_put_pm; + } + + /* +@@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, + if (en && dac->common->hfsel) + udelay(1); + ++ if (!enable) { ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ } ++ + return 0; ++ ++err_put_pm: ++ if (enable) { ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ } ++ ++ return ret; + } + + static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val) +@@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev) + static int stm32_dac_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; ++ struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct stm32_dac *dac; + int ret; +@@ -296,9 +332,61 @@ static int stm32_dac_probe(struct platform_device *pdev) + if (ret < 0) + return ret; + +- return devm_iio_device_register(&pdev->dev, indio_dev); ++ /* Get stm32-dac-core PM online */ ++ pm_runtime_get_noresume(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_enable(dev); ++ ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto err_pm_put; ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; ++ ++err_pm_put: ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); ++ ++ return ret; + } + ++static int stm32_dac_remove(struct platform_device *pdev) ++{ ++ struct iio_dev *indio_dev = platform_get_drvdata(pdev); ++ ++ pm_runtime_get_sync(&pdev->dev); ++ iio_device_unregister(indio_dev); ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_dac_suspend(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ int channel = indio_dev->channels[0].channel; ++ int ret; ++ ++ /* Ensure DAC is disabled before suspend */ ++ ret = stm32_dac_is_enabled(indio_dev, channel); ++ if (ret) ++ return ret < 0 ? ret : -EBUSY; ++ ++ return pm_runtime_force_suspend(dev); ++} ++ ++static const struct dev_pm_ops stm32_dac_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume) ++}; ++ + static const struct of_device_id stm32_dac_of_match[] = { + { .compatible = "st,stm32-dac", }, + {}, +@@ -307,9 +395,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); + + static struct platform_driver stm32_dac_driver = { + .probe = stm32_dac_probe, ++ .remove = stm32_dac_remove, + .driver = { + .name = "stm32-dac", + .of_match_table = stm32_dac_of_match, ++ .pm = &stm32_dac_pm_ops, + }, + }; + module_platform_driver(stm32_dac_driver); +diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c +index f98510c71..7d8962d65 100644 +--- a/drivers/iio/trigger/stm32-timer-trigger.c ++++ b/drivers/iio/trigger/stm32-timer-trigger.c +@@ -75,14 +75,27 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = { + { }, /* timer 17 */ + }; + ++struct stm32_timer_trigger_regs { ++ u32 cr1; ++ u32 cr2; ++ u32 psc; ++ u32 arr; ++ u32 cnt; ++ u32 smcr; ++}; ++ + struct stm32_timer_trigger { + struct device *dev; + struct regmap *regmap; + struct clk *clk; ++ bool enabled; + u32 max_arr; + const void *triggers; + const void *valids; + bool has_trgo2; ++ struct mutex lock; /* concurrent sysfs configuration */ ++ struct list_head tr_list; ++ struct stm32_timer_trigger_regs bak; + }; + + struct stm32_timer_trigger_cfg { +@@ -106,7 +119,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, + { + unsigned long long prd, div; + int prescaler = 0; +- u32 ccer, cr1; ++ u32 ccer; + + /* Period and prescaler values depends of clock rate */ + div = (unsigned long long)clk_get_rate(priv->clk); +@@ -136,9 +149,11 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, + if (ccer & TIM_CCER_CCXE) + return -EBUSY; + +- regmap_read(priv->regmap, TIM_CR1, &cr1); +- if (!(cr1 & TIM_CR1_CEN)) ++ mutex_lock(&priv->lock); ++ if (!priv->enabled) { ++ priv->enabled = true; + clk_enable(priv->clk); ++ } + + regmap_write(priv->regmap, TIM_PSC, prescaler); + regmap_write(priv->regmap, TIM_ARR, prd - 1); +@@ -157,6 +172,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, + + /* Enable controller */ + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); ++ mutex_unlock(&priv->lock); + + return 0; + } +@@ -164,16 +180,13 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, + static void stm32_timer_stop(struct stm32_timer_trigger *priv, + struct iio_trigger *trig) + { +- u32 ccer, cr1; ++ u32 ccer; + + regmap_read(priv->regmap, TIM_CCER, &ccer); + if (ccer & TIM_CCER_CCXE) + return; + +- regmap_read(priv->regmap, TIM_CR1, &cr1); +- if (cr1 & TIM_CR1_CEN) +- clk_disable(priv->clk); +- ++ mutex_lock(&priv->lock); + /* Stop timer */ + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); +@@ -188,6 +201,12 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv, + + /* Make sure that registers are updated */ + regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); ++ ++ if (priv->enabled) { ++ priv->enabled = false; ++ clk_disable(priv->clk); ++ } ++ mutex_unlock(&priv->lock); + } + + static ssize_t stm32_tt_store_frequency(struct device *dev, +@@ -302,11 +321,15 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, + for (i = 0; i <= master_mode_max; i++) { + if (!strncmp(master_mode_table[i], buf, + strlen(master_mode_table[i]))) { ++ mutex_lock(&priv->lock); ++ if (!priv->enabled) { ++ /* Clock should be enabled first */ ++ priv->enabled = true; ++ clk_enable(priv->clk); ++ } + regmap_update_bits(priv->regmap, TIM_CR2, mask, + i << shift); +- /* Make sure that registers are updated */ +- regmap_update_bits(priv->regmap, TIM_EGR, +- TIM_EGR_UG, TIM_EGR_UG); ++ mutex_unlock(&priv->lock); + return len; + } + } +@@ -364,11 +387,21 @@ static const struct attribute_group *stm32_trigger_attr_groups[] = { + static const struct iio_trigger_ops timer_trigger_ops = { + }; + +-static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) ++static void stm32_unregister_iio_triggers(struct stm32_timer_trigger *priv) ++{ ++ struct iio_trigger *tr; ++ ++ list_for_each_entry(tr, &priv->tr_list, alloc_list) ++ iio_trigger_unregister(tr); ++} ++ ++static int stm32_register_iio_triggers(struct stm32_timer_trigger *priv) + { + int ret; + const char * const *cur = priv->triggers; + ++ INIT_LIST_HEAD(&priv->tr_list); ++ + while (cur && *cur) { + struct iio_trigger *trig; + bool cur_is_trgo = stm32_timer_is_trgo_name(*cur); +@@ -395,9 +428,13 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) + + iio_trigger_set_drvdata(trig, priv); + +- ret = devm_iio_trigger_register(priv->dev, trig); +- if (ret) ++ ret = iio_trigger_register(trig); ++ if (ret) { ++ stm32_unregister_iio_triggers(priv); + return ret; ++ } ++ ++ list_add_tail(&trig->alloc_list, &priv->tr_list); + cur++; + } + +@@ -444,7 +481,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, + int val, int val2, long mask) + { + struct stm32_timer_trigger *priv = iio_priv(indio_dev); +- u32 dat; + + switch (mask) { + case IIO_CHAN_INFO_RAW: +@@ -455,19 +491,23 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, + return -EINVAL; + + case IIO_CHAN_INFO_ENABLE: ++ mutex_lock(&priv->lock); + if (val) { +- regmap_read(priv->regmap, TIM_CR1, &dat); +- if (!(dat & TIM_CR1_CEN)) ++ if (!priv->enabled) { ++ priv->enabled = true; + clk_enable(priv->clk); ++ } + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, + TIM_CR1_CEN); + } else { +- regmap_read(priv->regmap, TIM_CR1, &dat); + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, + 0); +- if (dat & TIM_CR1_CEN) ++ if (priv->enabled) { ++ priv->enabled = false; + clk_disable(priv->clk); ++ } + } ++ mutex_unlock(&priv->lock); + return 0; + } + +@@ -563,7 +603,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, + { + struct stm32_timer_trigger *priv = iio_priv(indio_dev); + int sms = stm32_enable_mode2sms(mode); +- u32 val; + + if (sms < 0) + return sms; +@@ -571,11 +610,12 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, + * Triggered mode sets CEN bit automatically by hardware. So, first + * enable counter clock, so it can use it. Keeps it in sync with CEN. + */ +- if (sms == 6) { +- regmap_read(priv->regmap, TIM_CR1, &val); +- if (!(val & TIM_CR1_CEN)) +- clk_enable(priv->clk); ++ mutex_lock(&priv->lock); ++ if (sms == 6 && !priv->enabled) { ++ clk_enable(priv->clk); ++ priv->enabled = true; + } ++ mutex_unlock(&priv->lock); + + regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); + +@@ -759,8 +799,9 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) + priv->triggers = triggers_table[index]; + priv->valids = cfg->valids_table[index]; + stm32_timer_detect_trgo2(priv); ++ mutex_init(&priv->lock); + +- ret = stm32_setup_iio_triggers(priv); ++ ret = stm32_register_iio_triggers(priv); + if (ret) + return ret; + +@@ -769,6 +810,77 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) + return 0; + } + ++static int stm32_timer_trigger_remove(struct platform_device *pdev) ++{ ++ struct stm32_timer_trigger *priv = platform_get_drvdata(pdev); ++ u32 val; ++ ++ /* Unregister triggers before everything can be safely turned off */ ++ stm32_unregister_iio_triggers(priv); ++ ++ /* Check if nobody else use the timer, then disable it */ ++ regmap_read(priv->regmap, TIM_CCER, &val); ++ if (!(val & TIM_CCER_CCXE)) ++ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); ++ ++ if (priv->enabled) ++ clk_disable(priv->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev) ++{ ++ struct stm32_timer_trigger *priv = dev_get_drvdata(dev); ++ ++ /* Only take care of enabled timer: don't disturb other MFD child */ ++ if (priv->enabled) { ++ /* Backup registers that may get lost in low power mode */ ++ regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1); ++ regmap_read(priv->regmap, TIM_CR2, &priv->bak.cr2); ++ regmap_read(priv->regmap, TIM_PSC, &priv->bak.psc); ++ regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr); ++ regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt); ++ regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr); ++ ++ /* Disable the timer */ ++ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); ++ clk_disable(priv->clk); ++ } ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_timer_trigger_resume(struct device *dev) ++{ ++ struct stm32_timer_trigger *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ if (priv->enabled) { ++ ret = clk_enable(priv->clk); ++ if (ret) ++ return ret; ++ ++ /* restore master/slave modes */ ++ regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr); ++ regmap_write(priv->regmap, TIM_CR2, priv->bak.cr2); ++ ++ /* restore sampling_frequency (trgo / trgo2 triggers) */ ++ regmap_write(priv->regmap, TIM_PSC, priv->bak.psc); ++ regmap_write(priv->regmap, TIM_ARR, priv->bak.arr); ++ regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt); ++ ++ /* Also re-enables the timer */ ++ regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1); ++ } ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops, ++ stm32_timer_trigger_suspend, ++ stm32_timer_trigger_resume); ++ + static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = { + .valids_table = valids_table, + .num_valids_table = ARRAY_SIZE(valids_table), +@@ -793,9 +905,11 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match); + + static struct platform_driver stm32_timer_trigger_driver = { + .probe = stm32_timer_trigger_probe, ++ .remove = stm32_timer_trigger_remove, + .driver = { + .name = "stm32-timer-trigger", + .of_match_table = stm32_trig_of_match, ++ .pm = &stm32_timer_trigger_pm_ops, + }, + }; + module_platform_driver(stm32_timer_trigger_driver); +diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c +index e00f2fa27..af4b0d690 100644 +--- a/drivers/irqchip/irq-stm32-exti.c ++++ b/drivers/irqchip/irq-stm32-exti.c +@@ -25,7 +25,6 @@ + #define IRQS_PER_BANK 32 + + #define HWSPNLCK_TIMEOUT 1000 /* usec */ +-#define HWSPNLCK_RETRY_DELAY 100 /* usec */ + + struct stm32_exti_bank { + u32 imr_ofst; +@@ -42,6 +41,7 @@ struct stm32_exti_bank { + struct stm32_desc_irq { + u32 exti; + u32 irq_parent; ++ struct irq_chip *chip; + }; + + struct stm32_exti_drv_data { +@@ -166,27 +166,49 @@ static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { + &stm32mp1_exti_b3, + }; + ++static struct irq_chip stm32_exti_h_chip; ++static struct irq_chip stm32_exti_h_chip_direct; ++ + static const struct stm32_desc_irq stm32mp1_desc_irq[] = { +- { .exti = 0, .irq_parent = 6 }, +- { .exti = 1, .irq_parent = 7 }, +- { .exti = 2, .irq_parent = 8 }, +- { .exti = 3, .irq_parent = 9 }, +- { .exti = 4, .irq_parent = 10 }, +- { .exti = 5, .irq_parent = 23 }, +- { .exti = 6, .irq_parent = 64 }, +- { .exti = 7, .irq_parent = 65 }, +- { .exti = 8, .irq_parent = 66 }, +- { .exti = 9, .irq_parent = 67 }, +- { .exti = 10, .irq_parent = 40 }, +- { .exti = 11, .irq_parent = 42 }, +- { .exti = 12, .irq_parent = 76 }, +- { .exti = 13, .irq_parent = 77 }, +- { .exti = 14, .irq_parent = 121 }, +- { .exti = 15, .irq_parent = 127 }, +- { .exti = 16, .irq_parent = 1 }, +- { .exti = 65, .irq_parent = 144 }, +- { .exti = 68, .irq_parent = 143 }, +- { .exti = 73, .irq_parent = 129 }, ++ { .exti = 0, .irq_parent = 6, .chip = &stm32_exti_h_chip }, ++ { .exti = 1, .irq_parent = 7, .chip = &stm32_exti_h_chip }, ++ { .exti = 2, .irq_parent = 8, .chip = &stm32_exti_h_chip }, ++ { .exti = 3, .irq_parent = 9, .chip = &stm32_exti_h_chip }, ++ { .exti = 4, .irq_parent = 10, .chip = &stm32_exti_h_chip }, ++ { .exti = 5, .irq_parent = 23, .chip = &stm32_exti_h_chip }, ++ { .exti = 6, .irq_parent = 64, .chip = &stm32_exti_h_chip }, ++ { .exti = 7, .irq_parent = 65, .chip = &stm32_exti_h_chip }, ++ { .exti = 8, .irq_parent = 66, .chip = &stm32_exti_h_chip }, ++ { .exti = 9, .irq_parent = 67, .chip = &stm32_exti_h_chip }, ++ { .exti = 10, .irq_parent = 40, .chip = &stm32_exti_h_chip }, ++ { .exti = 11, .irq_parent = 42, .chip = &stm32_exti_h_chip }, ++ { .exti = 12, .irq_parent = 76, .chip = &stm32_exti_h_chip }, ++ { .exti = 13, .irq_parent = 77, .chip = &stm32_exti_h_chip }, ++ { .exti = 14, .irq_parent = 121, .chip = &stm32_exti_h_chip }, ++ { .exti = 15, .irq_parent = 127, .chip = &stm32_exti_h_chip }, ++ { .exti = 16, .irq_parent = 1, .chip = &stm32_exti_h_chip }, ++ { .exti = 19, .irq_parent = 3, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 21, .irq_parent = 31, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 22, .irq_parent = 33, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 44, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 54, .irq_parent = 135, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 61, .irq_parent = 100, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 65, .irq_parent = 144, .chip = &stm32_exti_h_chip }, ++ { .exti = 68, .irq_parent = 143, .chip = &stm32_exti_h_chip }, ++ { .exti = 70, .irq_parent = 62, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 73, .irq_parent = 129, .chip = &stm32_exti_h_chip }, + }; + + static const struct stm32_exti_drv_data stm32mp1_drv_data = { +@@ -196,22 +218,23 @@ static const struct stm32_exti_drv_data stm32mp1_drv_data = { + .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq), + }; + +-static int stm32_exti_to_irq(const struct stm32_exti_drv_data *drv_data, +- irq_hw_number_t hwirq) ++static const struct ++stm32_desc_irq *stm32_exti_get_desc(const struct stm32_exti_drv_data *drv_data, ++ irq_hw_number_t hwirq) + { +- const struct stm32_desc_irq *desc_irq; ++ const struct stm32_desc_irq *desc = NULL; + int i; + + if (!drv_data->desc_irqs) +- return -EINVAL; ++ return NULL; + + for (i = 0; i < drv_data->irq_nr; i++) { +- desc_irq = &drv_data->desc_irqs[i]; +- if (desc_irq->exti == hwirq) +- return desc_irq->irq_parent; ++ desc = &drv_data->desc_irqs[i]; ++ if (desc->exti == hwirq) ++ break; + } + +- return -EINVAL; ++ return desc; + } + + static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +@@ -277,55 +300,24 @@ static int stm32_exti_set_type(struct irq_data *d, + return 0; + } + +-static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) +-{ +- int ret, timeout = 0; +- +- if (!chip_data->host_data->hwlock) +- return 0; +- +- /* +- * Use the x_raw API since we are under spin_lock protection. +- * Do not use the x_timeout API because we are under irq_disable +- * mode (see __setup_irq()) +- */ +- do { +- ret = hwspin_trylock_raw(chip_data->host_data->hwlock); +- if (!ret) +- return 0; +- +- udelay(HWSPNLCK_RETRY_DELAY); +- timeout += HWSPNLCK_RETRY_DELAY; +- } while (timeout < HWSPNLCK_TIMEOUT); +- +- if (ret == -EBUSY) +- ret = -ETIMEDOUT; +- +- if (ret) +- pr_err("%s can't get hwspinlock (%d)\n", __func__, ret); +- +- return ret; +-} +- +-static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) +-{ +- if (chip_data->host_data->hwlock) +- hwspin_unlock_raw(chip_data->host_data->hwlock); +-} +- + static int stm32_irq_set_type(struct irq_data *d, unsigned int type) + { + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; ++ struct hwspinlock *hwlock = chip_data->host_data->hwlock; + u32 rtsr, ftsr; + int err; + + irq_gc_lock(gc); + +- err = stm32_exti_hwspin_lock(chip_data); +- if (err) +- goto unlock; ++ if (hwlock) { ++ err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT); ++ if (err) { ++ pr_err("%s can't get hwspinlock (%d)\n", __func__, err); ++ goto unlock; ++ } ++ } + + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); +@@ -338,7 +330,8 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); + + unspinlock: +- stm32_exti_hwspin_unlock(chip_data); ++ if (hwlock) ++ hwspin_unlock_in_atomic(hwlock); + unlock: + irq_gc_unlock(gc); + +@@ -504,15 +497,20 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) + { + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; ++ struct hwspinlock *hwlock = chip_data->host_data->hwlock; + void __iomem *base = chip_data->host_data->base; + u32 rtsr, ftsr; + int err; + + raw_spin_lock(&chip_data->rlock); + +- err = stm32_exti_hwspin_lock(chip_data); +- if (err) +- goto unlock; ++ if (hwlock) { ++ err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT); ++ if (err) { ++ pr_err("%s can't get hwspinlock (%d)\n", __func__, err); ++ goto unlock; ++ } ++ } + + rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); + ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); +@@ -525,10 +523,14 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) + writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); + + unspinlock: +- stm32_exti_hwspin_unlock(chip_data); ++ if (hwlock) ++ hwspin_unlock_in_atomic(hwlock); + unlock: + raw_spin_unlock(&chip_data->rlock); + ++ if (d->parent_data->chip) ++ irq_chip_set_type_parent(d, type); ++ + return err; + } + +@@ -546,6 +548,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) + + raw_spin_unlock(&chip_data->rlock); + ++ if (d->parent_data->chip) ++ irq_chip_set_wake_parent(d, on); ++ + return 0; + } + +@@ -555,7 +560,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, + if (d->parent_data->chip) + return irq_chip_set_affinity_parent(d, dest, force); + +- return -EINVAL; ++ return IRQ_SET_MASK_OK_DONE; ++} ++ ++static void stm32_exti_h_ack(struct irq_data *d) ++{ ++ if (d->parent_data->chip) ++ irq_chip_ack_parent(d); + } + + static int __maybe_unused stm32_exti_h_suspend(void) +@@ -604,45 +615,90 @@ static void stm32_exti_h_syscore_deinit(void) + unregister_syscore_ops(&stm32_exti_h_syscore_ops); + } + ++static int stm32_exti_h_retrigger(struct irq_data *d) ++{ ++ struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); ++ const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; ++ void __iomem *base = chip_data->host_data->base; ++ u32 mask = BIT(d->hwirq % IRQS_PER_BANK); ++ ++ writel_relaxed(mask, base + stm32_bank->swier_ofst); ++ ++ return 0; ++} ++ + static struct irq_chip stm32_exti_h_chip = { + .name = "stm32-exti-h", + .irq_eoi = stm32_exti_h_eoi, ++ .irq_ack = stm32_exti_h_ack, + .irq_mask = stm32_exti_h_mask, + .irq_unmask = stm32_exti_h_unmask, +- .irq_retrigger = irq_chip_retrigger_hierarchy, ++ .irq_retrigger = stm32_exti_h_retrigger, + .irq_set_type = stm32_exti_h_set_type, + .irq_set_wake = stm32_exti_h_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, + .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? stm32_exti_h_set_affinity : NULL, + }; + ++static struct irq_chip stm32_exti_h_chip_direct = { ++ .name = "stm32-exti-h-direct", ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_ack = irq_chip_ack_parent, ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_retrigger = irq_chip_retrigger_hierarchy, ++ .irq_set_type = irq_chip_set_type_parent, ++ .irq_set_wake = stm32_exti_h_set_wake, ++ .flags = IRQCHIP_MASK_ON_SUSPEND, ++ .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? irq_chip_set_affinity_parent : NULL, ++}; ++ + static int stm32_exti_h_domain_alloc(struct irq_domain *dm, + unsigned int virq, + unsigned int nr_irqs, void *data) + { + struct stm32_exti_host_data *host_data = dm->host_data; + struct stm32_exti_chip_data *chip_data; ++ const struct stm32_desc_irq *desc; + struct irq_fwspec *fwspec = data; + struct irq_fwspec p_fwspec; + irq_hw_number_t hwirq; +- int p_irq, bank; ++ int bank; + + hwirq = fwspec->param[0]; + bank = hwirq / IRQS_PER_BANK; + chip_data = &host_data->chips_data[bank]; + +- irq_domain_set_hwirq_and_chip(dm, virq, hwirq, +- &stm32_exti_h_chip, chip_data); + +- p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); +- if (p_irq >= 0) { ++ desc = stm32_exti_get_desc(host_data->drv_data, hwirq); ++ if (!desc) ++ return -EINVAL; ++ ++ irq_domain_set_hwirq_and_chip(dm, virq, hwirq, desc->chip, ++ chip_data); ++ ++ /* ++ * EXTI 55 to 60 are mapped to PWR interrupt controller. ++ * The hwirq translation is done diferently than for GIC. ++ */ ++ if (hwirq >= 55 && hwirq <= 60) { + p_fwspec.fwnode = dm->parent->fwnode; +- p_fwspec.param_count = 3; +- p_fwspec.param[0] = GIC_SPI; +- p_fwspec.param[1] = p_irq; +- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; ++ p_fwspec.param_count = 2; ++ p_fwspec.param[0] = hwirq - 55; ++ p_fwspec.param[1] = fwspec->param[1]; + + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); ++ } else { ++ if (desc->irq_parent >= 0) { ++ p_fwspec.fwnode = dm->parent->fwnode; ++ p_fwspec.param_count = 3; ++ p_fwspec.param[0] = GIC_SPI; ++ p_fwspec.param[1] = desc->irq_parent; ++ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; ++ ++ return irq_domain_alloc_irqs_parent(dm, virq, 1, ++ &p_fwspec); ++ } + } + + return 0; +@@ -807,11 +863,12 @@ static int stm32_exti_probe(struct platform_device *pdev) + { + int ret, i; + struct device *dev = &pdev->dev; +- struct device_node *np = dev->of_node; ++ struct device_node *child, *np = dev->of_node; + struct irq_domain *parent_domain, *domain; + struct stm32_exti_host_data *host_data; + const struct stm32_exti_drv_data *drv_data; + struct resource *res; ++ u32 nirqs; + + host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); + if (!host_data) +@@ -879,6 +936,34 @@ static int stm32_exti_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ for_each_child_of_node(np, child) { ++ parent_domain = irq_find_host(of_irq_find_parent(child)); ++ if (!parent_domain) { ++ dev_err(dev, "child interrupt-parent not found\n"); ++ return -EINVAL; ++ } ++ ++ ret = of_property_read_u32(child, "st,irq-number", &nirqs); ++ if (ret || !nirqs) { ++ dev_err(dev, "Missing or bad irq-number property\n"); ++ return -EINVAL; ++ } ++ ++ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs, ++ child, ++ &stm32_exti_h_domain_ops, ++ host_data); ++ if (!domain) { ++ dev_err(dev, "Could not register exti domain\n"); ++ return -ENOMEM; ++ } ++ ++ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, ++ domain); ++ if (ret) ++ return ret; ++ } ++ + stm32_exti_h_syscore_init(host_data); + + return 0; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch new file mode 100644 index 0000000..cac772b --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch @@ -0,0 +1,2728 @@ +From e0c91ba2bc4702d8ed587f7e200591cf135ade14 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:43:27 +0200 +Subject: [PATCH 10/23] ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG + +--- + Documentation/remoteproc.txt | 22 + + drivers/mailbox/Kconfig | 7 + + drivers/mailbox/Makefile | 2 + + drivers/mailbox/arm-smc-mailbox.c | 166 ++++++ + drivers/mailbox/stm32-ipcc.c | 36 +- + drivers/remoteproc/Kconfig | 21 + + drivers/remoteproc/Makefile | 2 + + drivers/remoteproc/remoteproc_core.c | 55 +- + drivers/remoteproc/rproc_srm_core.c | 303 ++++++++++ + drivers/remoteproc/rproc_srm_core.h | 98 ++++ + drivers/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++ + drivers/remoteproc/stm32_rproc.c | 314 ++++++++++- + drivers/rpmsg/Kconfig | 9 + + drivers/rpmsg/Makefile | 1 + + drivers/rpmsg/rpmsg_core.c | 19 + + drivers/rpmsg/rpmsg_internal.h | 2 + + drivers/rpmsg/rpmsg_tty.c | 310 +++++++++++ + drivers/rpmsg/virtio_rpmsg_bus.c | 11 + + include/linux/mailbox/arm-smccc-mbox.h | 20 + + include/linux/remoteproc.h | 2 + + include/linux/rpmsg.h | 9 + + 21 files changed, 2093 insertions(+), 60 deletions(-) + create mode 100644 drivers/mailbox/arm-smc-mailbox.c + create mode 100644 drivers/remoteproc/rproc_srm_core.c + create mode 100644 drivers/remoteproc/rproc_srm_core.h + create mode 100644 drivers/remoteproc/rproc_srm_dev.c + create mode 100644 drivers/rpmsg/rpmsg_tty.c + create mode 100644 include/linux/mailbox/arm-smccc-mbox.h + +diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt +index 03c3d2e56..5b217887b 100644 +--- a/Documentation/remoteproc.txt ++++ b/Documentation/remoteproc.txt +@@ -357,3 +357,25 @@ Of course, RSC_VDEV resource entries are only good enough for static + allocation of virtio devices. Dynamic allocations will also be made possible + using the rpmsg bus (similar to how we already do dynamic allocations of + rpmsg channels; read more about it in rpmsg.txt). ++ ++8. System Resource Manager (SRM) ++ ++Since some resources are shared (directly or not) between the processors, a ++processor cannot manage such resources without potentially impacting the other ++processors : as an example, if a processor changes the frequency of a clock, the ++frequency of another clock managed by another processor may be updated too. ++ ++The System Resource Manager prevents such resource conflicts between the ++processors : it reserves and initializes the system resources of the peripherals ++assigned to a remote processor. ++ ++As of today the following resources are controlled by the SRM: ++- clocks ++- regulators (power supplies) ++ ++The SRM is implemented as an 'rproc_subdev' and registered to remoteproc_core. ++Unlike the virtio device (vdev), the SRM subdev is probed *before* the rproc ++boots, ensuring the availability of the resources before the remoteproc starts. ++ ++The resources handled by the SRM are defined in the DeviceTree: please read ++Documentation/devicetree/bindings/remoteproc/rproc-srm.txt for details. +diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig +index ab4eb750b..7707ee262 100644 +--- a/drivers/mailbox/Kconfig ++++ b/drivers/mailbox/Kconfig +@@ -16,6 +16,13 @@ config ARM_MHU + The controller has 3 mailbox channels, the last of which can be + used in Secure mode only. + ++config ARM_SMC_MBOX ++ tristate "Generic ARM smc mailbox" ++ depends on OF && HAVE_ARM_SMCCC ++ help ++ Generic mailbox driver which uses ARM smc calls to call into ++ firmware for triggering mailboxes. ++ + config IMX_MBOX + tristate "i.MX Mailbox" + depends on ARCH_MXC || COMPILE_TEST +diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile +index c22fad6f6..93918a84c 100644 +--- a/drivers/mailbox/Makefile ++++ b/drivers/mailbox/Makefile +@@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o + + obj-$(CONFIG_ARM_MHU) += arm_mhu.o + ++obj-$(CONFIG_ARM_SMC_MBOX) += arm-smc-mailbox.o ++ + obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o + + obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o +diff --git a/drivers/mailbox/arm-smc-mailbox.c b/drivers/mailbox/arm-smc-mailbox.c +new file mode 100644 +index 000000000..a6ec56f41 +--- /dev/null ++++ b/drivers/mailbox/arm-smc-mailbox.c +@@ -0,0 +1,166 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2016,2017 ARM Ltd. ++ * Copyright 2019 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef unsigned long (smc_mbox_fn)(unsigned int, unsigned long, ++ unsigned long, unsigned long, ++ unsigned long, unsigned long, ++ unsigned long); ++ ++struct arm_smc_chan_data { ++ unsigned int function_id; ++ smc_mbox_fn *invoke_smc_mbox_fn; ++}; ++ ++static int arm_smc_send_data(struct mbox_chan *link, void *data) ++{ ++ struct arm_smc_chan_data *chan_data = link->con_priv; ++ struct arm_smccc_mbox_cmd *cmd = data; ++ unsigned long ret; ++ ++ if (ARM_SMCCC_IS_64(chan_data->function_id)) { ++ ret = chan_data->invoke_smc_mbox_fn(chan_data->function_id, ++ cmd->args_smccc64[0], ++ cmd->args_smccc64[1], ++ cmd->args_smccc64[2], ++ cmd->args_smccc64[3], ++ cmd->args_smccc64[4], ++ cmd->args_smccc64[5]); ++ } else { ++ ret = chan_data->invoke_smc_mbox_fn(chan_data->function_id, ++ cmd->args_smccc32[0], ++ cmd->args_smccc32[1], ++ cmd->args_smccc32[2], ++ cmd->args_smccc32[3], ++ cmd->args_smccc32[4], ++ cmd->args_smccc32[5]); ++ } ++ ++ mbox_chan_received_data(link, (void *)ret); ++ ++ return 0; ++} ++ ++static unsigned long __invoke_fn_hvc(unsigned int function_id, ++ unsigned long arg0, unsigned long arg1, ++ unsigned long arg2, unsigned long arg3, ++ unsigned long arg4, unsigned long arg5) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, ++ arg5, 0, &res); ++ return res.a0; ++} ++ ++static unsigned long __invoke_fn_smc(unsigned int function_id, ++ unsigned long arg0, unsigned long arg1, ++ unsigned long arg2, unsigned long arg3, ++ unsigned long arg4, unsigned long arg5) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, ++ arg5, 0, &res); ++ return res.a0; ++} ++ ++static const struct mbox_chan_ops arm_smc_mbox_chan_ops = { ++ .send_data = arm_smc_send_data, ++}; ++ ++static struct mbox_chan * ++arm_smc_mbox_of_xlate(struct mbox_controller *mbox, ++ const struct of_phandle_args *sp) ++{ ++ return mbox->chans; ++} ++ ++static int arm_smc_mbox_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mbox_controller *mbox; ++ struct arm_smc_chan_data *chan_data; ++ int ret; ++ ++ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); ++ if (!mbox) ++ return -ENOMEM; ++ ++ mbox->of_xlate = arm_smc_mbox_of_xlate; ++ mbox->num_chans = 1; ++ mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL); ++ if (!mbox->chans) ++ return -ENOMEM; ++ ++ chan_data = devm_kzalloc(dev, sizeof(*chan_data), GFP_KERNEL); ++ if (!chan_data) ++ return -ENOMEM; ++ ++ ret = of_property_read_u32(dev->of_node, "arm,func-id", ++ &chan_data->function_id); ++ if (ret) ++ return ret; ++ ++ if (of_device_is_compatible(dev->of_node, "arm,smc-mbox")) ++ chan_data->invoke_smc_mbox_fn = __invoke_fn_smc; ++ else ++ chan_data->invoke_smc_mbox_fn = __invoke_fn_hvc; ++ ++ ++ mbox->chans->con_priv = chan_data; ++ ++ mbox->txdone_poll = false; ++ mbox->txdone_irq = false; ++ mbox->ops = &arm_smc_mbox_chan_ops; ++ mbox->dev = dev; ++ ++ platform_set_drvdata(pdev, mbox); ++ ++ ret = devm_mbox_controller_register(dev, mbox); ++ if (ret) ++ return ret; ++ ++ dev_info(dev, "ARM SMC mailbox enabled.\n"); ++ ++ return ret; ++} ++ ++static int arm_smc_mbox_remove(struct platform_device *pdev) ++{ ++ struct mbox_controller *mbox = platform_get_drvdata(pdev); ++ ++ mbox_controller_unregister(mbox); ++ return 0; ++} ++ ++static const struct of_device_id arm_smc_mbox_of_match[] = { ++ { .compatible = "arm,smc-mbox", }, ++ { .compatible = "arm,hvc-mbox", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, arm_smc_mbox_of_match); ++ ++static struct platform_driver arm_smc_mbox_driver = { ++ .driver = { ++ .name = "arm-smc-mbox", ++ .of_match_table = arm_smc_mbox_of_match, ++ }, ++ .probe = arm_smc_mbox_probe, ++ .remove = arm_smc_mbox_remove, ++}; ++module_platform_driver(arm_smc_mbox_driver); ++ ++MODULE_AUTHOR("Peng Fan "); ++MODULE_DESCRIPTION("Generic ARM smc mailbox driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c +index 5c2d1e1f9..ef966887a 100644 +--- a/drivers/mailbox/stm32-ipcc.c ++++ b/drivers/mailbox/stm32-ipcc.c +@@ -52,7 +52,6 @@ struct stm32_ipcc { + struct clk *clk; + spinlock_t lock; /* protect access to IPCC registers */ + int irqs[IPCC_IRQ_NUM]; +- int wkp; + u32 proc_id; + u32 n_chans; + u32 xcr; +@@ -282,16 +281,9 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + + /* wakeup */ + if (of_property_read_bool(np, "wakeup-source")) { +- ipcc->wkp = platform_get_irq_byname(pdev, "wakeup"); +- if (ipcc->wkp < 0) { +- if (ipcc->wkp != -EPROBE_DEFER) +- dev_err(dev, "could not get wakeup IRQ\n"); +- ret = ipcc->wkp; +- goto err_clk; +- } +- + device_set_wakeup_capable(dev, true); +- ret = dev_pm_set_dedicated_wake_irq(dev, ipcc->wkp); ++ ++ ret = dev_pm_set_wake_irq(dev, ipcc->irqs[IPCC_IRQ_RX]); + if (ret) { + dev_err(dev, "Failed to set wake up irq\n"); + goto err_init_wkp; +@@ -334,10 +326,10 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + return 0; + + err_irq_wkp: +- if (ipcc->wkp) ++ if (of_property_read_bool(np, "wakeup-source")) + dev_pm_clear_wake_irq(dev); + err_init_wkp: +- device_init_wakeup(dev, false); ++ device_set_wakeup_capable(dev, false); + err_clk: + clk_disable_unprepare(ipcc->clk); + return ret; +@@ -345,27 +337,17 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + + static int stm32_ipcc_remove(struct platform_device *pdev) + { +- struct stm32_ipcc *ipcc = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; + +- if (ipcc->wkp) ++ if (of_property_read_bool(dev->of_node, "wakeup-source")) + dev_pm_clear_wake_irq(&pdev->dev); + +- device_init_wakeup(&pdev->dev, false); ++ device_set_wakeup_capable(dev, false); + + return 0; + } + + #ifdef CONFIG_PM_SLEEP +-static void stm32_ipcc_set_irq_wake(struct device *dev, bool enable) +-{ +- struct stm32_ipcc *ipcc = dev_get_drvdata(dev); +- unsigned int i; +- +- if (device_may_wakeup(dev)) +- for (i = 0; i < IPCC_IRQ_NUM; i++) +- irq_set_irq_wake(ipcc->irqs[i], enable); +-} +- + static int stm32_ipcc_suspend(struct device *dev) + { + struct stm32_ipcc *ipcc = dev_get_drvdata(dev); +@@ -373,8 +355,6 @@ static int stm32_ipcc_suspend(struct device *dev) + ipcc->xmr = readl_relaxed(ipcc->reg_proc + IPCC_XMR); + ipcc->xcr = readl_relaxed(ipcc->reg_proc + IPCC_XCR); + +- stm32_ipcc_set_irq_wake(dev, true); +- + return 0; + } + +@@ -382,8 +362,6 @@ static int stm32_ipcc_resume(struct device *dev) + { + struct stm32_ipcc *ipcc = dev_get_drvdata(dev); + +- stm32_ipcc_set_irq_wake(dev, false); +- + writel_relaxed(ipcc->xmr, ipcc->reg_proc + IPCC_XMR); + writel_relaxed(ipcc->xcr, ipcc->reg_proc + IPCC_XCR); + +diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig +index 94afdde4b..9d1436ddf 100644 +--- a/drivers/remoteproc/Kconfig ++++ b/drivers/remoteproc/Kconfig +@@ -14,6 +14,25 @@ config REMOTEPROC + + if REMOTEPROC + ++config REMOTEPROC_SRM_CORE ++ tristate "Remoteproc System Resource Manager core" ++ depends on RPMSG ++ help ++ Say y here to enable the core driver of the remoteproc System Resource ++ Manager (SRM). ++ The SRM handles resources allocated to remote processors. ++ The core part is in charge of controlling the device children. ++ ++config REMOTEPROC_SRM_DEV ++ tristate "Remoteproc System Resource Manager device" ++ depends on REMOTEPROC_SRM_CORE ++ help ++ Say y here to enable the device driver of the remoteproc System ++ Resource Manager (SRM). ++ The SRM handles resources allocated to remote processors. ++ The device part is in charge of reserving and initializing resources ++ for a peripheral assigned to a coprocessor. ++ + config IMX_REMOTEPROC + tristate "IMX6/7 remoteproc support" + depends on ARCH_MXC +@@ -204,6 +223,8 @@ config STM32_RPROC + depends on ARCH_STM32 + depends on REMOTEPROC + select MAILBOX ++ select REMOTEPROC_SRM_CORE ++ select REMOTEPROC_SRM_DEV + help + Say y here to support STM32 MCU processors via the + remote processor framework. +diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile +index 00f09e658..0e8bad12b 100644 +--- a/drivers/remoteproc/Makefile ++++ b/drivers/remoteproc/Makefile +@@ -9,6 +9,8 @@ remoteproc-y += remoteproc_debugfs.o + remoteproc-y += remoteproc_sysfs.o + remoteproc-y += remoteproc_virtio.o + remoteproc-y += remoteproc_elf_loader.o ++obj-$(CONFIG_REMOTEPROC_SRM_CORE) += rproc_srm_core.o ++obj-$(CONFIG_REMOTEPROC_SRM_DEV) += rproc_srm_dev.o + obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o + obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o + obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o +diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c +index b542debbc..cdbec7fc3 100644 +--- a/drivers/remoteproc/remoteproc_core.c ++++ b/drivers/remoteproc/remoteproc_core.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1372,7 +1373,11 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) + if (ret) + return ret; + +- dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); ++ if (fw) ++ dev_info(dev, "Booting fw image %s, size %zd\n", name, ++ fw->size); ++ else ++ dev_info(dev, "Synchronizing with early booted co-processor\n"); + + /* + * if enabling an IOMMU isn't relevant for this rproc, this is +@@ -1467,6 +1472,9 @@ static int rproc_stop(struct rproc *rproc, bool crashed) + struct device *dev = &rproc->dev; + int ret; + ++ if (rproc->state == RPROC_OFFLINE) ++ return 0; ++ + /* Stop any subdevices for the remote processor */ + rproc_stop_subdevices(rproc, crashed); + +@@ -1667,6 +1675,13 @@ int rproc_trigger_recovery(struct rproc *rproc) + /* generate coredump */ + rproc_coredump(rproc); + ++ if (!rproc->firmware) { ++ /* we don't know how to recover it, so try to shutdown it*/ ++ mutex_unlock(&rproc->lock); ++ rproc_shutdown(rproc); ++ return 0; ++ } ++ + /* load firmware */ + ret = request_firmware(&firmware_p, rproc->firmware, dev); + if (ret < 0) { +@@ -1728,7 +1743,7 @@ static void rproc_crash_handler_work(struct work_struct *work) + */ + int rproc_boot(struct rproc *rproc) + { +- const struct firmware *firmware_p; ++ const struct firmware *firmware_p = NULL; + struct device *dev; + int ret; + +@@ -1759,11 +1774,17 @@ int rproc_boot(struct rproc *rproc) + + dev_info(dev, "powering up %s\n", rproc->name); + +- /* load firmware */ +- ret = request_firmware(&firmware_p, rproc->firmware, dev); +- if (ret < 0) { +- dev_err(dev, "request_firmware failed: %d\n", ret); +- goto downref_rproc; ++ if (!rproc->early_boot) { ++ /* load firmware */ ++ ret = request_firmware(&firmware_p, rproc->firmware, dev); ++ if (ret < 0) { ++ dev_err(dev, "request_firmware failed: %d\n", ret); ++ goto downref_rproc; ++ } ++ } else { ++ /* set firmware name to null as unknown */ ++ kfree(rproc->firmware); ++ rproc->firmware = NULL; + } + + ret = rproc_fw_boot(rproc, firmware_p); +@@ -1917,8 +1938,22 @@ int rproc_add(struct rproc *rproc) + /* create debugfs entries */ + rproc_create_debug_dir(rproc); + +- /* if rproc is marked always-on, request it to boot */ +- if (rproc->auto_boot) { ++ /* add resource manager device */ ++ ret = devm_of_platform_populate(dev->parent); ++ if (ret < 0) ++ return ret; ++ ++ if (rproc->early_boot) { ++ /* ++ * If rproc is marked already booted, no need to wait ++ * for firmware. ++ * Just handle associated resources and start sub devices ++ */ ++ ret = rproc_boot(rproc); ++ if (ret < 0) ++ return ret; ++ } else if (rproc->auto_boot) { ++ /* if rproc is marked always-on, request it to boot */ + ret = rproc_trigger_auto_boot(rproc); + if (ret < 0) + return ret; +@@ -2144,6 +2179,8 @@ int rproc_del(struct rproc *rproc) + list_del(&rproc->node); + mutex_unlock(&rproc_list_mutex); + ++ of_platform_depopulate(rproc->dev.parent); ++ + device_del(&rproc->dev); + + return 0; +diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c +new file mode 100644 +index 000000000..fc61e8b35 +--- /dev/null ++++ b/drivers/remoteproc/rproc_srm_core.c +@@ -0,0 +1,303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rproc_srm_core.h" ++ ++#define BIND_TIMEOUT 10000 ++ ++struct rproc_srm_core { ++ struct device *dev; ++ struct completion all_bound; ++ int bind_status; ++ atomic_t prepared; ++ struct rproc_subdev subdev; ++ struct rpmsg_driver rpdrv; ++ struct blocking_notifier_head notifier; ++}; ++ ++#define to_rproc_srm_core(s) container_of(s, struct rproc_srm_core, subdev) ++ ++static struct rproc_srm_core *rpmsg_srm_to_core(struct rpmsg_device *rpdev) ++{ ++ struct rpmsg_driver *rpdrv; ++ struct rproc_srm_core *core; ++ ++ rpdrv = container_of(rpdev->dev.driver, struct rpmsg_driver, drv); ++ core = container_of(rpdrv, struct rproc_srm_core, rpdrv); ++ ++ return core; ++} ++ ++int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg) ++{ ++ int ret; ++ ++ ret = rpmsg_send(ept, (void *)msg, sizeof(*msg)); ++ if (ret) ++ dev_err(&ept->rpdev->dev, "rpmsg_send failed: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rpmsg_srm_send); ++ ++static int rpmsg_srm_cb(struct rpmsg_device *rpdev, void *data, int len, ++ void *priv, u32 src) ++{ ++ struct rproc_srm_core *core = rpmsg_srm_to_core(rpdev); ++ struct rpmsg_srm_msg_desc desc; ++ int ret; ++ ++ desc.ept = rpdev->ept; ++ desc.msg = data; ++ ++ ret = blocking_notifier_call_chain(&core->notifier, 0, &desc); ++ ++ if (!(ret & NOTIFY_STOP_MASK)) { ++ dev_warn(&rpdev->dev, "unknown device\n"); ++ desc.msg->message_type = RPROC_SRM_MSG_ERROR; ++ rpmsg_srm_send(desc.ept, desc.msg); ++ } ++ ++ return 0; ++} ++ ++static int rpmsg_srm_probe(struct rpmsg_device *rpdev) ++{ ++ int ret; ++ ++ dev_dbg(&rpdev->dev, "%s\n", __func__); ++ ++ /* Send an empty message to complete the initialization */ ++ ret = rpmsg_send(rpdev->ept, NULL, 0); ++ if (ret) ++ dev_err(&rpdev->dev, "failed to send init message\n"); ++ ++ return ret; ++} ++ ++static void rpmsg_srm_remove(struct rpmsg_device *rpdev) ++{ ++ /* Note : the remove ops is mandatory */ ++ dev_dbg(&rpdev->dev, "%s\n", __func__); ++} ++ ++static struct rpmsg_device_id rpmsg_srm_id_table[] = { ++ { .name = "rproc-srm" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(rpmsg, rpmsg_srm_id_table); ++ ++static struct rpmsg_driver rpmsg_srm_drv = { ++ .drv.name = "rpmsg_srm", ++ .id_table = rpmsg_srm_id_table, ++ .probe = rpmsg_srm_probe, ++ .callback = rpmsg_srm_cb, ++ .remove = rpmsg_srm_remove, ++}; ++ ++int rproc_srm_core_register_notifier(struct rproc_srm_core *core, ++ struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&core->notifier, nb); ++} ++EXPORT_SYMBOL(rproc_srm_core_register_notifier); ++ ++int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, ++ struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&core->notifier, nb); ++} ++EXPORT_SYMBOL(rproc_srm_core_unregister_notifier); ++ ++static int compare_of(struct device *dev, void *data) ++{ ++ return dev->of_node == data; ++} ++ ++static void release_of(struct device *dev, void *data) ++{ ++ of_node_put(data); ++} ++ ++static void rproc_srm_core_unbind(struct device *dev) ++{ ++ component_unbind_all(dev, NULL); ++} ++ ++static int rproc_srm_core_bind(struct device *dev) ++{ ++ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); ++ ++ rproc_srm_core->bind_status = component_bind_all(dev, NULL); ++ complete(&rproc_srm_core->all_bound); ++ ++ return rproc_srm_core->bind_status; ++} ++ ++static const struct component_master_ops srm_comp_ops = { ++ .bind = rproc_srm_core_bind, ++ .unbind = rproc_srm_core_unbind, ++}; ++ ++static int rproc_srm_core_prepare(struct rproc_subdev *subdev) ++{ ++ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); ++ struct device *dev = rproc_srm_core->dev; ++ struct device_node *node = dev->of_node; ++ struct device_node *child_np; ++ struct component_match *match = NULL; ++ int ret; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ init_completion(&rproc_srm_core->all_bound); ++ ++ ret = devm_of_platform_populate(dev); ++ if (ret) { ++ dev_err(dev, "cannot populate node (%d)\n", ret); ++ return ret; ++ } ++ ++ child_np = of_get_next_available_child(node, NULL); ++ ++ while (child_np) { ++ of_node_get(child_np); ++ component_match_add_release(dev, &match, release_of, compare_of, ++ child_np); ++ child_np = of_get_next_available_child(node, child_np); ++ } ++ ++ if (!match) { ++ dev_dbg(dev, "No available child\n"); ++ goto done; ++ } ++ ++ ret = component_master_add_with_match(dev, &srm_comp_ops, match); ++ if (ret) ++ goto depopulate; ++ ++ /* Wait for every child to be bound */ ++ if (!wait_for_completion_timeout(&rproc_srm_core->all_bound, ++ msecs_to_jiffies(BIND_TIMEOUT))) { ++ dev_err(dev, "failed to bind one or more system resource device(s)\n"); ++ ret = -ETIMEDOUT; ++ goto master; ++ } ++ ++ ret = rproc_srm_core->bind_status; ++ if (ret) { ++ dev_err(dev, "failed to bind\n"); ++ goto master; ++ } ++ ++ /* Register rpmsg driver for dynamic management */ ++ rproc_srm_core->rpdrv = rpmsg_srm_drv; ++ ret = register_rpmsg_driver(&rproc_srm_core->rpdrv); ++ if (ret) { ++ dev_err(dev, "failed to register rpmsg drv\n"); ++ goto master; ++ } ++ ++done: ++ atomic_inc(&rproc_srm_core->prepared); ++ ++ return 0; ++ ++master: ++ component_master_del(dev, &srm_comp_ops); ++depopulate: ++ devm_of_platform_depopulate(dev); ++ return ret; ++} ++ ++static void rproc_srm_core_unprepare(struct rproc_subdev *subdev) ++{ ++ struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev); ++ struct device *dev = rproc_srm_core->dev; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ if (!atomic_read(&rproc_srm_core->prepared)) ++ return; ++ ++ atomic_dec(&rproc_srm_core->prepared); ++ ++ unregister_rpmsg_driver(&rproc_srm_core->rpdrv); ++ ++ component_master_del(dev, &srm_comp_ops); ++ devm_of_platform_depopulate(dev); ++} ++ ++static int rproc_srm_core_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rproc *rproc = dev_get_drvdata(dev->parent); ++ struct rproc_srm_core *rproc_srm_core; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ rproc_srm_core = devm_kzalloc(dev, sizeof(struct rproc_srm_core), ++ GFP_KERNEL); ++ if (!rproc_srm_core) ++ return -ENOMEM; ++ ++ rproc_srm_core->dev = dev; ++ BLOCKING_INIT_NOTIFIER_HEAD(&rproc_srm_core->notifier); ++ ++ /* Register rproc subdevice with (un)prepare ops */ ++ rproc_srm_core->subdev.prepare = rproc_srm_core_prepare; ++ rproc_srm_core->subdev.unprepare = rproc_srm_core_unprepare; ++ rproc_add_subdev(rproc, &rproc_srm_core->subdev); ++ ++ dev_set_drvdata(dev, rproc_srm_core); ++ ++ return 0; ++} ++ ++static int rproc_srm_core_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rproc_srm_core *rproc_srm_core = dev_get_drvdata(dev); ++ struct rproc *rproc = dev_get_drvdata(dev->parent); ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ if (atomic_read(&rproc->power) > 0) ++ dev_warn(dev, "Releasing resources while firmware running!\n"); ++ ++ rproc_srm_core_unprepare(&rproc_srm_core->subdev); ++ ++ return 0; ++} ++ ++static const struct of_device_id rproc_srm_core_match[] = { ++ { .compatible = "rproc-srm-core", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, rproc_srm_core_match); ++ ++static struct platform_driver rproc_srm_core_driver = { ++ .probe = rproc_srm_core_probe, ++ .remove = rproc_srm_core_remove, ++ .driver = { ++ .name = "rproc-srm-core", ++ .of_match_table = of_match_ptr(rproc_srm_core_match), ++ }, ++}; ++ ++module_platform_driver(rproc_srm_core_driver); ++ ++MODULE_AUTHOR("Fabien Dessenne "); ++MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - core"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h +new file mode 100644 +index 000000000..7dffdb38f +--- /dev/null ++++ b/drivers/remoteproc/rproc_srm_core.h +@@ -0,0 +1,98 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++#ifndef _RPROC_SRM_CORE_H_ ++#define _RPROC_SRM_CORE_H_ ++ ++/** ++ * Message type used in resource manager rpmsg: ++ * RPROC_SRM_MSG_GETCONFIG: Request to get the configuration of a resource ++ * RPROC_SRM_MSG_SETCONFIG: Request to set the configuration of a resource ++ * RPROC_SRM_MSG_ERROR: Error when processing a request ++ */ ++#define RPROC_SRM_MSG_GETCONFIG 0x00 ++#define RPROC_SRM_MSG_SETCONFIG 0x01 ++#define RPROC_SRM_MSG_ERROR 0xFF ++ ++/** ++ * Resource type used in resource manager rpmsg: ++ * RPROC_SRM_RSC_CLOCK: clock resource ++ * RPROC_SRM_RSC_REGU: regulator resource ++ */ ++#define RPROC_SRM_RSC_CLOCK 0x00 ++#define RPROC_SRM_RSC_REGU 0x01 ++ ++/** ++ * struct clock_cfg - clock configuration used in resource manager rpmsg ++ * @index: clock index ++ * @name: clock name ++ * @rate: clock rate request (in SetConfig message) or current status (in ++ * GetConfig message) ++ */ ++struct clock_cfg { ++ u32 index; ++ u8 name[16]; ++ u32 rate; ++}; ++ ++/** ++ * struct regu_cfg - regu configuration used in resource manager rpmsg ++ * @index: regulator index ++ * @name: regulator name ++ * @enable: regulator enable/disable request (in SetConfig message) or ++ * current status (in GetConfig message) ++ * @curr_voltage_mv: current regulator voltage in mV (meaningful in ++ * SetConfig message) ++ * @min_voltage_mv: regulator min voltage request in mV (meaningful in ++ * SetConfig message) ++ * @max_voltage_mv: regulator max voltage request in mV (meaningful in ++ * SetConfig message) ++ */ ++struct regu_cfg { ++ u32 index; ++ u8 name[16]; ++ u32 enable; ++ u32 curr_voltage_mv; ++ u32 min_voltage_mv; ++ u32 max_voltage_mv; ++}; ++ ++/** ++ * struct rpmsg_srm_msg - message structure used between processors to ++ * dynamically update resources configuration ++ * @message_type: type of the message: see RPROC_SRM_MSG* ++ * @device_id: an identifier specifying the device owning the resources. ++ * This is implementation dependent. As example it may be the ++ * device name or the device address. ++ * @rsc_type: the type of the resource for which the configuration applies: ++ * see RPROC_SRM_RSC* ++ * @clock_cfg: clock config - relevant if &rsc_type is RPROC_SRM_RSC_CLOCK ++ * @regu_cfg: regulator config - relevant if &rsc_type is RPROC_SRM_RSC_REGU ++ */ ++struct rpmsg_srm_msg { ++ u32 message_type; ++ u8 device_id[32]; ++ u32 rsc_type; ++ union { ++ struct clock_cfg clock_cfg; ++ struct regu_cfg regu_cfg; ++ }; ++}; ++ ++struct rpmsg_srm_msg_desc { ++ struct rpmsg_endpoint *ept; ++ struct rpmsg_srm_msg *msg; ++}; ++ ++struct rproc_srm_core; ++ ++int rproc_srm_core_register_notifier(struct rproc_srm_core *core, ++ struct notifier_block *nb); ++int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core, ++ struct notifier_block *nb); ++int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg); ++ ++#endif +diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c +new file mode 100644 +index 000000000..6b164dad5 +--- /dev/null ++++ b/drivers/remoteproc/rproc_srm_dev.c +@@ -0,0 +1,744 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rproc_srm_core.h" ++ ++struct rproc_srm_clk_info { ++ struct list_head list; ++ unsigned int index; ++ struct clk *clk; ++ const char *name; ++ bool parent_enabled; ++}; ++ ++struct rproc_srm_regu_info { ++ struct list_head list; ++ unsigned int index; ++ struct regulator *regu; ++ const char *name; ++ bool enabled; ++}; ++ ++struct rproc_srm_irq_info { ++ struct list_head list; ++ unsigned int index; ++ char *name; ++ int irq; ++ bool enabled; ++}; ++ ++struct rproc_srm_dev { ++ struct device *dev; ++ struct rproc_srm_core *core; ++ struct notifier_block nb; ++ bool early_boot; ++ ++ struct list_head clk_list_head; ++ struct list_head regu_list_head; ++ struct list_head irq_list_head; ++}; ++ ++/* Irqs */ ++static void rproc_srm_dev_irqs_put(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct rproc_srm_irq_info *i, *tmp; ++ ++ list_for_each_entry_safe(i, tmp, &rproc_srm_dev->irq_list_head, list) { ++ devm_free_irq(dev, i->irq, NULL); ++ dev_dbg(dev, "Put irq %d (%s)\n", i->irq, i->name); ++ list_del(&i->list); ++ } ++} ++ ++static irqreturn_t rproc_srm_dev_irq_handler(int irq, void *dev) ++{ ++ dev_warn(dev, "Spurious interrupt\n"); ++ return IRQ_HANDLED; ++} ++ ++static int rproc_srm_dev_irqs_get(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct device_node *np = dev->of_node; ++ struct rproc_srm_irq_info *info; ++ const char *name; ++ int nr, ret, irq; ++ unsigned int i; ++ ++ if (!np) ++ return 0; ++ ++ nr = platform_irq_count(pdev); ++ if (!nr) ++ return 0; ++ ++ if (rproc_srm_dev->early_boot) ++ /* ++ * Do not overwrite the irq configuration. ++ * No need to parse irq from DT since the resource manager does ++ * not offer any service to update the irq config. ++ */ ++ return 0; ++ ++ for (i = 0; i < nr; i++) { ++ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ irq = platform_get_irq(pdev, i); ++ if (irq <= 0) { ++ ret = irq; ++ dev_err(dev, "Failed to get irq (%d)\n", ret); ++ goto err; ++ } ++ ++ info->irq = irq; ++ ++ /* Register a dummy irq handleras not used by Linux */ ++ ret = devm_request_irq(dev, info->irq, ++ rproc_srm_dev_irq_handler, 0, ++ dev_name(dev), NULL); ++ if (ret) { ++ dev_err(dev, "Failed to request irq (%d)\n", ret); ++ goto err; ++ } ++ ++ /* ++ * Disable IRQ. Since it is used by the remote processor we ++ * must not use the 'irq lazy disable' optimization ++ */ ++ irq_set_status_flags(info->irq, IRQ_DISABLE_UNLAZY); ++ disable_irq(info->irq); ++ ++ /* Note: "interrupt-names" is optional */ ++ if (!of_property_read_string_index(np, "interrupt-names", i, ++ &name)) ++ info->name = devm_kstrdup(dev, name, GFP_KERNEL); ++ else ++ info->name = devm_kstrdup(dev, "", GFP_KERNEL); ++ ++ info->index = i; ++ ++ list_add_tail(&info->list, &rproc_srm_dev->irq_list_head); ++ dev_dbg(dev, "Got irq %d (%s)\n", info->irq, info->name); ++ } ++ ++ return 0; ++ ++err: ++ rproc_srm_dev_irqs_put(rproc_srm_dev); ++ ++ return ret; ++} ++ ++/* Clocks */ ++static void rproc_srm_dev_clocks_unsetup(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct rproc_srm_clk_info *c; ++ ++ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { ++ if (!c->parent_enabled) ++ continue; ++ ++ clk_disable_unprepare(clk_get_parent(c->clk)); ++ c->parent_enabled = false; ++ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) unsetup\n", ++ c->index, c->name); ++ } ++} ++ ++static int rproc_srm_dev_clocks_setup(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct rproc_srm_clk_info *c; ++ int ret; ++ ++ /* ++ * Prepare and enable the parent clocks. ++ * Since the clock tree is under the exclusive control of the master ++ * processor, we need to configure the clock tree of the targeted clock. ++ * We do not want to enable the clock itself, which is under the ++ * responsibility of the remote processor. ++ * Hence we prepare and enable the parent clock. ++ */ ++ ++ list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) { ++ if (c->parent_enabled) ++ continue; ++ ++ ret = clk_prepare_enable(clk_get_parent(c->clk)); ++ if (ret) { ++ dev_err(rproc_srm_dev->dev, ++ "clk %d (%s) parent enable failed\n", ++ c->index, c->name); ++ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); ++ return ret; ++ } ++ c->parent_enabled = true; ++ dev_dbg(rproc_srm_dev->dev, "clk %d (%s) parent enabled\n", ++ c->index, c->name); ++ } ++ ++ return 0; ++} ++ ++static struct rproc_srm_clk_info ++ *rproc_srm_dev_clock_find(struct rproc_srm_dev *rproc_srm_dev, ++ struct clock_cfg *cfg) ++{ ++ struct rproc_srm_clk_info *ci; ++ ++ /* Search by index (if valid value) otherwise search by name */ ++ list_for_each_entry(ci, &rproc_srm_dev->clk_list_head, list) { ++ if (cfg->index != U32_MAX) { ++ if (ci->index == cfg->index) ++ return ci; ++ } else { ++ if (!strcmp(ci->name, cfg->name)) ++ return ci; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int rproc_srm_dev_clock_set_cfg(struct rproc_srm_dev *rproc_srm_dev, ++ struct clock_cfg *cfg) ++{ ++ struct rproc_srm_clk_info *c; ++ struct device *dev = rproc_srm_dev->dev; ++ int ret; ++ ++ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); ++ ++ if (!c) { ++ dev_err(dev, "unknown clock (id %d)\n", cfg->index); ++ return -EINVAL; ++ } ++ ++ if (cfg->rate && clk_get_rate(c->clk) != cfg->rate) { ++ ret = clk_set_rate(c->clk, cfg->rate); ++ if (ret) { ++ dev_err(dev, "clk set rate failed\n"); ++ return ret; ++ } ++ ++ dev_dbg(dev, "clk %d (%s) rate = %d\n", c->index, c->name, ++ cfg->rate); ++ } ++ ++ return 0; ++} ++ ++static int rproc_srm_dev_clock_get_cfg(struct rproc_srm_dev *rproc_srm_dev, ++ struct clock_cfg *cfg) ++{ ++ struct rproc_srm_clk_info *c; ++ ++ c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg); ++ if (!c) { ++ dev_err(rproc_srm_dev->dev, "unknown clock (%d)\n", cfg->index); ++ return -EINVAL; ++ } ++ ++ strlcpy(cfg->name, c->name, sizeof(cfg->name)); ++ cfg->index = c->index; ++ cfg->rate = (u32)clk_get_rate(c->clk); ++ ++ return 0; ++} ++ ++static void rproc_srm_dev_clocks_put(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct rproc_srm_clk_info *c, *tmp; ++ ++ list_for_each_entry_safe(c, tmp, &rproc_srm_dev->clk_list_head, list) { ++ clk_put(c->clk); ++ dev_dbg(dev, "put clock %d (%s)\n", c->index, c->name); ++ list_del(&c->list); ++ } ++} ++ ++static int rproc_srm_dev_clocks_get(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct device_node *np = dev->of_node; ++ struct rproc_srm_clk_info *c; ++ const char *name; ++ int nb_c, ret; ++ unsigned int i; ++ ++ if (!np) ++ return 0; ++ ++ nb_c = of_clk_get_parent_count(np); ++ if (!nb_c) ++ return 0; ++ ++ for (i = 0; i < nb_c; i++) { ++ c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); ++ if (!c) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ c->clk = of_clk_get(np, i); ++ if (IS_ERR(c->clk)) { ++ dev_err(dev, "clock %d KO (%ld)\n", i, ++ PTR_ERR(c->clk)); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ /* Note: "clock-names" is optional */ ++ if (!of_property_read_string_index(np, "clock-names", i, ++ &name)) ++ c->name = devm_kstrdup(dev, name, GFP_KERNEL); ++ else ++ c->name = devm_kstrdup(dev, "", GFP_KERNEL); ++ ++ c->index = i; ++ ++ list_add_tail(&c->list, &rproc_srm_dev->clk_list_head); ++ dev_dbg(dev, "got clock %d (%s)\n", c->index, c->name); ++ } ++ ++ return 0; ++ ++err: ++ rproc_srm_dev_clocks_put(rproc_srm_dev); ++ return ret; ++} ++ ++/* Regulators */ ++static void rproc_srm_dev_regus_unsetup(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct rproc_srm_regu_info *r; ++ struct device *dev = rproc_srm_dev->dev; ++ ++ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { ++ if (!r->enabled) ++ continue; ++ ++ if (regulator_disable(r->regu)) { ++ dev_warn(dev, "regu %d disabled failed\n", r->index); ++ continue; ++ } ++ ++ r->enabled = false; ++ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); ++ } ++} ++ ++static int rproc_srm_dev_regus_setup(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct rproc_srm_regu_info *r; ++ int ret; ++ ++ /* Enable all the regulators */ ++ list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) { ++ if (r->enabled) ++ continue; ++ ++ /* in early_boot mode sync on hw */ ++ if (rproc_srm_dev->early_boot && !regulator_is_enabled(r->regu)) ++ continue; ++ ++ ret = regulator_enable(r->regu); ++ if (ret) { ++ dev_err(rproc_srm_dev->dev, "regu %d (%s) failed\n", ++ r->index, r->name); ++ rproc_srm_dev_regus_unsetup(rproc_srm_dev); ++ return ret; ++ } ++ r->enabled = true; ++ dev_dbg(rproc_srm_dev->dev, "regu %d (%s) enabled\n", ++ r->index, r->name); ++ } ++ ++ return 0; ++} ++ ++static struct rproc_srm_regu_info ++ *rproc_srm_dev_regu_find(struct rproc_srm_dev *rproc_srm_dev, ++ struct regu_cfg *cfg) ++{ ++ struct rproc_srm_regu_info *ri; ++ ++ list_for_each_entry(ri, &rproc_srm_dev->regu_list_head, list) { ++ if (cfg->index != U32_MAX) { ++ if (ri->index == cfg->index) ++ return ri; ++ } else { ++ if (!strcmp(ri->name, cfg->name)) ++ return ri; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int rproc_srm_dev_regu_set_cfg(struct rproc_srm_dev *rproc_srm_dev, ++ struct regu_cfg *cfg) ++{ ++ struct rproc_srm_regu_info *r; ++ struct device *dev = rproc_srm_dev->dev; ++ int ret; ++ ++ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); ++ if (!r) { ++ dev_err(dev, "unknown regu (%d)\n", cfg->index); ++ return -EINVAL; ++ } ++ ++ if (!r->enabled && cfg->enable) { ++ ret = regulator_enable(r->regu); ++ if (ret) { ++ dev_err(dev, "regu %d enable failed\n", r->index); ++ return ret; ++ } ++ r->enabled = true; ++ dev_dbg(dev, "regu %d (%s) enabled\n", r->index, r->name); ++ } else if (r->enabled && !cfg->enable) { ++ ret = regulator_disable(r->regu); ++ if (ret) { ++ dev_err(dev, "regu %d disable failed\n", r->index); ++ return ret; ++ } ++ r->enabled = false; ++ dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name); ++ } ++ ++ if (cfg->min_voltage_mv || cfg->max_voltage_mv) { ++ ret = regulator_set_voltage(r->regu, cfg->min_voltage_mv * 1000, ++ cfg->max_voltage_mv * 1000); ++ if (ret) { ++ dev_err(dev, "regu %d set voltage failed\n", r->index); ++ return ret; ++ } ++ ++ dev_dbg(dev, "regu %d (%s) voltage = [%d - %d] mv\n", r->index, ++ r->name, cfg->min_voltage_mv, cfg->max_voltage_mv); ++ } ++ ++ return 0; ++} ++ ++static int rproc_srm_dev_regu_get_cfg(struct rproc_srm_dev *rproc_srm_dev, ++ struct regu_cfg *cfg) ++{ ++ struct rproc_srm_regu_info *r; ++ struct device *dev = rproc_srm_dev->dev; ++ int v; ++ ++ r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg); ++ if (!r) { ++ dev_err(dev, "unknown regu (%d)\n", cfg->index); ++ return -EINVAL; ++ } ++ ++ strlcpy(cfg->name, r->name, sizeof(cfg->name)); ++ cfg->index = r->index; ++ cfg->enable = r->enabled; ++ cfg->min_voltage_mv = 0; ++ cfg->max_voltage_mv = 0; ++ ++ v = regulator_get_voltage(r->regu); ++ if (v < 0) { ++ dev_warn(dev, "cannot get %s voltage\n", r->name); ++ cfg->curr_voltage_mv = 0; ++ } else { ++ cfg->curr_voltage_mv = v / 1000; ++ } ++ ++ return 0; ++} ++ ++static void rproc_srm_dev_regus_put(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct rproc_srm_regu_info *r, *tmp; ++ ++ list_for_each_entry_safe(r, tmp, &rproc_srm_dev->regu_list_head, list) { ++ devm_regulator_put(r->regu); ++ dev_dbg(dev, "put regu %d (%s)\n", r->index, r->name); ++ list_del(&r->list); ++ } ++} ++ ++static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev) ++{ ++ struct device *dev = rproc_srm_dev->dev; ++ struct device_node *np = dev->of_node; ++ struct property *p; ++ const char *n; ++ char *name; ++ struct rproc_srm_regu_info *r; ++ int ret, nb_s = 0; ++ ++ if (!np) ++ return 0; ++ ++ for_each_property_of_node(np, p) { ++ n = strstr(p->name, "-supply"); ++ if (!n || n == p->name) ++ continue; ++ ++ r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); ++ if (!r) { ++ ret = -ENOMEM; ++ goto err_list; ++ } ++ ++ name = devm_kstrdup(dev, p->name, GFP_KERNEL); ++ name[strlen(p->name) - strlen("-supply")] = '\0'; ++ r->name = name; ++ ++ r->regu = devm_regulator_get(dev, r->name); ++ if (IS_ERR(r->regu)) { ++ dev_err(dev, "cannot get regu %s\n", r->name); ++ ret = -EINVAL; ++ goto err_list; ++ } ++ ++ r->index = nb_s++; ++ ++ list_add_tail(&r->list, &rproc_srm_dev->regu_list_head); ++ dev_dbg(dev, "got regu %d (%s)\n", r->index, r->name); ++ } ++ ++ return 0; ++ ++err_list: ++ rproc_srm_dev_regus_put(rproc_srm_dev); ++ return ret; ++} ++ ++/* Core */ ++static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, ++ void *data) ++{ ++ struct rproc_srm_dev *rproc_srm_dev = ++ container_of(nb, struct rproc_srm_dev, nb); ++ struct device *dev = rproc_srm_dev->dev; ++ struct rpmsg_srm_msg_desc *desc; ++ struct rpmsg_srm_msg *i, o; ++ int ret = 0; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ desc = (struct rpmsg_srm_msg_desc *)data; ++ i = desc->msg; ++ o = *i; ++ ++ /* Check if 'device_id' (name / addr ) matches this device */ ++ if (!strstr(dev_name(dev), i->device_id)) ++ return NOTIFY_DONE; ++ ++ switch (i->message_type) { ++ case RPROC_SRM_MSG_SETCONFIG: ++ switch (i->rsc_type) { ++ case RPROC_SRM_RSC_CLOCK: ++ ret = rproc_srm_dev_clock_set_cfg(rproc_srm_dev, ++ &i->clock_cfg); ++ if (!ret) ++ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, ++ &o.clock_cfg); ++ break; ++ case RPROC_SRM_RSC_REGU: ++ ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev, ++ &i->regu_cfg); ++ if (!ret) ++ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, ++ &o.regu_cfg); ++ break; ++ default: ++ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); ++ ret = -EINVAL; ++ break; ++ } ++ break; ++ case RPROC_SRM_MSG_GETCONFIG: ++ switch (i->rsc_type) { ++ case RPROC_SRM_RSC_CLOCK: ++ ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, ++ &o.clock_cfg); ++ break; ++ case RPROC_SRM_RSC_REGU: ++ ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, ++ &o.regu_cfg); ++ break; ++ default: ++ dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type); ++ ret = -EINVAL; ++ break; ++ } ++ break; ++ default: ++ dev_warn(dev, "bad msg type (%d)\n", i->message_type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ /* Send return msg */ ++ if (ret) ++ o.message_type = RPROC_SRM_MSG_ERROR; ++ ++ ret = rpmsg_srm_send(desc->ept, &o); ++ ++ return ret ? NOTIFY_BAD : NOTIFY_STOP; ++} ++ ++static void ++rproc_srm_dev_unbind(struct device *dev, struct device *master, void *data) ++{ ++ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ rproc_srm_dev_regus_unsetup(rproc_srm_dev); ++ rproc_srm_dev_clocks_unsetup(rproc_srm_dev); ++ ++ /* For IRQs: nothing to unsetup */ ++} ++ ++static int ++rproc_srm_dev_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ ret = rproc_srm_dev_clocks_setup(rproc_srm_dev); ++ if (ret) ++ return ret; ++ ++ ret = rproc_srm_dev_regus_setup(rproc_srm_dev); ++ if (ret) ++ return ret; ++ ++ /* For IRQs: nothing to setup */ ++ return 0; ++} ++ ++static const struct component_ops rproc_srm_dev_ops = { ++ .bind = rproc_srm_dev_bind, ++ .unbind = rproc_srm_dev_unbind, ++}; ++ ++static int rproc_srm_dev_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rproc_srm_dev *rproc_srm_dev; ++ struct rproc *rproc; ++ int ret; ++ ++ dev_dbg(dev, "%s for node %s\n", __func__, dev->of_node->name); ++ ++ rproc_srm_dev = devm_kzalloc(dev, sizeof(struct rproc_srm_dev), ++ GFP_KERNEL); ++ if (!rproc_srm_dev) ++ return -ENOMEM; ++ ++ rproc_srm_dev->dev = dev; ++ rproc = (struct rproc *)dev_get_drvdata(dev->parent->parent); ++ rproc_srm_dev->early_boot = rproc->early_boot; ++ rproc_srm_dev->core = dev_get_drvdata(dev->parent); ++ ++ INIT_LIST_HEAD(&rproc_srm_dev->clk_list_head); ++ INIT_LIST_HEAD(&rproc_srm_dev->regu_list_head); ++ INIT_LIST_HEAD(&rproc_srm_dev->irq_list_head); ++ ++ /* Get clocks, regu and irqs */ ++ ret = rproc_srm_dev_clocks_get(rproc_srm_dev); ++ if (ret) ++ return ret; ++ ++ ret = rproc_srm_dev_regus_get(rproc_srm_dev); ++ if (ret) ++ goto err_get; ++ ++ ret = rproc_srm_dev_irqs_get(rproc_srm_dev); ++ if (ret) ++ goto err_get; ++ ++ rproc_srm_dev->nb.notifier_call = rproc_srm_dev_notify_cb; ++ ret = rproc_srm_core_register_notifier(rproc_srm_dev->core, ++ &rproc_srm_dev->nb); ++ if (ret) ++ goto err_register; ++ ++ dev_set_drvdata(dev, rproc_srm_dev); ++ ++ return component_add(dev, &rproc_srm_dev_ops); ++ ++err_register: ++ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, ++ &rproc_srm_dev->nb); ++err_get: ++ rproc_srm_dev_irqs_put(rproc_srm_dev); ++ rproc_srm_dev_regus_put(rproc_srm_dev); ++ rproc_srm_dev_clocks_put(rproc_srm_dev); ++ return ret; ++} ++ ++static int rproc_srm_dev_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rproc_srm_dev *rproc_srm_dev = dev_get_drvdata(dev); ++ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ component_del(dev, &rproc_srm_dev_ops); ++ ++ rproc_srm_core_unregister_notifier(rproc_srm_dev->core, ++ &rproc_srm_dev->nb); ++ ++ rproc_srm_dev_irqs_put(rproc_srm_dev); ++ rproc_srm_dev_regus_put(rproc_srm_dev); ++ rproc_srm_dev_clocks_put(rproc_srm_dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id rproc_srm_dev_match[] = { ++ { .compatible = "rproc-srm-dev", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, rproc_srm_dev_match); ++ ++static struct platform_driver rproc_srm_dev_driver = { ++ .probe = rproc_srm_dev_probe, ++ .remove = rproc_srm_dev_remove, ++ .driver = { ++ .name = "rproc-srm-dev", ++ .of_match_table = of_match_ptr(rproc_srm_dev_match), ++ }, ++}; ++ ++module_platform_driver(rproc_srm_dev_driver); ++ ++MODULE_AUTHOR("Fabien Dessenne "); ++MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - dev"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c +index 2cf4b2992..061562405 100644 +--- a/drivers/remoteproc/stm32_rproc.c ++++ b/drivers/remoteproc/stm32_rproc.c +@@ -15,9 +15,11 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + + #include "remoteproc_internal.h" + +@@ -31,9 +33,20 @@ + #define STM32_SMC_REG_WRITE 0x1 + + #define STM32_MBX_VQ0 "vq0" ++#define STM32_MBX_VQ0_ID 0 + #define STM32_MBX_VQ1 "vq1" ++#define STM32_MBX_VQ1_ID 1 + #define STM32_MBX_SHUTDOWN "shutdown" + ++#define RSC_TBL_SIZE (1024) ++ ++#define COPRO_STATE_OFF 0 ++#define COPRO_STATE_INIT 1 ++#define COPRO_STATE_CRUN 2 ++#define COPRO_STATE_CSTOP 3 ++#define COPRO_STATE_STANDBY 4 ++#define COPRO_STATE_CRASH 5 ++ + struct stm32_syscon { + struct regmap *map; + u32 reg; +@@ -58,6 +71,7 @@ struct stm32_mbox { + const unsigned char name[10]; + struct mbox_chan *chan; + struct mbox_client client; ++ struct work_struct vq_work; + int vq_id; + }; + +@@ -65,10 +79,14 @@ struct stm32_rproc { + struct reset_control *rst; + struct stm32_syscon hold_boot; + struct stm32_syscon pdds; ++ struct stm32_syscon copro_state; ++ int wdg_irq; + u32 nb_rmems; + struct stm32_rproc_mem *rmems; + struct stm32_mbox mb[MBOX_NB_MBX]; ++ struct workqueue_struct *workqueue; + bool secured_soc; ++ void __iomem *rsc_va; + }; + + static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) +@@ -91,6 +109,28 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) + return -EINVAL; + } + ++static int stm32_rproc_da_to_pa(struct rproc *rproc, u64 da, phys_addr_t *pa) ++{ ++ unsigned int i; ++ struct stm32_rproc *ddata = rproc->priv; ++ struct stm32_rproc_mem *p_mem; ++ ++ for (i = 0; i < ddata->nb_rmems; i++) { ++ p_mem = &ddata->rmems[i]; ++ ++ if (da < p_mem->dev_addr || ++ da >= p_mem->dev_addr + p_mem->size) ++ continue; ++ *pa = da - p_mem->dev_addr + p_mem->bus_addr; ++ dev_dbg(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa); ++ return 0; ++ } ++ ++ dev_err(rproc->dev.parent, "can't translate da %llx\n", da); ++ ++ return -EINVAL; ++} ++ + static int stm32_rproc_mem_alloc(struct rproc *rproc, + struct rproc_mem_entry *mem) + { +@@ -120,6 +160,15 @@ static int stm32_rproc_mem_release(struct rproc *rproc, + return 0; + } + ++static int stm32_rproc_elf_load_segments(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ if (!rproc->early_boot) ++ return rproc_elf_load_segments(rproc, fw); ++ ++ return 0; ++} ++ + static int stm32_rproc_of_memory_translations(struct rproc *rproc) + { + struct device *parent, *dev = rproc->dev.parent; +@@ -190,9 +239,34 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) + static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, + const struct firmware *fw) + { +- if (rproc_elf_load_rsc_table(rproc, fw)) +- dev_warn(&rproc->dev, "no resource table found for this firmware\n"); ++ struct resource_table *table = NULL; ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ if (!rproc->early_boot) { ++ if (rproc_elf_load_rsc_table(rproc, fw)) ++ goto no_rsc_table; ++ ++ return 0; ++ } ++ ++ if (ddata->rsc_va) { ++ table = (struct resource_table *)ddata->rsc_va; ++ /* Assuming that the resource table fits in 1kB is fair */ ++ rproc->cached_table = kmemdup(table, RSC_TBL_SIZE, GFP_KERNEL); ++ if (!rproc->cached_table) ++ return -ENOMEM; ++ ++ rproc->table_ptr = rproc->cached_table; ++ rproc->table_sz = RSC_TBL_SIZE; ++ return 0; ++ } ++ ++ rproc->cached_table = NULL; ++ rproc->table_ptr = NULL; ++ rproc->table_sz = 0; + ++no_rsc_table: ++ dev_warn(&rproc->dev, "no resource table found for this firmware\n"); + return 0; + } + +@@ -252,6 +326,36 @@ static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) + return stm32_rproc_elf_load_rsc_table(rproc, fw); + } + ++static struct resource_table * ++stm32_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ if (!rproc->early_boot) ++ return rproc_elf_find_loaded_rsc_table(rproc, fw); ++ ++ return (struct resource_table *)ddata->rsc_va; ++} ++ ++static int stm32_rproc_elf_sanity_check(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ if (!rproc->early_boot) ++ return rproc_elf_sanity_check(rproc, fw); ++ ++ return 0; ++} ++ ++static u32 stm32_rproc_elf_get_boot_addr(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ if (!rproc->early_boot) ++ return rproc_elf_get_boot_addr(rproc, fw); ++ ++ return 0; ++} ++ + static irqreturn_t stm32_rproc_wdg(int irq, void *data) + { + struct rproc *rproc = data; +@@ -261,13 +365,22 @@ static irqreturn_t stm32_rproc_wdg(int irq, void *data) + return IRQ_HANDLED; + } + ++static void stm32_rproc_mb_vq_work(struct work_struct *work) ++{ ++ struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work); ++ struct rproc *rproc = dev_get_drvdata(mb->client.dev); ++ ++ if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) ++ dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); ++} ++ + static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data) + { + struct rproc *rproc = dev_get_drvdata(cl->dev); + struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client); ++ struct stm32_rproc *ddata = rproc->priv; + +- if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) +- dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); ++ queue_work(ddata->workqueue, &mb->vq_work); + } + + static void stm32_rproc_free_mbox(struct rproc *rproc) +@@ -285,7 +398,7 @@ static void stm32_rproc_free_mbox(struct rproc *rproc) + static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { + { + .name = STM32_MBX_VQ0, +- .vq_id = 0, ++ .vq_id = STM32_MBX_VQ0_ID, + .client = { + .rx_callback = stm32_rproc_mb_callback, + .tx_block = false, +@@ -293,7 +406,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { + }, + { + .name = STM32_MBX_VQ1, +- .vq_id = 1, ++ .vq_id = STM32_MBX_VQ1_ID, + .client = { + .rx_callback = stm32_rproc_mb_callback, + .tx_block = false, +@@ -310,7 +423,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { + } + }; + +-static void stm32_rproc_request_mbox(struct rproc *rproc) ++static int stm32_rproc_request_mbox(struct rproc *rproc) + { + struct stm32_rproc *ddata = rproc->priv; + struct device *dev = &rproc->dev; +@@ -329,10 +442,18 @@ static void stm32_rproc_request_mbox(struct rproc *rproc) + + ddata->mb[i].chan = mbox_request_channel_byname(cl, name); + if (IS_ERR(ddata->mb[i].chan)) { ++ if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; + dev_warn(dev, "cannot get %s mbox\n", name); + ddata->mb[i].chan = NULL; + } ++ if (ddata->mb[i].vq_id >= 0) { ++ INIT_WORK(&ddata->mb[i].vq_work, ++ stm32_rproc_mb_vq_work); ++ } + } ++ ++ return 0; + } + + static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) +@@ -389,7 +510,7 @@ static int stm32_rproc_start(struct rproc *rproc) + stm32_rproc_add_coredump_trace(rproc); + + /* clear remote proc Deep Sleep */ +- if (ddata->pdds.map) { ++ if (ddata->pdds.map && !rproc->early_boot) { + err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, + ddata->pdds.mask, 0); + if (err) { +@@ -398,9 +519,15 @@ static int stm32_rproc_start(struct rproc *rproc) + } + } + +- err = stm32_rproc_set_hold_boot(rproc, false); +- if (err) +- return err; ++ /* ++ * If M4 previously started by bootloader, just guarantee holdboot ++ * is set to catch any crash. ++ */ ++ if (!rproc->early_boot) { ++ err = stm32_rproc_set_hold_boot(rproc, false); ++ if (err) ++ return err; ++ } + + return stm32_rproc_set_hold_boot(rproc, true); + } +@@ -442,6 +569,21 @@ static int stm32_rproc_stop(struct rproc *rproc) + } + } + ++ /* update copro state to OFF */ ++ if (ddata->copro_state.map) { ++ err = regmap_update_bits(ddata->copro_state.map, ++ ddata->copro_state.reg, ++ ddata->copro_state.mask, ++ COPRO_STATE_OFF); ++ if (err) { ++ dev_err(&rproc->dev, "failed to set copro state\n"); ++ return err; ++ } ++ } ++ ++ /* Reset early_boot state as we stop the co-processor */ ++ rproc->early_boot = false; ++ + return 0; + } + +@@ -471,11 +613,11 @@ static struct rproc_ops st_rproc_ops = { + .start = stm32_rproc_start, + .stop = stm32_rproc_stop, + .kick = stm32_rproc_kick, +- .load = rproc_elf_load_segments, ++ .load = stm32_rproc_elf_load_segments, + .parse_fw = stm32_rproc_parse_fw, +- .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, +- .sanity_check = rproc_elf_sanity_check, +- .get_boot_addr = rproc_elf_get_boot_addr, ++ .find_loaded_rsc_table = stm32_rproc_elf_find_loaded_rsc_table, ++ .sanity_check = stm32_rproc_elf_sanity_check, ++ .get_boot_addr = stm32_rproc_elf_get_boot_addr, + }; + + static const struct of_device_id stm32_rproc_match[] = { +@@ -512,8 +654,10 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) + struct device_node *np = dev->of_node; + struct rproc *rproc = platform_get_drvdata(pdev); + struct stm32_rproc *ddata = rproc->priv; +- struct stm32_syscon tz; +- unsigned int tzen; ++ struct stm32_syscon tz, rsctbl; ++ phys_addr_t rsc_pa; ++ u32 rsc_da; ++ unsigned int tzen, state; + int err, irq; + + irq = platform_get_irq(pdev, 0); +@@ -528,12 +672,21 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) + return err; + } + ++ ddata->wdg_irq = irq; ++ ++ if (of_property_read_bool(np, "wakeup-source")) { ++ device_init_wakeup(dev, true); ++ dev_pm_set_wake_irq(dev, irq); ++ } ++ + dev_info(dev, "wdg irq registered\n"); + } + + ddata->rst = devm_reset_control_get_by_index(dev, 0); + if (IS_ERR(ddata->rst)) { +- dev_err(dev, "failed to get mcu reset\n"); ++ if (PTR_ERR(ddata->rst) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get mcu reset\n"); ++ + return PTR_ERR(ddata->rst); + } + +@@ -564,11 +717,62 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) + + err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); + if (err) +- dev_warn(dev, "failed to get pdds\n"); ++ dev_warn(dev, "pdds not supported\n"); + + rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); + +- return stm32_rproc_of_memory_translations(rproc); ++ err = stm32_rproc_of_memory_translations(rproc); ++ if (err) ++ return err; ++ ++ /* check if the coprocessor has been started from the bootloader */ ++ err = stm32_rproc_get_syscon(np, "st,syscfg-copro-state", ++ &ddata->copro_state); ++ if (err) { ++ /* no copro_state syscon (optional) */ ++ dev_warn(dev, "copro_state not supported\n"); ++ goto bail; ++ } ++ ++ err = regmap_read(ddata->copro_state.map, ddata->copro_state.reg, ++ &state); ++ if (err) { ++ dev_err(&rproc->dev, "failed to read copro state\n"); ++ return err; ++ } ++ ++ if (state == COPRO_STATE_CRUN) { ++ rproc->early_boot = true; ++ ++ if (stm32_rproc_get_syscon(np, "st,syscfg-rsc-tbl", &rsctbl)) { ++ /* no rsc table syscon (optional) */ ++ dev_warn(dev, "rsc tbl syscon not supported\n"); ++ goto bail; ++ } ++ ++ err = regmap_read(rsctbl.map, rsctbl.reg, &rsc_da); ++ if (err) { ++ dev_err(&rproc->dev, "failed to read rsc tbl addr\n"); ++ return err; ++ } ++ if (!rsc_da) ++ /* no rsc table */ ++ goto bail; ++ ++ err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); ++ if (err) ++ return err; ++ ++ ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); ++ if (IS_ERR_OR_NULL(ddata->rsc_va)) { ++ dev_err(dev, "Unable to map memory region: %pa+%zx\n", ++ &rsc_pa, RSC_TBL_SIZE); ++ ddata->rsc_va = NULL; ++ return -ENOMEM; ++ } ++ } ++bail: ++ return 0; + } + + static int stm32_rproc_probe(struct platform_device *pdev) +@@ -589,14 +793,28 @@ static int stm32_rproc_probe(struct platform_device *pdev) + + rproc->has_iommu = false; + ddata = rproc->priv; ++ ddata->workqueue = create_workqueue(dev_name(dev)); ++ if (!ddata->workqueue) { ++ dev_err(dev, "cannot create workqueue\n"); ++ ret = -ENOMEM; ++ goto free_rproc; ++ } + + platform_set_drvdata(pdev, rproc); + + ret = stm32_rproc_parse_dt(pdev); + if (ret) +- goto free_rproc; ++ goto free_wkq; + +- stm32_rproc_request_mbox(rproc); ++ if (!rproc->early_boot) { ++ ret = stm32_rproc_stop(rproc); ++ if (ret) ++ goto free_wkq; ++ } ++ ++ ret = stm32_rproc_request_mbox(rproc); ++ if (ret) ++ goto free_wkq; + + ret = rproc_add(rproc); + if (ret) +@@ -606,7 +824,13 @@ static int stm32_rproc_probe(struct platform_device *pdev) + + free_mb: + stm32_rproc_free_mbox(rproc); ++free_wkq: ++ destroy_workqueue(ddata->workqueue); + free_rproc: ++ if (device_may_wakeup(dev)) { ++ dev_pm_clear_wake_irq(dev); ++ device_init_wakeup(dev, false); ++ } + rproc_free(rproc); + return ret; + } +@@ -614,22 +838,68 @@ static int stm32_rproc_probe(struct platform_device *pdev) + static int stm32_rproc_remove(struct platform_device *pdev) + { + struct rproc *rproc = platform_get_drvdata(pdev); ++ struct stm32_rproc *ddata = rproc->priv; ++ struct device *dev = &pdev->dev; + + if (atomic_read(&rproc->power) > 0) + rproc_shutdown(rproc); + + rproc_del(rproc); + stm32_rproc_free_mbox(rproc); ++ destroy_workqueue(ddata->workqueue); ++ ++ if (device_may_wakeup(dev)) { ++ dev_pm_clear_wake_irq(dev); ++ device_init_wakeup(dev, false); ++ } + rproc_free(rproc); + + return 0; + } + ++static void stm32_rproc_shutdown(struct platform_device *pdev) ++{ ++ struct rproc *rproc = platform_get_drvdata(pdev); ++ ++ if (atomic_read(&rproc->power) > 0) ++ dev_warn(&pdev->dev, ++ "Warning: remote fw is still running with possible side effect!!!\n"); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int stm32_rproc_suspend(struct device *dev) ++{ ++ struct rproc *rproc = dev_get_drvdata(dev); ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ if (device_may_wakeup(dev)) ++ return enable_irq_wake(ddata->wdg_irq); ++ ++ return 0; ++} ++ ++static int stm32_rproc_resume(struct device *dev) ++{ ++ struct rproc *rproc = dev_get_drvdata(dev); ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ if (device_may_wakeup(dev)) ++ return disable_irq_wake(ddata->wdg_irq); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, ++ stm32_rproc_suspend, stm32_rproc_resume); ++ + static struct platform_driver stm32_rproc_driver = { + .probe = stm32_rproc_probe, + .remove = stm32_rproc_remove, ++ .shutdown = stm32_rproc_shutdown, + .driver = { + .name = "stm32-rproc", ++ .pm = &stm32_rproc_pm_ops, + .of_match_table = of_match_ptr(stm32_rproc_match), + }, + }; +diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig +index d0322b41e..88759a4c9 100644 +--- a/drivers/rpmsg/Kconfig ++++ b/drivers/rpmsg/Kconfig +@@ -55,4 +55,13 @@ config RPMSG_VIRTIO + select RPMSG + select VIRTIO + ++config RPMSG_TTY ++ tristate "RPMSG tty driver" ++ depends on RPMSG ++ help ++ Say y here to export rpmsg endpoints as tty console, usually found ++ in /dev/ttyRPMSG. ++ This makes it possible for user-space programs to send and receive ++ rpmsg messages as a standard tty protocol. ++ + endmenu +diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile +index 9aa859502..107145c63 100644 +--- a/drivers/rpmsg/Makefile ++++ b/drivers/rpmsg/Makefile +@@ -5,4 +5,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o + obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o + obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o + obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o ++obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o + obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o +diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c +index e330ec4df..48f24503f 100644 +--- a/drivers/rpmsg/rpmsg_core.c ++++ b/drivers/rpmsg/rpmsg_core.c +@@ -283,6 +283,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, + } + EXPORT_SYMBOL(rpmsg_trysend_offchannel); + ++/** ++ * rpmsg_get_buffer_size() ++ * This function returns buffer size available for sending messages. ++ * ++ * @ept: the rpmsg endpoint ++ * ++ * Returns buffer size on success and an appropriate error value on failure. ++ */ ++int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) ++{ ++ if (WARN_ON(!ept)) ++ return -EINVAL; ++ if (!ept->ops->get_buffer_size) ++ return -ENXIO; ++ ++ return ept->ops->get_buffer_size(ept); ++} ++EXPORT_SYMBOL(rpmsg_get_buffer_size); ++ + /* + * match an rpmsg channel with a channel info struct. + * this is used to make sure we're not creating rpmsg devices for channels +diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h +index 3fc83cd50..244292540 100644 +--- a/drivers/rpmsg/rpmsg_internal.h ++++ b/drivers/rpmsg/rpmsg_internal.h +@@ -47,6 +47,7 @@ struct rpmsg_device_ops { + * @trysendto: see @rpmsg_trysendto(), optional + * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional + * @poll: see @rpmsg_poll(), optional ++ * @get_buffer_size: see @rpmsg_get_buffer_size(), optional + * + * Indirection table for the operations that a rpmsg backend should implement. + * In addition to @destroy_ept, the backend must at least implement @send and +@@ -66,6 +67,7 @@ struct rpmsg_endpoint_ops { + void *data, int len); + __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, + poll_table *wait); ++ int (*get_buffer_size)(struct rpmsg_endpoint *ept); + }; + + int rpmsg_register_device(struct rpmsg_device *rpdev); +diff --git a/drivers/rpmsg/rpmsg_tty.c b/drivers/rpmsg/rpmsg_tty.c +new file mode 100644 +index 000000000..57763898e +--- /dev/null ++++ b/drivers/rpmsg/rpmsg_tty.c +@@ -0,0 +1,310 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Arnaud Pouliquen for STMicroelectronics. ++ * Derived from the imx-rmpsg and omap-rpmsg implementations. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_TTY_RPMSG_INDEX 32 /* Should be enough for a while */ ++ ++static LIST_HEAD(rpmsg_tty_list); /* tty instances list */ ++static DEFINE_MUTEX(rpmsg_tty_lock); /* protect tty list */ ++ ++static struct tty_driver *rpmsg_tty_driver; ++static struct tty_port_operations rpmsg_tty_port_ops = { }; ++ ++struct rpmsg_tty_port { ++ struct tty_port port; /* TTY port data */ ++ struct list_head list; /* TTY device list */ ++ u32 id; /* tty rpmsg index */ ++ spinlock_t rx_lock; /* message reception lock */ ++ struct rpmsg_device *rpdev; /* handle rpmsg device */ ++}; ++ ++static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, ++ void *priv, u32 src) ++{ ++ int space; ++ unsigned char *cbuf; ++ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); ++ ++ /* Flush the recv-ed none-zero data to tty node */ ++ if (len == 0) ++ return -EINVAL; ++ ++ dev_dbg(&rpdev->dev, "msg(<- src 0x%x) len %d\n", src, len); ++ ++ print_hex_dump_debug(__func__, DUMP_PREFIX_NONE, 16, 1, data, len, ++ true); ++ ++ spin_lock(&cport->rx_lock); ++ space = tty_prepare_flip_string(&cport->port, &cbuf, len); ++ if (space <= 0) { ++ dev_err(&rpdev->dev, "No memory for tty_prepare_flip_string\n"); ++ spin_unlock(&cport->rx_lock); ++ return -ENOMEM; ++ } ++ ++ if (space != len) ++ dev_warn(&rpdev->dev, "Trunc buffer from %d to %d\n", ++ len, space); ++ ++ memcpy(cbuf, data, space); ++ tty_flip_buffer_push(&cport->port); ++ spin_unlock(&cport->rx_lock); ++ ++ return 0; ++} ++ ++static struct rpmsg_tty_port *rpmsg_tty_get(unsigned int index) ++{ ++ struct rpmsg_tty_port *cport; ++ ++ mutex_lock(&rpmsg_tty_lock); ++ list_for_each_entry(cport, &rpmsg_tty_list, list) { ++ if (index == cport->id) { ++ mutex_unlock(&rpmsg_tty_lock); ++ return cport; ++ } ++ } ++ mutex_unlock(&rpmsg_tty_lock); ++ ++ return NULL; ++} ++ ++static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty) ++{ ++ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); ++ ++ if (!cport) ++ return -ENODEV; ++ ++ return tty_port_install(&cport->port, driver, tty); ++} ++ ++static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp) ++{ ++ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); ++ ++ if (!cport) ++ return -ENODEV; ++ ++ return tty_port_open(tty->port, tty, filp); ++} ++ ++static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp) ++{ ++ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); ++ ++ if (!cport) ++ return; ++ return tty_port_close(tty->port, tty, filp); ++} ++ ++static int rpmsg_tty_write(struct tty_struct *tty, const unsigned char *buf, ++ int total) ++{ ++ int count, ret = 0; ++ const unsigned char *tbuf; ++ struct rpmsg_tty_port *cport = container_of(tty->port, ++ struct rpmsg_tty_port, port); ++ struct rpmsg_device *rpdev = cport->rpdev; ++ int msg_size; ++ ++ dev_dbg(&rpdev->dev, "%s: send message from tty->index = %d\n", ++ __func__, tty->index); ++ ++ if (!buf) { ++ dev_err(&rpdev->dev, "buf shouldn't be null.\n"); ++ return -ENOMEM; ++ } ++ ++ msg_size = rpmsg_get_buffer_size(rpdev->ept); ++ if (msg_size < 0) ++ return msg_size; ++ ++ count = total; ++ tbuf = buf; ++ do { ++ /* send a message to our remote processor */ ++ ret = rpmsg_trysend(rpdev->ept, (void *)tbuf, ++ count > msg_size ? msg_size : count); ++ if (ret) { ++ dev_dbg(&rpdev->dev, "rpmsg_send failed: %d\n", ret); ++ return 0; ++ } ++ ++ if (count > msg_size) { ++ count -= msg_size; ++ tbuf += msg_size; ++ } else { ++ count = 0; ++ } ++ } while (count > 0); ++ ++ return total; ++} ++ ++static int rpmsg_tty_write_room(struct tty_struct *tty) ++{ ++ struct rpmsg_tty_port *cport = container_of(tty->port, ++ struct rpmsg_tty_port, port); ++ struct rpmsg_device *rpdev = cport->rpdev; ++ ++ /* report the space in the rpmsg buffer */ ++ return rpmsg_get_buffer_size(rpdev->ept); ++} ++ ++static const struct tty_operations rpmsg_tty_ops = { ++ .install = rpmsg_tty_install, ++ .open = rpmsg_tty_open, ++ .close = rpmsg_tty_close, ++ .write = rpmsg_tty_write, ++ .write_room = rpmsg_tty_write_room, ++}; ++ ++static int rpmsg_tty_probe(struct rpmsg_device *rpdev) ++{ ++ struct rpmsg_tty_port *cport, *tmp; ++ unsigned int index; ++ struct device *tty_dev; ++ ++ cport = devm_kzalloc(&rpdev->dev, sizeof(*cport), GFP_KERNEL); ++ if (!cport) ++ return -ENOMEM; ++ ++ tty_port_init(&cport->port); ++ cport->port.ops = &rpmsg_tty_port_ops; ++ spin_lock_init(&cport->rx_lock); ++ ++ cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY; ++ ++ cport->rpdev = rpdev; ++ ++ /* get free index */ ++ mutex_lock(&rpmsg_tty_lock); ++ for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) { ++ bool id_found = false; ++ ++ list_for_each_entry(tmp, &rpmsg_tty_list, list) { ++ if (index == tmp->id) { ++ id_found = true; ++ break; ++ } ++ } ++ if (!id_found) ++ break; ++ } ++ ++ tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, ++ index, &rpdev->dev); ++ if (IS_ERR(tty_dev)) { ++ dev_err(&rpdev->dev, "failed to register tty port\n"); ++ tty_port_destroy(&cport->port); ++ mutex_unlock(&rpmsg_tty_lock); ++ return PTR_ERR(tty_dev); ++ } ++ ++ cport->id = index; ++ list_add_tail(&cport->list, &rpmsg_tty_list); ++ mutex_unlock(&rpmsg_tty_lock); ++ dev_set_drvdata(&rpdev->dev, cport); ++ ++ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x : ttyRPMSG%d\n", ++ rpdev->src, rpdev->dst, index); ++ ++ return 0; ++} ++ ++static void rpmsg_tty_remove(struct rpmsg_device *rpdev) ++{ ++ struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); ++ ++ /* User hang up to release the tty */ ++ if (tty_port_initialized(&cport->port)) ++ tty_port_tty_hangup(&cport->port, false); ++ tty_port_destroy(&cport->port); ++ tty_unregister_device(rpmsg_tty_driver, cport->id); ++ list_del(&cport->list); ++ ++ dev_info(&rpdev->dev, "rpmsg tty device %d is removed\n", cport->id); ++} ++ ++static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = { ++ { .name = "rpmsg-tty-channel" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table); ++ ++static struct rpmsg_driver rpmsg_tty_rmpsg_drv = { ++ .drv.name = KBUILD_MODNAME, ++ .drv.owner = THIS_MODULE, ++ .id_table = rpmsg_driver_tty_id_table, ++ .probe = rpmsg_tty_probe, ++ .callback = rpmsg_tty_cb, ++ .remove = rpmsg_tty_remove, ++}; ++ ++static int __init rpmsg_tty_init(void) ++{ ++ int err; ++ ++ rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG_INDEX, 0); ++ if (IS_ERR(rpmsg_tty_driver)) ++ return PTR_ERR(rpmsg_tty_driver); ++ ++ rpmsg_tty_driver->driver_name = "rpmsg_tty"; ++ rpmsg_tty_driver->name = "ttyRPMSG"; ++ rpmsg_tty_driver->major = TTYAUX_MAJOR; ++ rpmsg_tty_driver->minor_start = 3; ++ rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE; ++ rpmsg_tty_driver->init_termios = tty_std_termios; ++ rpmsg_tty_driver->flags = TTY_DRIVER_REAL_RAW | ++ TTY_DRIVER_DYNAMIC_DEV; ++ ++ tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); ++ ++ /* Disable unused mode by default */ ++ rpmsg_tty_driver->init_termios = tty_std_termios; ++ rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON); ++ rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR); ++ ++ err = tty_register_driver(rpmsg_tty_driver); ++ if (err < 0) { ++ pr_err("Couldn't install rpmsg tty driver: err %d\n", err); ++ goto tty_error; ++ } ++ err = register_rpmsg_driver(&rpmsg_tty_rmpsg_drv); ++ ++ if (!err) ++ return 0; ++ ++ tty_unregister_driver(rpmsg_tty_driver); ++ ++tty_error: ++ put_tty_driver(rpmsg_tty_driver); ++ ++ return err; ++} ++ ++static void __exit rpmsg_tty_exit(void) ++{ ++ unregister_rpmsg_driver(&rpmsg_tty_rmpsg_drv); ++ tty_unregister_driver(rpmsg_tty_driver); ++ put_tty_driver(rpmsg_tty_driver); ++} ++ ++module_init(rpmsg_tty_init); ++module_exit(rpmsg_tty_exit); ++ ++MODULE_AUTHOR("Arnaud Pouliquen "); ++MODULE_DESCRIPTION("virtio remote processor messaging tty driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c +index 376ebbf88..31b6d053f 100644 +--- a/drivers/rpmsg/virtio_rpmsg_bus.c ++++ b/drivers/rpmsg/virtio_rpmsg_bus.c +@@ -175,6 +175,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, + int len, u32 dst); + static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, + u32 dst, void *data, int len); ++static int virtio_get_buffer_size(struct rpmsg_endpoint *ept); + + static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { + .destroy_ept = virtio_rpmsg_destroy_ept, +@@ -184,6 +185,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { + .trysend = virtio_rpmsg_trysend, + .trysendto = virtio_rpmsg_trysendto, + .trysend_offchannel = virtio_rpmsg_trysend_offchannel, ++ .get_buffer_size = virtio_get_buffer_size, + }; + + /** +@@ -699,6 +701,15 @@ static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); + } + ++static int virtio_get_buffer_size(struct rpmsg_endpoint *ept) ++{ ++ struct rpmsg_device *rpdev = ept->rpdev; ++ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); ++ struct virtproc_info *vrp = vch->vrp; ++ ++ return vrp->buf_size - sizeof(struct rpmsg_hdr); ++} ++ + static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, + struct rpmsg_hdr *msg, unsigned int len) + { +diff --git a/include/linux/mailbox/arm-smccc-mbox.h b/include/linux/mailbox/arm-smccc-mbox.h +new file mode 100644 +index 000000000..d35fb89a7 +--- /dev/null ++++ b/include/linux/mailbox/arm-smccc-mbox.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef _LINUX_ARM_SMCCC_MBOX_H_ ++#define _LINUX_ARM_SMCCC_MBOX_H_ ++ ++#include ++ ++/** ++ * struct arm_smccc_mbox_cmd - ARM SMCCC message structure ++ * @args_smccc32/64: actual usage of registers is up to the protocol ++ * (within the SMCCC limits) ++ */ ++struct arm_smccc_mbox_cmd { ++ union { ++ u32 args_smccc32[6]; ++ u64 args_smccc64[6]; ++ }; ++}; ++ ++#endif /* _LINUX_ARM_SMCCC_MBOX_H_ */ +diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h +index 16ad66683..221f98b73 100644 +--- a/include/linux/remoteproc.h ++++ b/include/linux/remoteproc.h +@@ -481,6 +481,7 @@ struct rproc_dump_segment { + * @auto_boot: flag to indicate if remote processor should be auto-started + * @dump_segments: list of segments in the firmware + * @nb_vdev: number of vdev currently handled by rproc ++ * @early_boot: remote processor has been booted before kernel boot + */ + struct rproc { + struct list_head node; +@@ -514,6 +515,7 @@ struct rproc { + bool auto_boot; + struct list_head dump_segments; + int nb_vdev; ++ bool early_boot; + }; + + /** +diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h +index 9fe156d1c..2af767403 100644 +--- a/include/linux/rpmsg.h ++++ b/include/linux/rpmsg.h +@@ -135,6 +135,7 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, + __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, + poll_table *wait); + ++int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept); + #else + + static inline int register_rpmsg_device(struct rpmsg_device *dev) +@@ -242,6 +243,14 @@ static inline __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, + return 0; + } + ++static int rpmsg_get_buffer_size(struct rpmsg_endpoint *ept) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return -ENXIO; ++} ++ + #endif /* IS_ENABLED(CONFIG_RPMSG) */ + + /* use a macro to avoid include chaining to get THIS_MODULE */ +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch new file mode 100644 index 0000000..858673c --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch @@ -0,0 +1,471 @@ +From 835fe45ed0a3c0ef8cb2b74a900d227a124b4761 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:44:22 +0200 +Subject: [PATCH 11/23] ARM-stm32mp1-r1-RESET-RTC-WATCHDOG + +--- + drivers/reset/reset-stm32mp1.c | 83 +++++++++++------ + drivers/rtc/Kconfig | 1 + + drivers/rtc/rtc-stm32.c | 159 +++++++++++++++++++++++++++------ + drivers/watchdog/stm32_iwdg.c | 6 +- + 4 files changed, 192 insertions(+), 57 deletions(-) + +diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c +index b221a2804..daf0e26b2 100644 +--- a/drivers/reset/reset-stm32mp1.c ++++ b/drivers/reset/reset-stm32mp1.c +@@ -4,14 +4,21 @@ + * Author: Gabriel Fernandez for STMicroelectronics. + */ + ++#include ++#include + #include + #include + #include ++#include + #include ++#include + #include + #include ++#include + +-#define CLR_OFFSET 0x4 ++#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) ++ ++#define CLR_OFFSET 0x4 + + struct stm32_reset_data { + struct reset_controller_dev rcdev; +@@ -79,37 +86,57 @@ static const struct of_device_id stm32_reset_dt_ids[] = { + { /* sentinel */ }, + }; + +-static int stm32_reset_probe(struct platform_device *pdev) ++static void __init stm32mp1_reset_init(struct device_node *np) + { +- struct device *dev = &pdev->dev; +- struct stm32_reset_data *data; +- void __iomem *membase; +- struct resource *res; +- +- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ void __iomem *base; ++ const struct of_device_id *match; ++ struct stm32_reset_data *data = NULL; ++ int ret; ++ ++ base = of_iomap(np, 0); ++ if (!base) { ++ pr_err("%pOFn: unable to map resource", np); ++ of_node_put(np); ++ return; ++ } ++ ++ match = of_match_node(stm32_reset_dt_ids, np); ++ if (!match) { ++ pr_err("%s: match data not found\n", __func__); ++ goto err; ++ } ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) +- return -ENOMEM; +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- membase = devm_ioremap_resource(dev, res); +- if (IS_ERR(membase)) +- return PTR_ERR(membase); ++ goto err; + +- data->membase = membase; ++ data->membase = base; + data->rcdev.owner = THIS_MODULE; +- data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; + data->rcdev.ops = &stm32_reset_ops; +- data->rcdev.of_node = dev->of_node; +- +- return devm_reset_controller_register(dev, &data->rcdev); ++ data->rcdev.of_node = np; ++ data->rcdev.nr_resets = STM32MP1_RESET_ID_MASK; ++ ++ ret = reset_controller_register(&data->rcdev); ++ if (!ret) ++ return; ++ ++err: ++ pr_err("stm32mp1 reset failed to initialize\n"); ++ if (data) ++ kfree(data); ++ if (base) ++ iounmap(base); ++ of_node_put(np); + } + +-static struct platform_driver stm32_reset_driver = { +- .probe = stm32_reset_probe, +- .driver = { +- .name = "stm32mp1-reset", +- .of_match_table = stm32_reset_dt_ids, +- }, +-}; +- +-builtin_platform_driver(stm32_reset_driver); ++/* ++ * RCC reset and clock drivers bind to the same RCC node. ++ * Register RCC reset driver at init through clock of table, ++ * clock driver for RCC will register at probe time. ++ */ ++static void __init stm32mp1_reset_of_init_drv(struct device_node *np) ++{ ++ of_node_clear_flag(np, OF_POPULATED); ++ stm32mp1_reset_init(np); ++} ++OF_DECLARE_1(clk, stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_reset_of_init_drv); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index c5b980414..d590b4205 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1862,6 +1862,7 @@ config RTC_DRV_R7301 + config RTC_DRV_STM32 + tristate "STM32 RTC" + select REGMAP_MMIO ++ depends on COMMON_CLK + depends on ARCH_STM32 || COMPILE_TEST + help + If you say yes here you get support for the STM32 On-Chip +diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c +index 2999e33a7..5bfe655c5 100644 +--- a/drivers/rtc/rtc-stm32.c ++++ b/drivers/rtc/rtc-stm32.c +@@ -6,6 +6,8 @@ + + #include + #include ++#include ++#include + #include + #include + #include +@@ -15,6 +17,8 @@ + #include + #include + ++#include ++ + #define DRIVER_NAME "stm32_rtc" + + /* STM32_RTC_TR bit fields */ +@@ -39,6 +43,12 @@ + #define STM32_RTC_CR_FMT BIT(6) + #define STM32_RTC_CR_ALRAE BIT(8) + #define STM32_RTC_CR_ALRAIE BIT(12) ++#define STM32_RTC_CR_COSEL BIT(19) ++#define STM32_RTC_CR_OSEL_SHIFT 21 ++#define STM32_RTC_CR_OSEL GENMASK(22, 21) ++#define STM32_RTC_CR_COE BIT(23) ++#define STM32_RTC_CR_TAMPOE BIT(26) ++#define STM32_RTC_CR_OUT2EN BIT(31) + + /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ + #define STM32_RTC_ISR_ALRAWF BIT(0) +@@ -75,6 +85,11 @@ + /* STM32_RTC_SR/_SCR bit fields */ + #define STM32_RTC_SR_ALRA BIT(0) + ++/* STM32_RTC_CFGR bit fields */ ++#define STM32_RTC_CFGR_OUT2_RMP BIT(0) ++#define STM32_RTC_CFGR_LSCOEN_OUT1 1 ++#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2 ++ + /* STM32_RTC_VERR bit fields */ + #define STM32_RTC_VERR_MINREV_SHIFT 0 + #define STM32_RTC_VERR_MINREV GENMASK(3, 0) +@@ -101,6 +116,7 @@ struct stm32_rtc_registers { + u16 wpr; + u16 sr; + u16 scr; ++ u16 cfgr; + u16 verr; + }; + +@@ -114,7 +130,7 @@ struct stm32_rtc_data { + void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); + bool has_pclk; + bool need_dbp; +- bool has_wakeirq; ++ bool has_lsco; + }; + + struct stm32_rtc { +@@ -127,9 +143,87 @@ struct stm32_rtc { + struct clk *rtc_ck; + const struct stm32_rtc_data *data; + int irq_alarm; +- int wakeirq_alarm; ++ int lsco; ++ struct clk *clk_lsco; + }; + ++/* ++ * ------------------------------------------------------------------------- ++ * | TAMPOE | OSEL[1:0] | COE | OUT2EN | RTC_OUT1 | RTC_OUT2 | ++ * | | | | | | or RTC_OUT2_RMP | ++ * |-------------------------------------------------------------------------| ++ * | 0 | 00 | 0 | 0 or 1 | - | - | ++ * |--------|-----------|-----|--------|------------------|------------------| ++ * | 0 | 00 | 1 | 0 | CALIB | - | ++ * |--------|-----------|-----|--------|------------------|------------------| ++ * | 0 or 1 | !=00 | 0 | 0 | TAMPALRM | - | ++ * |--------|-----------|-----|--------|------------------|------------------| ++ * | 0 | 00 | 1 | 1 | - | CALIB | ++ * |--------|-----------|-----|--------|------------------|------------------| ++ * | 0 or 1 | !=00 | 0 | 1 | - | TAMPALRM | ++ * |--------|-----------|-----|--------|------------------|------------------| ++ * | 0 or 1 | !=00 | 1 | 1 | TAMPALRM | CALIB | ++ * ------------------------------------------------------------------------- ++ */ ++static int stm32_rtc_clk_lsco_check_availability(struct stm32_rtc *rtc) ++{ ++ struct stm32_rtc_registers regs = rtc->data->regs; ++ unsigned int cr = readl_relaxed(rtc->base + regs.cr); ++ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr); ++ unsigned int calib = STM32_RTC_CR_COE; ++ unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL; ++ ++ switch (rtc->lsco) { ++ case RTC_OUT1: ++ if ((!(cr & STM32_RTC_CR_OUT2EN) && ++ ((cr & calib) || cr & tampalrm)) || ++ ((cr & calib) && (cr & tampalrm))) ++ return -EBUSY; ++ break; ++ case RTC_OUT2_RMP: ++ if ((cr & STM32_RTC_CR_OUT2EN) && ++ (cfgr & STM32_RTC_CFGR_OUT2_RMP) && ++ ((cr & calib) || (cr & tampalrm))) ++ return -EBUSY; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (clk_get_rate(rtc->rtc_ck) != 32768) ++ return -ERANGE; ++ ++ return 0; ++} ++ ++static int stm32_rtc_clk_lsco_register(struct platform_device *pdev) ++{ ++ struct stm32_rtc *rtc = platform_get_drvdata(pdev); ++ struct stm32_rtc_registers regs = rtc->data->regs; ++ u8 lscoen; ++ int ret; ++ ++ ret = stm32_rtc_clk_lsco_check_availability(rtc); ++ if (ret) ++ return ret; ++ ++ lscoen = (rtc->lsco == RTC_OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : ++ STM32_RTC_CFGR_LSCOEN_OUT2_RMP; ++ ++ rtc->clk_lsco = clk_register_gate(&pdev->dev, "rtc_lsco", ++ __clk_get_name(rtc->rtc_ck), ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, ++ rtc->base + regs.cfgr, lscoen, ++ 0, NULL); ++ if (IS_ERR(rtc->clk_lsco)) ++ return PTR_ERR(rtc->clk_lsco); ++ ++ of_clk_add_provider(pdev->dev.of_node, ++ of_clk_src_simple_get, rtc->clk_lsco); ++ ++ return 0; ++} ++ + static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) + { + const struct stm32_rtc_registers *regs = &rtc->data->regs; +@@ -547,7 +641,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, + static const struct stm32_rtc_data stm32_rtc_data = { + .has_pclk = false, + .need_dbp = true, +- .has_wakeirq = false, ++ .has_lsco = false, + .regs = { + .tr = 0x00, + .dr = 0x04, +@@ -558,6 +652,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { + .wpr = 0x24, + .sr = 0x0C, /* set to ISR offset to ease alarm management */ + .scr = UNDEF_REG, ++ .cfgr = UNDEF_REG, + .verr = UNDEF_REG, + }, + .events = { +@@ -569,7 +664,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { + static const struct stm32_rtc_data stm32h7_rtc_data = { + .has_pclk = true, + .need_dbp = true, +- .has_wakeirq = false, ++ .has_lsco = false, + .regs = { + .tr = 0x00, + .dr = 0x04, +@@ -580,6 +675,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { + .wpr = 0x24, + .sr = 0x0C, /* set to ISR offset to ease alarm management */ + .scr = UNDEF_REG, ++ .cfgr = UNDEF_REG, + .verr = UNDEF_REG, + }, + .events = { +@@ -600,7 +696,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, + static const struct stm32_rtc_data stm32mp1_data = { + .has_pclk = true, + .need_dbp = false, +- .has_wakeirq = true, ++ .has_lsco = true, + .regs = { + .tr = 0x00, + .dr = 0x04, +@@ -611,6 +707,7 @@ static const struct stm32_rtc_data stm32mp1_data = { + .wpr = 0x24, + .sr = 0x50, + .scr = 0x5C, ++ .cfgr = 0x60, + .verr = 0x3F4, + }, + .events = { +@@ -738,13 +835,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) + } else { + rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(rtc->pclk)) { +- dev_err(&pdev->dev, "no pclk clock"); ++ if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "no pclk clock"); + return PTR_ERR(rtc->pclk); + } + rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); + } + if (IS_ERR(rtc->rtc_ck)) { +- dev_err(&pdev->dev, "no rtc_ck clock"); ++ if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "no rtc_ck clock"); + return PTR_ERR(rtc->rtc_ck); + } + +@@ -781,19 +880,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) + } + + ret = device_init_wakeup(&pdev->dev, true); +- if (rtc->data->has_wakeirq) { +- rtc->wakeirq_alarm = platform_get_irq(pdev, 1); +- if (rtc->wakeirq_alarm > 0) { +- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, +- rtc->wakeirq_alarm); +- } else { +- ret = rtc->wakeirq_alarm; +- if (rtc->wakeirq_alarm == -EPROBE_DEFER) +- goto err; +- } +- } + if (ret) +- dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret); ++ goto err; ++ ++ ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm); ++ if (ret) ++ goto err; + + platform_set_drvdata(pdev, rtc); + +@@ -816,6 +908,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) + goto err; + } + ++ if (rtc->data->has_lsco) { ++ ret = of_property_read_s32(pdev->dev.of_node, ++ "st,lsco", &rtc->lsco); ++ if (!ret) { ++ ret = stm32_rtc_clk_lsco_register(pdev); ++ if (ret) ++ dev_warn(&pdev->dev, ++ "LSCO clock registration failed: %d\n", ++ ret); ++ } else { ++ rtc->lsco = ret; ++ dev_dbg(&pdev->dev, "No LSCO clock: %d\n", ret); ++ } ++ } ++ + /* + * If INITS flag is reset (calendar year field set to 0x00), calendar + * must be initialized +@@ -852,6 +959,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) + const struct stm32_rtc_registers *regs = &rtc->data->regs; + unsigned int cr; + ++ if (!IS_ERR_OR_NULL(rtc->clk_lsco)) ++ clk_unregister_gate(rtc->clk_lsco); ++ + /* Disable interrupts */ + stm32_rtc_wpr_unlock(rtc); + cr = readl_relaxed(rtc->base + regs->cr); +@@ -881,9 +991,6 @@ static int stm32_rtc_suspend(struct device *dev) + if (rtc->data->has_pclk) + clk_disable_unprepare(rtc->pclk); + +- if (device_may_wakeup(dev)) +- return enable_irq_wake(rtc->irq_alarm); +- + return 0; + } + +@@ -902,15 +1009,13 @@ static int stm32_rtc_resume(struct device *dev) + if (ret < 0) + return ret; + +- if (device_may_wakeup(dev)) +- return disable_irq_wake(rtc->irq_alarm); +- + return ret; + } + #endif + +-static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, +- stm32_rtc_suspend, stm32_rtc_resume); ++static const struct dev_pm_ops stm32_rtc_pm_ops = { ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) ++}; + + static struct platform_driver stm32_rtc_driver = { + .probe = stm32_rtc_probe, +diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c +index 25188d6bb..1b71c205c 100644 +--- a/drivers/watchdog/stm32_iwdg.c ++++ b/drivers/watchdog/stm32_iwdg.c +@@ -163,7 +163,8 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, + + wdt->clk_lsi = devm_clk_get(dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { +- dev_err(dev, "Unable to get lsi clock\n"); ++ if (PTR_ERR(wdt->clk_lsi) != -EPROBE_DEFER) ++ dev_err(dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + +@@ -171,7 +172,8 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, + if (wdt->data->has_pclk) { + wdt->clk_pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { +- dev_err(dev, "Unable to get pclk clock\n"); ++ if (PTR_ERR(wdt->clk_pclk) != -EPROBE_DEFER) ++ dev_err(dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch new file mode 100644 index 0000000..109f19f --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch @@ -0,0 +1,1556 @@ +From 3da66d9a5ce2cb975d8ee48f47d497de85d79ccc Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:44:58 +0200 +Subject: [PATCH 12/23] ARM-stm32mp1-r1-MEDIA-SOC-THERMAL + +--- + drivers/media/i2c/ov5640.c | 77 +++-- + drivers/media/platform/stm32/stm32-cec.c | 10 +- + drivers/media/platform/stm32/stm32-dcmi.c | 51 ++- + drivers/media/v4l2-core/v4l2-fwnode.c | 3 + + drivers/soc/Kconfig | 1 + + drivers/soc/Makefile | 1 + + drivers/soc/st/Kconfig | 17 + + drivers/soc/st/Makefile | 2 + + drivers/soc/st/stm32_hdp.c | 242 ++++++++++++++ + drivers/soc/st/stm32_pm_domain.c | 212 ++++++++++++ + drivers/thermal/st/stm_thermal.c | 383 +++++++--------------- + include/media/v4l2-fwnode.h | 2 + + 12 files changed, 699 insertions(+), 302 deletions(-) + create mode 100644 drivers/soc/st/Kconfig + create mode 100644 drivers/soc/st/Makefile + create mode 100644 drivers/soc/st/stm32_hdp.c + create mode 100644 drivers/soc/st/stm32_pm_domain.c + +diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c +index a398ea81e..3bee8eed7 100644 +--- a/drivers/media/i2c/ov5640.c ++++ b/drivers/media/i2c/ov5640.c +@@ -63,6 +63,7 @@ + #define OV5640_REG_TIMING_VTS 0x380e + #define OV5640_REG_TIMING_TC_REG20 0x3820 + #define OV5640_REG_TIMING_TC_REG21 0x3821 ++#define OV5640_REG_DVP_PCLK_DIVIDER 0x3824 + #define OV5640_REG_AEC_CTRL00 0x3a00 + #define OV5640_REG_AEC_B50_STEP 0x3a08 + #define OV5640_REG_AEC_B60_STEP 0x3a0a +@@ -214,6 +215,7 @@ struct ov5640_ctrls { + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *link_freq; + }; + + struct ov5640_dev { +@@ -370,8 +372,8 @@ static const struct reg_value ov5640_setting_VGA_640_480[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_XGA_1024_768[] = { +@@ -389,8 +391,7 @@ static const struct reg_value ov5640_setting_XGA_1024_768[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_QVGA_320_240[] = { +@@ -408,8 +409,7 @@ static const struct reg_value ov5640_setting_QVGA_320_240[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_QCIF_176_144[] = { +@@ -427,8 +427,7 @@ static const struct reg_value ov5640_setting_QCIF_176_144[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_NTSC_720_480[] = { +@@ -446,8 +445,7 @@ static const struct reg_value ov5640_setting_NTSC_720_480[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_PAL_720_576[] = { +@@ -465,8 +463,7 @@ static const struct reg_value ov5640_setting_PAL_720_576[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_720P_1280_720[] = { +@@ -484,8 +481,7 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = { + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, +- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + + static const struct reg_value ov5640_setting_1080P_1920_1080[] = { +@@ -504,8 +500,8 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, ++ {0x4407, 0x04, 0, 0}, ++ {0x5001, 0x83, 0, 0}, + {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, +@@ -516,7 +512,6 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, +- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, + }; + +@@ -535,8 +530,8 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, ++ {0x4407, 0x04, 0, 0}, ++ {0x5001, 0x83, 0, 70}, + }; + + /* power-on sensor init reg table */ +@@ -1005,9 +1000,38 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, + + static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) + { ++ const struct ov5640_mode_info *mode = sensor->current_mode; + u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; ++ struct i2c_client *client = sensor->i2c_client; ++ unsigned int pclk_freq, max_pclk_freq; ++ u8 dvp_pclk_divider; + int ret; + ++ /* ++ * 1280x720 and 1024x768 are reported to use 'SUBSAMPLING' only, ++ * but they seems to go through the scaler before subsampling. ++ */ ++ if (mode->dn_mode == SCALING || ++ (mode->id == OV5640_MODE_720P_1280_720) || ++ (mode->id == OV5640_MODE_XGA_1024_768)) ++ dvp_pclk_divider = 1; ++ else ++ dvp_pclk_divider = 2; ++ ++ ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER, ++ dvp_pclk_divider); ++ if (ret) ++ return ret; ++ pclk_freq = rate / dvp_pclk_divider; ++ max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency; ++ ++ /* clip rate according to optional maximum pixel clock limit */ ++ if (max_pclk_freq && (pclk_freq > max_pclk_freq)) { ++ rate = max_pclk_freq * dvp_pclk_divider; ++ dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n", ++ pclk_freq, max_pclk_freq); ++ } ++ + ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, + &bit_div, &pclk_div); + +@@ -1042,6 +1066,7 @@ static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) + (ilog2(pclk_div) << 4)); + } + ++#if 0 + /* set JPEG framing sizes */ + static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) +@@ -1065,19 +1090,20 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, + + return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); + } ++#endif + + /* download ov5640 settings to sensor through i2c */ + static int ov5640_set_timings(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) + { + int ret; +- ++#if 0 + if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { + ret = ov5640_set_jpeg_timings(sensor, mode); + if (ret < 0) + return ret; + } +- ++#endif + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); + if (ret < 0) + return ret; +@@ -2199,6 +2225,10 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, + return 0; + } + ++static const s64 link_freq_menu_items[] = { ++ 384000000, ++}; ++ + static int ov5640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +@@ -2637,6 +2667,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_VFLIP: + ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); + break; ++ case V4L2_CID_LINK_FREQ: ++ return 0; + default: + ret = -EINVAL; + break; +@@ -2704,6 +2736,9 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + ++ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, ++ 0, 0, link_freq_menu_items); ++ + if (hdl->error) { + ret = hdl->error; + goto free_ctrls; +diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c +index 8a86b2cc2..108f83c26 100644 +--- a/drivers/media/platform/stm32/stm32-cec.c ++++ b/drivers/media/platform/stm32/stm32-cec.c +@@ -291,7 +291,9 @@ static int stm32_cec_probe(struct platform_device *pdev) + + cec->clk_cec = devm_clk_get(&pdev->dev, "cec"); + if (IS_ERR(cec->clk_cec)) { +- dev_err(&pdev->dev, "Cannot get cec clock\n"); ++ if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Cannot get cec clock\n"); ++ + return PTR_ERR(cec->clk_cec); + } + +@@ -302,10 +304,14 @@ static int stm32_cec_probe(struct platform_device *pdev) + } + + cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec"); ++ if (IS_ERR(cec->clk_hdmi_cec) && ++ PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ + if (!IS_ERR(cec->clk_hdmi_cec)) { + ret = clk_prepare(cec->clk_hdmi_cec); + if (ret) { +- dev_err(&pdev->dev, "Unable to prepare hdmi-cec clock\n"); ++ dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n"); + return ret; + } + } +diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c +index 9392e3409..2e78facd0 100644 +--- a/drivers/media/platform/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/stm32/stm32-dcmi.c +@@ -95,6 +95,9 @@ enum state { + #define MIN_HEIGHT 16U + #define MAX_HEIGHT 2592U + ++/* DMA can sustain YUV 720p@15fps max */ ++#define MAX_DMA_BANDWIDTH (1280 * 720 * 2 * 15) ++ + #define TIMEOUT_MS 1000 + + #define OVERRUN_ERROR_THRESHOLD 3 +@@ -324,7 +327,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, + } + + /* +- * Avoid call of dmaengine_terminate_all() between ++ * Avoid call of dmaengine_terminate_sync() between + * dmaengine_prep_slave_single() and dmaengine_submit() + * by locking the whole DMA submission sequence + */ +@@ -438,7 +441,7 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) + } + + /* Abort DMA operation */ +- dmaengine_terminate_all(dcmi->dma_chan); ++ dmaengine_terminate_sync(dcmi->dma_chan); + + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) +@@ -784,8 +787,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + dcmi_set_crop(dcmi); + + /* Enable jpeg capture */ +- if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) +- reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ ++ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) { ++ unsigned int rate; ++ struct v4l2_streamparm p = { ++ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE ++ }; ++ struct v4l2_fract frame_interval = {1, 30}; ++ ++ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.source, &p); ++ if (!ret) ++ frame_interval = p.parm.capture.timeperframe; ++ ++ rate = dcmi->fmt.fmt.pix.sizeimage * ++ frame_interval.denominator / frame_interval.numerator; ++ ++ /* ++ * If rate exceed DMA capabilities, switch to snapshot mode ++ * to ensure that current DMA transfer is elapsed before ++ * capturing a new JPEG. ++ */ ++ if (rate > MAX_DMA_BANDWIDTH) { ++ reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ ++ dev_dbg(dcmi->dev, "Capture rate is too high for continuous mode (%d > %d bytes/s), switch to snapshot mode\n", ++ rate, MAX_DMA_BANDWIDTH); ++ } ++ } + + /* Enable dcmi */ + reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); +@@ -884,7 +910,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) + + /* Stop all pending DMA operations */ + mutex_lock(&dcmi->dma_lock); +- dmaengine_terminate_all(dcmi->dma_chan); ++ dmaengine_terminate_sync(dcmi->dma_chan); + mutex_unlock(&dcmi->dma_lock); + + pm_runtime_put(dcmi->dev); +@@ -1853,7 +1879,9 @@ static int dcmi_probe(struct platform_device *pdev) + + dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(dcmi->rstc)) { +- dev_err(&pdev->dev, "Could not get reset control\n"); ++ if (PTR_ERR(dcmi->rstc) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get reset control\n"); ++ + return PTR_ERR(dcmi->rstc); + } + +@@ -1910,10 +1938,13 @@ static int dcmi_probe(struct platform_device *pdev) + return PTR_ERR(mclk); + } + +- chan = dma_request_slave_channel(&pdev->dev, "tx"); +- if (!chan) { +- dev_info(&pdev->dev, "Unable to request DMA channel, defer probing\n"); +- return -EPROBE_DEFER; ++ chan = dma_request_chan(&pdev->dev, "tx"); ++ if (IS_ERR(chan)) { ++ ret = PTR_ERR(chan); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "Failed to request DMA channel: %d\n", ret); ++ return ret; + } + + spin_lock_init(&dcmi->irqlock); +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index 3bd188878..7f370d6b7 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -356,6 +356,9 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, + pr_debug("data-enable-active %s\n", v ? "high" : "low"); + } + ++ if (!fwnode_property_read_u32(fwnode, "pclk-max-frequency", &v)) ++ bus->pclk_max_frequency = v; ++ + switch (bus_type) { + default: + bus->flags = flags; +diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig +index 833e04a78..4ad5724f5 100644 +--- a/drivers/soc/Kconfig ++++ b/drivers/soc/Kconfig +@@ -14,6 +14,7 @@ source "drivers/soc/qcom/Kconfig" + source "drivers/soc/renesas/Kconfig" + source "drivers/soc/rockchip/Kconfig" + source "drivers/soc/samsung/Kconfig" ++source "drivers/soc/st/Kconfig" + source "drivers/soc/sunxi/Kconfig" + source "drivers/soc/tegra/Kconfig" + source "drivers/soc/ti/Kconfig" +diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile +index 2ec355003..30d3dcabf 100644 +--- a/drivers/soc/Makefile ++++ b/drivers/soc/Makefile +@@ -20,6 +20,7 @@ obj-y += qcom/ + obj-y += renesas/ + obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ + obj-$(CONFIG_SOC_SAMSUNG) += samsung/ ++obj-$(CONFIG_ARCH_STM32) += st/ + obj-y += sunxi/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-y += ti/ +diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig +new file mode 100644 +index 000000000..59db03150 +--- /dev/null ++++ b/drivers/soc/st/Kconfig +@@ -0,0 +1,17 @@ ++if ARCH_STM32 ++ ++config STM32_HDP ++ bool "STMicroelectronics STM32MP157 Hardware Debug Port (HDP) pin control" ++ depends on MACH_STM32MP157 ++ default n if MACH_STM32MP157 ++ help ++ The Hardware Debug Port allows the observation of internal signals. By using multiplexers, ++ up to 16 signals for each of 8-bit output can be observed. ++ ++config STM32_PM_DOMAINS ++ bool "STM32 PM domains" ++ depends on MACH_STM32MP157 ++ select PM_GENERIC_DOMAINS ++ default y if MACH_STM32MP157 ++ ++endif # ARCH_STM32 +diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile +new file mode 100644 +index 000000000..0fce1db16 +--- /dev/null ++++ b/drivers/soc/st/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_STM32_HDP) += stm32_hdp.o ++obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o +diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c +new file mode 100644 +index 000000000..6408ac68c +--- /dev/null ++++ b/drivers/soc/st/stm32_hdp.c +@@ -0,0 +1,242 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Christophe Roullier ++ * for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define HDP_CTRL_ENABLE 1 ++#define HDP_CTRL_DISABLE 0 ++ ++enum { ++ HDP_CTRL = 0, ++ HDP_MUX = 0x4, ++ HDP_VAL = 0x10, ++ HDP_GPOSET = 0x14, ++ HDP_GPOCLR = 0x18, ++ HDP_GPOVAL = 0x1c, ++ HDP_VERR = 0x3f4, ++ HDP_IPIDR = 0x3f8, ++ HDP_SIDR = 0x3fc ++} HDP_register_offsets; ++ ++struct data_priv { ++ struct clk *clk; ++ int clk_is_enabled; ++ struct dentry *pwr_dentry; ++ unsigned char __iomem *hdp_membase; ++ unsigned int hdp_ctrl; ++ unsigned int hdp_mux; ++}; ++ ++/* enable/disable */ ++static int stm32_hdp_enable_set(void *data, int val) ++{ ++ struct data_priv *e = (struct data_priv *)data; ++ ++ if (!e->clk) ++ return -EPERM; ++ ++ if (val == 1) { ++ if (clk_prepare_enable(e->clk) < 0) { ++ pr_err("Failed to enable HDP clock\n"); ++ return -EPERM; ++ } ++ e->clk_is_enabled = 1; ++ } else { ++ clk_disable_unprepare(e->clk); ++ e->clk_is_enabled = 0; ++ } ++ return 0; ++} ++ ++static int stm32_hdp_fops_set(void *data, u64 val) ++{ ++ unsigned char __iomem *addr = (unsigned char __iomem *)data; ++ ++ writel_relaxed(val, addr); ++ ++ return 0; ++} ++ ++static int stm32_hdp_fops_get(void *data, u64 *val) ++{ ++ unsigned char __iomem *addr = (unsigned char __iomem *)data; ++ ++ *val = readl_relaxed(addr); ++ ++ return 0; ++} ++ ++DEFINE_SIMPLE_ATTRIBUTE(stm32_hdp_fops, stm32_hdp_fops_get, ++ stm32_hdp_fops_set, "0x%llx\n"); ++ ++int stm32_hdp_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ ++ struct data_priv *data; ++ struct dentry *r; ++ ++ int ret; ++ const __be32 *getmuxing; ++ u32 muxing, version; ++ ++ if (!np) ++ return -ENODEV; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(struct data_priv), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ data->hdp_membase = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->hdp_membase)) ++ return PTR_ERR(data->hdp_membase); ++ ++ /* Get HDP clocks */ ++ data->clk = devm_clk_get(dev, "hdp"); ++ if (IS_ERR(data->clk)) { ++ dev_err(dev, "No HDP CK clock provided...\n"); ++ return PTR_ERR(data->clk); ++ } ++ ++ /* Enable clock */ ++ ret = stm32_hdp_enable_set(data, 1); ++ if (ret != 0) ++ return ret; ++ ++ getmuxing = of_get_property(np, "muxing-hdp", NULL); ++ if (!getmuxing) { ++ dev_err(dev, ++ "no muxing-hdp property in node\n"); ++ /* Disable clock */ ++ ret = stm32_hdp_enable_set(data, 0); ++ if (ret != 0) ++ return ret; ++ ++ return -EINVAL; ++ } ++ ++ /* add hdp directory */ ++ r = debugfs_create_dir("hdp", NULL); ++ if (!r) { ++ dev_err(dev, "Unable to create HDP debugFS\n"); ++ /* Disable clock */ ++ ret = stm32_hdp_enable_set(data, 0); ++ if (ret != 0) ++ return ret; ++ ++ return -ENODEV; ++ } ++ ++ debugfs_create_file("ctrl", 0644, r, ++ data->hdp_membase + HDP_CTRL, &stm32_hdp_fops); ++ debugfs_create_file("mux", 0644, r, ++ data->hdp_membase + HDP_MUX, &stm32_hdp_fops); ++ debugfs_create_file("val", 0644, r, ++ data->hdp_membase + HDP_VAL, &stm32_hdp_fops); ++ debugfs_create_file("gposet", 0644, r, ++ data->hdp_membase + HDP_GPOSET, &stm32_hdp_fops); ++ debugfs_create_file("gpoclr", 0644, r, ++ data->hdp_membase + HDP_GPOCLR, &stm32_hdp_fops); ++ debugfs_create_file("gpoval", 0644, r, ++ data->hdp_membase + HDP_GPOVAL, &stm32_hdp_fops); ++ ++ /* Enable HDP */ ++ writel(HDP_CTRL_ENABLE, data->hdp_membase + HDP_CTRL); ++ ++ /* HDP Multiplexing */ ++ muxing = of_read_number(getmuxing, ++ of_n_addr_cells(np)); ++ ++ writel(muxing, data->hdp_membase + HDP_MUX); ++ ++ platform_set_drvdata(pdev, data); ++ ++ /* Get Majeur, Minor version */ ++ version = readl(data->hdp_membase + HDP_VERR); ++ ++ dev_info(dev, "STM32 HDP version %d.%d initialized\n", ++ version >> 4, version & 0x0F); ++ ++ return 0; ++} ++ ++static int stm32_hdp_remove(struct platform_device *pdev) ++{ ++ struct data_priv *data = platform_get_drvdata(pdev); ++ ++ /* Disable HDP */ ++ writel(HDP_CTRL_DISABLE, data->hdp_membase + HDP_CTRL); ++ ++ if (data->clk) { ++ if (data->clk_is_enabled) ++ clk_disable_unprepare(data->clk); ++ } ++ ++ pr_info("driver STM32 HDP removed\n"); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int stm32_hdp_suspend(struct device *dev) ++{ ++ struct data_priv *data = dev_get_drvdata(dev); ++ ++ data->hdp_ctrl = readl_relaxed(data->hdp_membase + HDP_CTRL); ++ data->hdp_mux = readl_relaxed(data->hdp_membase + HDP_MUX); ++ ++ pinctrl_pm_select_sleep_state(dev); ++ ++ return 0; ++} ++ ++static int stm32_hdp_resume(struct device *dev) ++{ ++ struct data_priv *data = dev_get_drvdata(dev); ++ ++ writel_relaxed(data->hdp_ctrl, data->hdp_membase + HDP_CTRL); ++ writel_relaxed(data->hdp_mux, data->hdp_membase + HDP_MUX); ++ ++ pinctrl_pm_select_default_state(dev); ++ ++ return 0; ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++static SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, ++ stm32_hdp_suspend, ++ stm32_hdp_resume); ++ ++static const struct of_device_id hdp_match[] = { ++ { .compatible = "st,stm32mp1-hdp",}, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, hdp_match); ++ ++static struct platform_driver hdp_driver = { ++ .probe = stm32_hdp_probe, ++ .remove = stm32_hdp_remove, ++ .driver = { ++ .name = "hdp", ++ .of_match_table = hdp_match, ++ .pm = &stm32_hdp_pm_ops, ++ }, ++}; ++ ++module_platform_driver(hdp_driver); +diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c +new file mode 100644 +index 000000000..0386624c2 +--- /dev/null ++++ b/drivers/soc/st/stm32_pm_domain.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ * Author: Olivier Bideau for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SMC(domain, state) \ ++{ \ ++ struct arm_smccc_res res; \ ++ arm_smccc_smc(0x82001008, domain, state, 0, \ ++ 0, 0, 0, 0, &res); \ ++} ++ ++#define STM32_SMC_PD_DOMAIN_ON 0 ++#define STM32_SMC_PD_DOMAIN_OFF 1 ++ ++struct stm32_pm_domain { ++ struct device *dev; ++ struct generic_pm_domain genpd; ++ int id; ++}; ++ ++static int stm32_pd_power_off(struct generic_pm_domain *domain) ++{ ++ struct stm32_pm_domain *priv = container_of(domain, ++ struct stm32_pm_domain, ++ genpd); ++ ++ SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF); ++ ++ dev_dbg(priv->dev, "%s OFF\n", domain->name); ++ ++ return 0; ++} ++ ++static int stm32_pd_power_on(struct generic_pm_domain *domain) ++{ ++ struct stm32_pm_domain *priv = container_of(domain, ++ struct stm32_pm_domain, ++ genpd); ++ ++ SMC(priv->id, STM32_SMC_PD_DOMAIN_ON); ++ ++ dev_dbg(priv->dev, "%s ON\n", domain->name); ++ ++ return 0; ++} ++ ++static void stm32_pm_domain_remove(struct stm32_pm_domain *domain) ++{ ++ int ret; ++ ++ ret = pm_genpd_remove(&domain->genpd); ++ if (ret) ++ dev_err(domain->dev, "failed to remove PM domain %s: %d\n", ++ domain->genpd.name, ret); ++} ++ ++static int stm32_pm_domain_add(struct stm32_pm_domain *domain, ++ struct device *dev, ++ struct device_node *np) ++{ ++ int ret; ++ ++ domain->dev = dev; ++ domain->genpd.name = np->name; ++ domain->genpd.power_off = stm32_pd_power_off; ++ domain->genpd.power_on = stm32_pd_power_on; ++ domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; ++ ++ ret = of_property_read_u32(np, "reg", &domain->id); ++ if (ret) { ++ dev_err(domain->dev, "no domain ID\n"); ++ return ret; ++ } ++ ++ ret = pm_genpd_init(&domain->genpd, NULL, 0); ++ if (ret < 0) { ++ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", ++ np->name, ret); ++ return ret; ++ } ++ ++ ret = of_genpd_add_provider_simple(np, &domain->genpd); ++ if (ret < 0) { ++ dev_err(domain->dev, "failed to register PM domain %s: %d\n", ++ np->name, ret); ++ stm32_pm_domain_remove(domain); ++ return ret; ++ } ++ ++ dev_info(domain->dev, "domain %s registered\n", np->name); ++ ++ return 0; ++} ++ ++static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain, ++ struct device *dev, ++ struct device_node *np) ++{ ++ struct device_node *np_child; ++ int ret; ++ ++ for_each_child_of_node(np, np_child) { ++ struct stm32_pm_domain *sub_domain; ++ ++ sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL); ++ if (!sub_domain) ++ continue; ++ ++ sub_domain->dev = dev; ++ sub_domain->genpd.name = np_child->name; ++ sub_domain->genpd.power_off = stm32_pd_power_off; ++ sub_domain->genpd.power_on = stm32_pd_power_on; ++ sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; ++ ++ ret = of_property_read_u32(np_child, "reg", &sub_domain->id); ++ if (ret) { ++ dev_err(sub_domain->dev, "no domain ID\n"); ++ devm_kfree(dev, sub_domain); ++ continue; ++ } ++ ++ ret = pm_genpd_init(&sub_domain->genpd, NULL, 0); ++ if (ret < 0) { ++ dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n" ++ , np_child->name, ret); ++ devm_kfree(dev, sub_domain); ++ continue; ++ } ++ ++ ret = of_genpd_add_provider_simple(np_child, ++ &sub_domain->genpd); ++ if (ret < 0) { ++ dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n" ++ , np_child->name, ret); ++ stm32_pm_domain_remove(sub_domain); ++ devm_kfree(dev, sub_domain); ++ continue; ++ } ++ ++ ret = pm_genpd_add_subdomain(&domain->genpd, ++ &sub_domain->genpd); ++ ++ if (ret < 0) { ++ dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n" ++ , np_child->name, ret); ++ stm32_pm_domain_remove(sub_domain); ++ devm_kfree(dev, sub_domain); ++ continue; ++ } ++ ++ dev_info(sub_domain->dev, "subdomain %s registered\n", ++ np_child->name); ++ } ++} ++ ++static int stm32_pm_domain_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node, *child_np; ++ int ret; ++ ++ for_each_child_of_node(np, child_np) { ++ struct stm32_pm_domain *domain; ++ ++ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); ++ if (!domain) ++ continue; ++ ++ ret = stm32_pm_domain_add(domain, dev, child_np); ++ if (ret) { ++ devm_kfree(dev, domain); ++ continue; ++ } ++ ++ stm32_pm_subdomain_add(domain, dev, child_np); ++ } ++ ++ dev_info(dev, "domains probed\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id stm32_pm_domain_matches[] = { ++ { .compatible = "st,stm32mp157c-pd", }, ++ { }, ++}; ++ ++static struct platform_driver stm32_pm_domains_driver = { ++ .probe = stm32_pm_domain_probe, ++ .driver = { ++ .name = "stm32-pm-domain", ++ .of_match_table = stm32_pm_domain_matches, ++ }, ++}; ++ ++static int __init stm32_pm_domains_init(void) ++{ ++ return platform_driver_register(&stm32_pm_domains_driver); ++} ++core_initcall(stm32_pm_domains_init); +diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c +index cf9ddc52f..1cecf9544 100644 +--- a/drivers/thermal/st/stm_thermal.c ++++ b/drivers/thermal/st/stm_thermal.c +@@ -30,7 +30,7 @@ + #define DTS_DR_OFFSET 0x1C + #define DTS_SR_OFFSET 0x20 + #define DTS_ITENR_OFFSET 0x24 +-#define DTS_CIFR_OFFSET 0x28 ++#define DTS_ICIFR_OFFSET 0x28 + + /* DTS_CFGR1 register mask definitions */ + #define HSREF_CLK_DIV_MASK GENMASK(30, 24) +@@ -51,10 +51,16 @@ + /* DTS_DR register mask definitions */ + #define TS1_MFREQ_MASK GENMASK(15, 0) + ++/* DTS_ITENR register mask definitions */ ++#define ITENR_MASK (GENMASK(2, 0) | GENMASK(6, 4)) ++ ++/* DTS_ICIFR register mask definitions */ ++#define ICIFR_MASK (GENMASK(2, 0) | GENMASK(6, 4)) ++ + /* Less significant bit position definitions */ + #define TS1_T0_POS 16 +-#define TS1_SMP_TIME_POS 16 + #define TS1_HITTHD_POS 16 ++#define TS1_LITTHD_POS 0 + #define HSREF_CLK_DIV_POS 24 + + /* DTS_CFGR1 bit definitions */ +@@ -76,58 +82,37 @@ + #define ONE_MHZ 1000000 + #define POLL_TIMEOUT 5000 + #define STARTUP_TIME 40 +-#define TS1_T0_VAL0 30 +-#define TS1_T0_VAL1 130 ++#define T0 30000 /* 30 celsius */ + #define NO_HW_TRIG 0 +- +-/* The Thermal Framework expects millidegrees */ +-#define mcelsius(temp) ((temp) * 1000) +- +-/* The Sensor expects oC degrees */ +-#define celsius(temp) ((temp) / 1000) ++#define SAMPLING_TIME 15 + + struct stm_thermal_sensor { + struct device *dev; + struct thermal_zone_device *th_dev; + enum thermal_device_mode mode; + struct clk *clk; +- int high_temp; +- int low_temp; +- int temp_critical; +- int temp_passive; + unsigned int low_temp_enabled; +- int num_trips; ++ unsigned int high_temp_enabled; + int irq; +- unsigned int irq_enabled; + void __iomem *base; +- int t0, fmt0, ramp_coeff; ++ int fmt0, ramp_coeff; + }; + +-static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata) +-{ +- struct stm_thermal_sensor *sensor = sdata; +- +- disable_irq_nosync(irq); +- sensor->irq_enabled = false; +- +- return IRQ_WAKE_THREAD; +-} ++static int stm_enable_irq(struct stm_thermal_sensor *sensor); + + static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata) + { +- u32 value; + struct stm_thermal_sensor *sensor = sdata; + +- /* read IT reason in SR and clear flags */ +- value = readl_relaxed(sensor->base + DTS_SR_OFFSET); ++ dev_dbg(sensor->dev, "sr:%d\n", ++ readl_relaxed(sensor->base + DTS_SR_OFFSET)); + +- if ((value & LOW_THRESHOLD) == LOW_THRESHOLD) +- writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); ++ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); + +- if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD) +- writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); ++ stm_enable_irq(sensor); + +- thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); ++ /* Acknoledge all DTS irqs */ ++ writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET); + + return IRQ_HANDLED; + } +@@ -160,6 +145,8 @@ static int stm_sensor_power_on(struct stm_thermal_sensor *sensor) + writel_relaxed(value, sensor->base + + DTS_CFGR1_OFFSET); + ++ sensor->mode = THERMAL_DEVICE_ENABLED; ++ + return 0; + } + +@@ -167,6 +154,8 @@ static int stm_sensor_power_off(struct stm_thermal_sensor *sensor) + { + u32 value; + ++ sensor->mode = THERMAL_DEVICE_DISABLED; ++ + /* Stop measuring */ + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + value &= ~TS1_START; +@@ -232,14 +221,6 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) + /* Fill in DTS structure with factory sensor values */ + static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) + { +- /* Retrieve engineering calibration temperature */ +- sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) & +- TS1_T0_MASK; +- if (!sensor->t0) +- sensor->t0 = TS1_T0_VAL0; +- else +- sensor->t0 = TS1_T0_VAL1; +- + /* Retrieve fmt0 and put it on Hz */ + sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base + + DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK); +@@ -253,8 +234,8 @@ static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) + return -EINVAL; + } + +- dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC", +- __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff); ++ dev_dbg(sensor->dev, "%s: FMT0 = %dHz, RAMP_COEFF = %dHz/oC", ++ __func__, sensor->fmt0, sensor->ramp_coeff); + + return 0; + } +@@ -263,60 +244,16 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor, + int temp, u32 *th) + { + int freqM; +- u32 sampling_time; +- +- /* Retrieve the number of periods to sample */ +- sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & +- TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; + + /* Figure out the CLK_PTAT frequency for a given temperature */ +- freqM = ((temp - sensor->t0) * sensor->ramp_coeff) +- + sensor->fmt0; +- +- dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz", +- __func__, freqM); ++ freqM = ((temp - T0) * sensor->ramp_coeff) / 1000 + sensor->fmt0; + + /* Figure out the threshold sample number */ +- *th = clk_get_rate(sensor->clk); ++ *th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM; + if (!*th) + return -EINVAL; + +- *th = *th / freqM; +- +- *th *= sampling_time; +- +- return 0; +-} +- +-static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor) +-{ +- u32 value, th; +- int ret; +- +- value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET); +- +- /* Erase threshold content */ +- value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK); +- +- /* Retrieve the sample threshold number th for a given temperature */ +- ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th); +- if (ret) +- return ret; +- +- value |= th & TS1_LITTHD_MASK; +- +- if (sensor->low_temp_enabled) { +- /* Retrieve the sample threshold */ +- ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp, +- &th); +- if (ret) +- return ret; +- +- value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS)); +- } +- +- /* Write value on the Low interrupt threshold */ +- writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET); ++ dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th); + + return 0; + } +@@ -326,12 +263,10 @@ static int stm_disable_irq(struct stm_thermal_sensor *sensor) + { + u32 value; + +- /* Disable IT generation for low and high thresholds */ ++ /* Disable IT generation */ + value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); +- writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD), +- sensor->base + DTS_ITENR_OFFSET); +- +- dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__); ++ value &= ~ITENR_MASK; ++ writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); + + return 0; + } +@@ -341,62 +276,68 @@ static int stm_enable_irq(struct stm_thermal_sensor *sensor) + { + u32 value; + +- /* +- * Code below enables High temperature threshold using a low threshold +- * sampling value +- */ +- +- /* Make sure LOW_THRESHOLD IT is clear before enabling */ +- writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); ++ dev_dbg(sensor->dev, "low:%d high:%d\n", sensor->low_temp_enabled, ++ sensor->high_temp_enabled); + +- /* Enable IT generation for low threshold */ ++ /* Disable IT generation for low and high thresholds */ + value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); +- value |= LOW_THRESHOLD; +- +- /* Enable the low temperature threshold if needed */ +- if (sensor->low_temp_enabled) { +- /* Make sure HIGH_THRESHOLD IT is clear before enabling */ +- writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); ++ value &= ~(LOW_THRESHOLD | HIGH_THRESHOLD); + +- /* Enable IT generation for high threshold */ ++ if (sensor->low_temp_enabled) + value |= HIGH_THRESHOLD; +- } + +- /* Enable thresholds */ +- writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); ++ if (sensor->high_temp_enabled) ++ value |= LOW_THRESHOLD; + +- dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__); ++ /* Enable interrupts */ ++ writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); + + return 0; + } + +-static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor) ++static int stm_thermal_set_trips(void *data, int low, int high) + { ++ struct stm_thermal_sensor *sensor = data; ++ u32 itr1, th; + int ret; + +- sensor->mode = THERMAL_DEVICE_DISABLED; ++ dev_dbg(sensor->dev, "set trips %d <--> %d\n", low, high); + +- ret = stm_sensor_power_off(sensor); +- if (ret) +- return ret; ++ /* Erase threshold content */ ++ itr1 = readl_relaxed(sensor->base + DTS_ITR1_OFFSET); ++ itr1 &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK); + +- ret = stm_disable_irq(sensor); +- if (ret) +- return ret; ++ /* ++ * Disable low-temp if "low" is too small. As per thermal framework ++ * API, we use -INT_MAX rather than INT_MIN. ++ */ + +- ret = stm_thermal_set_threshold(sensor); +- if (ret) +- return ret; ++ if (low > -INT_MAX) { ++ sensor->low_temp_enabled = 1; ++ /* add 0.5 of hysteresis due to measurement error */ ++ ret = stm_thermal_calculate_threshold(sensor, low - 500, &th); ++ if (ret) ++ return ret; + +- ret = stm_enable_irq(sensor); +- if (ret) +- return ret; ++ itr1 |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS)); ++ } else { ++ sensor->low_temp_enabled = 0; ++ } + +- ret = stm_sensor_power_on(sensor); +- if (ret) +- return ret; ++ /* Disable high-temp if "high" is too big. */ ++ if (high < INT_MAX) { ++ sensor->high_temp_enabled = 1; ++ ret = stm_thermal_calculate_threshold(sensor, high, &th); ++ if (ret) ++ return ret; + +- sensor->mode = THERMAL_DEVICE_ENABLED; ++ itr1 |= (TS1_LITTHD_MASK & (th << TS1_LITTHD_POS)); ++ } else { ++ sensor->high_temp_enabled = 0; ++ } ++ ++ /* Write new threshod values*/ ++ writel_relaxed(itr1, sensor->base + DTS_ITR1_OFFSET); + + return 0; + } +@@ -405,76 +346,26 @@ static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor) + static int stm_thermal_get_temp(void *data, int *temp) + { + struct stm_thermal_sensor *sensor = data; +- u32 sampling_time; ++ u32 periods; + int freqM, ret; + + if (sensor->mode != THERMAL_DEVICE_ENABLED) + return -EAGAIN; + +- /* Retrieve the number of samples */ +- ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM, +- (freqM & TS1_MFREQ_MASK), STARTUP_TIME, +- POLL_TIMEOUT); +- ++ /* Retrieve the number of periods sampled */ ++ ret = readl_relaxed_poll_timeout(sensor->base + DTS_DR_OFFSET, periods, ++ (periods & TS1_MFREQ_MASK), ++ STARTUP_TIME, POLL_TIMEOUT); + if (ret) + return ret; + +- if (!freqM) +- return -ENODATA; +- +- /* Retrieve the number of periods sampled */ +- sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & +- TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; +- +- /* Figure out the number of samples per period */ +- freqM /= sampling_time; +- + /* Figure out the CLK_PTAT frequency */ +- freqM = clk_get_rate(sensor->clk) / freqM; ++ freqM = (clk_get_rate(sensor->clk) * SAMPLING_TIME) / periods; + if (!freqM) + return -EINVAL; + +- dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM); +- + /* Figure out the temperature in mili celsius */ +- *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) / +- sensor->ramp_coeff)); +- +- dev_dbg(sensor->dev, "%s: temperature = %d millicelsius", +- __func__, *temp); +- +- /* Update thresholds */ +- if (sensor->num_trips > 1) { +- /* Update alarm threshold value to next higher trip point */ +- if (sensor->high_temp == sensor->temp_passive && +- celsius(*temp) >= sensor->temp_passive) { +- sensor->high_temp = sensor->temp_critical; +- sensor->low_temp = sensor->temp_passive; +- sensor->low_temp_enabled = true; +- ret = stm_thermal_update_threshold(sensor); +- if (ret) +- return ret; +- } +- +- if (sensor->high_temp == sensor->temp_critical && +- celsius(*temp) < sensor->temp_passive) { +- sensor->high_temp = sensor->temp_passive; +- sensor->low_temp_enabled = false; +- ret = stm_thermal_update_threshold(sensor); +- if (ret) +- return ret; +- } +- +- /* +- * Re-enable alarm IRQ if temperature below critical +- * temperature +- */ +- if (!sensor->irq_enabled && +- (celsius(*temp) < sensor->temp_critical)) { +- sensor->irq_enabled = true; +- enable_irq(sensor->irq); +- } +- } ++ *temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + T0; + + return 0; + } +@@ -493,7 +384,7 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor) + } + + ret = devm_request_threaded_irq(dev, sensor->irq, +- stm_thermal_alarm_irq, ++ NULL, + stm_thermal_alarm_irq_thread, + IRQF_ONESHOT, + dev->driver->name, sensor); +@@ -503,8 +394,6 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor) + return ret; + } + +- sensor->irq_enabled = true; +- + dev_dbg(dev, "%s: thermal IRQ registered", __func__); + + return 0; +@@ -514,6 +403,8 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor) + { + int ret; + ++ stm_disable_irq(sensor); ++ + ret = stm_sensor_power_off(sensor); + if (ret) + return ret; +@@ -526,7 +417,6 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor) + static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) + { + int ret; +- struct device *dev = sensor->dev; + + ret = clk_prepare_enable(sensor->clk); + if (ret) +@@ -540,26 +430,8 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) + if (ret) + goto thermal_unprepare; + +- /* Set threshold(s) for IRQ */ +- ret = stm_thermal_set_threshold(sensor); +- if (ret) +- goto thermal_unprepare; +- +- ret = stm_enable_irq(sensor); +- if (ret) +- goto thermal_unprepare; +- +- ret = stm_sensor_power_on(sensor); +- if (ret) { +- dev_err(dev, "%s: failed to power on sensor\n", __func__); +- goto irq_disable; +- } +- + return 0; + +-irq_disable: +- stm_disable_irq(sensor); +- + thermal_unprepare: + clk_disable_unprepare(sensor->clk); + +@@ -576,8 +448,6 @@ static int stm_thermal_suspend(struct device *dev) + if (ret) + return ret; + +- sensor->mode = THERMAL_DEVICE_DISABLED; +- + return 0; + } + +@@ -590,7 +460,12 @@ static int stm_thermal_resume(struct device *dev) + if (ret) + return ret; + +- sensor->mode = THERMAL_DEVICE_ENABLED; ++ ret = stm_sensor_power_on(sensor); ++ if (ret) ++ return ret; ++ ++ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); ++ stm_enable_irq(sensor); + + return 0; + } +@@ -600,6 +475,7 @@ SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume); + + static const struct thermal_zone_of_device_ops stm_tz_ops = { + .get_temp = stm_thermal_get_temp, ++ .set_trips = stm_thermal_set_trips, + }; + + static const struct of_device_id stm_thermal_of_match[] = { +@@ -612,9 +488,8 @@ static int stm_thermal_probe(struct platform_device *pdev) + { + struct stm_thermal_sensor *sensor; + struct resource *res; +- const struct thermal_trip *trip; + void __iomem *base; +- int ret, i; ++ int ret; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "%s: device tree node not found\n", +@@ -640,15 +515,28 @@ static int stm_thermal_probe(struct platform_device *pdev) + + sensor->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(sensor->clk)) { +- dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n", +- __func__); ++ if (PTR_ERR(sensor->clk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get PCLK clock\n"); + return PTR_ERR(sensor->clk); + } + +- /* Register IRQ into GIC */ +- ret = stm_register_irq(sensor); +- if (ret) ++ stm_disable_irq(sensor); ++ ++ /* Clear irq flags */ ++ writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET); ++ ++ /* Configure and enable HW sensor */ ++ ret = stm_thermal_prepare(sensor); ++ if (ret) { ++ dev_err(&pdev->dev, "Error preprare sensor: %d\n", ret); + return ret; ++ } ++ ++ ret = stm_sensor_power_on(sensor); ++ if (ret) { ++ dev_err(&pdev->dev, "Error power on sensor: %d\n", ret); ++ return ret; ++ } + + sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, + sensor, +@@ -661,53 +549,12 @@ static int stm_thermal_probe(struct platform_device *pdev) + return ret; + } + +- if (!sensor->th_dev->ops->get_crit_temp) { +- /* Critical point must be provided */ +- ret = -EINVAL; +- goto err_tz; +- } +- +- ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev, +- &sensor->temp_critical); +- if (ret) { +- dev_err(&pdev->dev, +- "Not able to read critical_temp: %d\n", ret); ++ /* Register IRQ into GIC */ ++ ret = stm_register_irq(sensor); ++ if (ret) + goto err_tz; +- } +- +- sensor->temp_critical = celsius(sensor->temp_critical); +- +- /* Set thresholds for IRQ */ +- sensor->high_temp = sensor->temp_critical; +- +- trip = of_thermal_get_trip_points(sensor->th_dev); +- sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev); +- +- /* Find out passive temperature if it exists */ +- for (i = (sensor->num_trips - 1); i >= 0; i--) { +- if (trip[i].type == THERMAL_TRIP_PASSIVE) { +- sensor->temp_passive = celsius(trip[i].temperature); +- /* Update high temperature threshold */ +- sensor->high_temp = sensor->temp_passive; +- } +- } +- +- /* +- * Ensure low_temp_enabled flag is disabled. +- * By disabling low_temp_enabled, low threshold IT will not be +- * configured neither enabled because it is not needed as high +- * threshold is set on the lowest temperature trip point after +- * probe. +- */ +- sensor->low_temp_enabled = false; + +- /* Configure and enable HW sensor */ +- ret = stm_thermal_prepare(sensor); +- if (ret) { +- dev_err(&pdev->dev, +- "Not able to enable sensor: %d\n", ret); +- goto err_tz; +- } ++ stm_enable_irq(sensor); + + /* + * Thermal_zone doesn't enable hwmon as default, +@@ -718,8 +565,6 @@ static int stm_thermal_probe(struct platform_device *pdev) + if (ret) + goto err_tz; + +- sensor->mode = THERMAL_DEVICE_ENABLED; +- + dev_info(&pdev->dev, "%s: Driver initialized successfully\n", + __func__); + +diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h +index f6a7bcd13..c3dd47f14 100644 +--- a/include/media/v4l2-fwnode.h ++++ b/include/media/v4l2-fwnode.h +@@ -50,11 +50,13 @@ struct v4l2_fwnode_bus_mipi_csi2 { + * @flags: media bus (V4L2_MBUS_*) flags + * @bus_width: bus width in bits + * @data_shift: data shift in bits ++ * @max_pclk_frequency: maximum pixel clock in hertz + */ + struct v4l2_fwnode_bus_parallel { + unsigned int flags; + unsigned char bus_width; + unsigned char data_shift; ++ unsigned int pclk_max_frequency; + }; + + /** +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch new file mode 100644 index 0000000..7e5757a --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch @@ -0,0 +1,716 @@ +From f811efe3cbe842a78d98740c0a0a8e1b7c0181b0 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:45:15 +0200 +Subject: [PATCH 13/23] ARM-stm32mp1-r1-MFD + +--- + drivers/mfd/Kconfig | 10 + + drivers/mfd/Makefile | 1 + + drivers/mfd/stm32-pwr.c | 400 +++++++++++++++++++++++++++++++ + drivers/mfd/stm32-timers.c | 36 ++- + drivers/mfd/stmfx.c | 22 +- + drivers/mfd/stpmic1.c | 6 + + drivers/mfd/wm8994-core.c | 21 ++ + include/linux/mfd/stm32-timers.h | 12 +- + include/linux/mfd/stmfx.h | 1 + + include/linux/mfd/wm8994/pdata.h | 6 + + 10 files changed, 494 insertions(+), 21 deletions(-) + create mode 100644 drivers/mfd/stm32-pwr.c + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 43169f25d..48ef1822a 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -1955,6 +1955,16 @@ config MFD_STPMIC1 + To compile this driver as a module, choose M here: the + module will be called stpmic1. + ++config MFD_STM32MP1_PWR ++ bool "STM32MP1 wake-up pins" ++ depends on MACH_STM32MP157 ++ default y ++ help ++ Select this option to enable STM32 PWR Wake-up pins driver. ++ ++ This driver provides interruptions that can be used to wake-up from ++ suspend. ++ + config MFD_STMFX + tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)" + depends on I2C +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index c1067ea46..11acfa1bf 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -249,6 +249,7 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o + + obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o + obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o ++obj-$(CONFIG_MFD_STM32MP1_PWR) += stm32-pwr.o + obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o + obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o + obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o +diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c +new file mode 100644 +index 000000000..48ca8b474 +--- /dev/null ++++ b/drivers/mfd/stm32-pwr.c +@@ -0,0 +1,400 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Pascal Paillet for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NB_WAKEUPPINS 6 ++ ++#define STM32_SVC_PWR 0x82001001 ++#define STM32_WRITE 0x1 ++#define STM32_SET_BITS 0x2 ++#define STM32_CLEAR_BITS 0x3 ++ ++#define PWR_WKUP_OFFSET 0x20 ++// PWR Registers ++#define WKUPCR 0x0 ++#define WKUPFR 0x4 ++#define MPUWKUPENR 0x8 ++ ++#define WKUP_FLAGS_MASK GENMASK(5, 0) ++ ++// WKUPCR bits definition ++#define WKUP_EDGE_SHIFT 8 ++#define WKUP_PULL_SHIFT 16 ++#define WKUP_PULL_MASK GENMASK(1, 0) ++ ++enum wkup_pull_setting { ++ WKUP_NO_PULL = 0, ++ WKUP_PULL_UP, ++ WKUP_PULL_DOWN, ++ WKUP_PULL_RESERVED ++}; ++ ++#define SMC(class, op, offset, val) do { \ ++ struct arm_smccc_res res; \ ++ arm_smccc_smc(class, op, PWR_WKUP_OFFSET + (offset), val, \ ++ 0, 0, 0, 0, &res); \ ++} while (0) \ ++ ++struct stm32_pwr_data { ++ struct device *dev; ++ void __iomem *base; /* IO Memory base address */ ++ struct irq_domain *domain; /* Domain for this controller */ ++ int irq; /* Parent interrupt */ ++ u32 masked; /* IRQ is masked */ ++ u32 wake; /* IRQ is wake on */ ++ u32 pending; /* IRQ has been received while wake on*/ ++ struct gpio_desc *gpio[NB_WAKEUPPINS]; ++}; ++ ++static void stm32_pwr_irq_ack(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq)); ++} ++ ++static void stm32_pwr_irq_set_enable(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ if (!(priv->masked & BIT(d->hwirq)) || (priv->wake & BIT(d->hwirq))) ++ SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq)); ++ else ++ SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq)); ++} ++ ++static void stm32_pwr_irq_mask(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ priv->masked |= BIT(d->hwirq); ++ stm32_pwr_irq_set_enable(d); ++} ++ ++static void stm32_pwr_irq_unmask(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ priv->masked &= ~BIT(d->hwirq); ++ stm32_pwr_irq_set_enable(d); ++} ++ ++static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ struct irq_data *parent = irq_get_irq_data(priv->irq); ++ ++ dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on); ++ if (on) { ++ priv->wake |= BIT(d->hwirq); ++ } else { ++ priv->wake &= ~BIT(d->hwirq); ++ priv->pending &= ~BIT(d->hwirq); ++ } ++ stm32_pwr_irq_set_enable(d); ++ ++ if (parent->chip && parent->chip->irq_set_wake) ++ return parent->chip->irq_set_wake(parent, on); ++ ++ return 0; ++} ++ ++static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ int pin_id = d->hwirq; ++ u32 wkupcr; ++ int en; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ ++ en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id); ++ /* reference manual request to disable the wakeup pin while ++ * changing the edge detection setting ++ */ ++ if (en) ++ stm32_pwr_irq_mask(d); ++ ++ wkupcr = readl_relaxed(priv->base + WKUPCR); ++ switch (flow_type & IRQ_TYPE_SENSE_MASK) { ++ case IRQF_TRIGGER_FALLING: ++ wkupcr |= (1 << (WKUP_EDGE_SHIFT + pin_id)); ++ break; ++ case IRQF_TRIGGER_RISING: ++ wkupcr &= ~(1 << (WKUP_EDGE_SHIFT + pin_id)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); ++ ++ if (en) ++ stm32_pwr_irq_unmask(d); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SMP ++static int stm32_pwr_set_affinity_parent(struct irq_data *data, ++ const struct cpumask *dest, bool force) ++{ ++ struct stm32_pwr_data *priv = data->domain->host_data; ++ struct irq_data *parent = irq_get_irq_data(priv->irq); ++ ++ if (parent->chip && parent->chip->irq_set_affinity) ++ return parent->chip->irq_set_affinity(parent, dest, force); ++ ++ return IRQ_SET_MASK_OK_DONE; ++} ++#endif ++ ++static int stm32_pwr_irq_request_resources(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ struct gpio_desc *gpio; ++ int ret; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ gpio = gpiod_get_index(priv->dev, "wakeup", d->hwirq, GPIOD_IN); ++ if (IS_ERR(gpio)) { ++ ret = PTR_ERR(gpio); ++ dev_err(priv->dev, "Failed to get wakeup gpio: %d", ret); ++ return ret; ++ } ++ priv->gpio[d->hwirq] = gpio; ++ return 0; ++} ++ ++static void stm32_pwr_irq_release_resources(struct irq_data *d) ++{ ++ struct stm32_pwr_data *priv = d->domain->host_data; ++ ++ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); ++ gpiod_put(priv->gpio[d->hwirq]); ++} ++ ++static struct irq_chip stm32_pwr_irq_chip = { ++ .name = "stm32-pwr-irq", ++ .irq_ack = stm32_pwr_irq_ack, ++ .irq_mask = stm32_pwr_irq_mask, ++ .irq_unmask = stm32_pwr_irq_unmask, ++ .irq_set_type = stm32_pwr_irq_set_type, ++ .irq_set_wake = stm32_pwr_irq_set_wake, ++ .irq_request_resources = stm32_pwr_irq_request_resources, ++ .irq_release_resources = stm32_pwr_irq_release_resources, ++#ifdef CONFIG_SMP ++ .irq_set_affinity = stm32_pwr_set_affinity_parent, ++#endif ++}; ++ ++static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id, ++ enum wkup_pull_setting config) ++{ ++ struct stm32_pwr_data *priv = d->host_data; ++ u32 wkupcr; ++ ++ dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config); ++ ++ if (config >= WKUP_PULL_RESERVED) { ++ pr_err("%s: bad irq pull config\n", __func__); ++ return -EINVAL; ++ } ++ ++ wkupcr = readl_relaxed(priv->base + WKUPCR); ++ wkupcr &= ~((WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2)); ++ wkupcr |= (config & WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2); ++ ++ SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); ++ ++ return 0; ++} ++ ++static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr, ++ const u32 *intspec, unsigned int intsize, ++ irq_hw_number_t *out_hwirq, unsigned int *out_type) ++{ ++ if (WARN_ON(intsize < 3)) { ++ pr_err("%s: bad irq config parameters\n", __func__); ++ return -EINVAL; ++ } ++ ++ *out_hwirq = intspec[0]; ++ *out_type = intspec[1] & (IRQ_TYPE_SENSE_MASK); ++ ++ return stm32_pwr_irq_set_pull_config(d, intspec[0], intspec[2]); ++} ++ ++static int stm32_pwr_alloc(struct irq_domain *d, unsigned int virq, ++ unsigned int nr_irqs, void *data) ++{ ++ struct irq_fwspec *fwspec = data; ++ irq_hw_number_t hwirq; ++ ++ hwirq = fwspec->param[0]; ++ irq_domain_set_info(d, virq, hwirq, &stm32_pwr_irq_chip, d->host_data, ++ handle_edge_irq, NULL, NULL); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops stm32_pwr_irq_domain_ops = { ++ .alloc = stm32_pwr_alloc, ++ .xlate = stm32_pwr_xlate, ++ .free = irq_domain_free_irqs_common, ++}; ++ ++/* ++ * Handler for the cascaded IRQ. ++ */ ++static void stm32_pwr_handle_irq(struct irq_desc *desc) ++{ ++ struct stm32_pwr_data *priv = irq_desc_get_handler_data(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ u32 wkupfr, wkupenr, i; ++ ++ chained_irq_enter(chip, desc); ++ ++ wkupfr = readl_relaxed(priv->base + WKUPFR); ++ wkupenr = readl_relaxed(priv->base + MPUWKUPENR); ++ ++ for (i = 0; i < NB_WAKEUPPINS; i++) { ++ if ((wkupfr & BIT(i)) && (wkupenr & BIT(i))) { ++ struct irq_desc *d; ++ ++ d = irq_to_desc(irq_find_mapping(priv->domain, i)); ++ ++ if (priv->wake & BIT(i)) { ++ dev_dbg(priv->dev, ++ "irq %d while wake enabled\n", i); ++ priv->pending |= BIT(i); ++ } ++ ++ dev_dbg(priv->dev, "handle wkup irq:%d\n", i); ++ handle_edge_irq(d); ++ } ++ } ++ chained_irq_exit(chip, desc); ++} ++ ++static int __maybe_unused stm32_pwr_suspend(struct device *dev) ++{ ++ struct stm32_pwr_data *priv = dev_get_drvdata(dev); ++ ++ pr_debug("suspend"); ++ if (priv->pending != 0) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops stm32_pwr_pm = { ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pwr_suspend, NULL) ++}; ++ ++static int stm32_pwr_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct stm32_pwr_data *priv; ++ struct device_node *np = dev->of_node; ++ struct resource *res; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ priv->dev = dev; ++ dev_set_drvdata(dev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->base)) { ++ dev_err(dev, "Unable to map registers\n"); ++ return PTR_ERR(priv->base); ++ } ++ ++ /* Disable all wake-up pins */ ++ SMC(STM32_SVC_PWR, STM32_WRITE, MPUWKUPENR, 0); ++ /* Clear all interrupts flags */ ++ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, WKUP_FLAGS_MASK); ++ ++ priv->domain = irq_domain_add_linear(np, NB_WAKEUPPINS, ++ &stm32_pwr_irq_domain_ops, priv); ++ if (!priv->domain) { ++ dev_err(dev, "%s: Unable to add irq domain!\n", __func__); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = irq_of_parse_and_map(np, 0); ++ if (ret < 0) { ++ dev_err(dev, "failed to get PWR IRQ\n"); ++ ret = priv->irq; ++ goto out_domain; ++ } ++ ++ priv->irq = ret; ++ irq_set_chained_handler_and_data(priv->irq, stm32_pwr_handle_irq, priv); ++ ++ of_node_clear_flag(np, OF_POPULATED); ++ ++ return 0; ++ ++out_domain: ++ irq_domain_remove(priv->domain); ++out: ++ return ret; ++} ++ ++static int stm32_pwr_remove(struct platform_device *pdev) ++{ ++ struct stm32_pwr_data *priv = dev_get_drvdata(&pdev->dev); ++ ++ irq_domain_remove(priv->domain); ++ return 0; ++} ++ ++static const struct of_device_id stm32_pwr_ids[] = { ++ { .compatible = "st,stm32mp1-pwr", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, stm32_pwr_ids); ++ ++static struct platform_driver stm32_pwr_driver = { ++ .probe = stm32_pwr_probe, ++ .remove = stm32_pwr_remove, ++ .driver = { ++ .name = "stm32_pwr", ++ .of_match_table = stm32_pwr_ids, ++ .pm = &stm32_pwr_pm, ++ }, ++}; ++ ++static int __init stm32_pwr_init(void) ++{ ++ return platform_driver_register(&stm32_pwr_driver); ++} ++ ++static void __exit stm32_pwr_exit(void) ++{ ++ return platform_driver_unregister(&stm32_pwr_driver); ++} ++ ++arch_initcall(stm32_pwr_init); ++module_exit(stm32_pwr_exit); +diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c +index efcd4b980..65a160a26 100644 +--- a/drivers/mfd/stm32-timers.c ++++ b/drivers/mfd/stm32-timers.c +@@ -167,26 +167,36 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata) + regmap_write(ddata->regmap, TIM_ARR, 0x0); + } + +-static void stm32_timers_dma_probe(struct device *dev, +- struct stm32_timers *ddata) ++static int stm32_timers_dma_probe(struct device *dev, ++ struct stm32_timers *ddata) + { + int i; ++ int ret = 0; + char name[4]; + + init_completion(&ddata->dma.completion); + mutex_init(&ddata->dma.lock); + +- /* Optional DMA support: get valid DMA channel(s) or NULL */ ++ /* Optional DMA support but report if an existing one fails */ + for (i = STM32_TIMERS_DMA_CH1; i <= STM32_TIMERS_DMA_CH4; i++) { + snprintf(name, ARRAY_SIZE(name), "ch%1d", i + 1); +- ddata->dma.chans[i] = dma_request_slave_channel(dev, name); ++ ddata->dma.chans[i] = dma_request_chan(dev, name); + } +- ddata->dma.chans[STM32_TIMERS_DMA_UP] = +- dma_request_slave_channel(dev, "up"); +- ddata->dma.chans[STM32_TIMERS_DMA_TRIG] = +- dma_request_slave_channel(dev, "trig"); +- ddata->dma.chans[STM32_TIMERS_DMA_COM] = +- dma_request_slave_channel(dev, "com"); ++ ddata->dma.chans[STM32_TIMERS_DMA_UP] = dma_request_chan(dev, "up"); ++ ddata->dma.chans[STM32_TIMERS_DMA_TRIG] = dma_request_chan(dev, "trig"); ++ ddata->dma.chans[STM32_TIMERS_DMA_COM] = dma_request_chan(dev, "com"); ++ ++ for (i = STM32_TIMERS_DMA_CH1; i < STM32_TIMERS_MAX_DMAS; i++) { ++ if (IS_ERR(ddata->dma.chans[i])) { ++ /* Save the first error code to return */ ++ if (PTR_ERR(ddata->dma.chans[i]) != -ENODEV && !ret) ++ ret = PTR_ERR(ddata->dma.chans[i]); ++ ++ ddata->dma.chans[i] = NULL; ++ } ++ } ++ ++ return ret; + } + + static void stm32_timers_dma_remove(struct device *dev, +@@ -230,7 +240,11 @@ static int stm32_timers_probe(struct platform_device *pdev) + + stm32_timers_get_arr_size(ddata); + +- stm32_timers_dma_probe(dev, ddata); ++ ret = stm32_timers_dma_probe(dev, ddata); ++ if (ret) { ++ stm32_timers_dma_remove(dev, ddata); ++ return ret; ++ } + + platform_set_drvdata(pdev, ddata); + +diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c +index 857991cb3..711979afd 100644 +--- a/drivers/mfd/stmfx.c ++++ b/drivers/mfd/stmfx.c +@@ -287,14 +287,21 @@ static int stmfx_irq_init(struct i2c_client *client) + + ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); + if (ret) +- return ret; ++ goto irq_exit; + + ret = devm_request_threaded_irq(stmfx->dev, client->irq, + NULL, stmfx_irq_handler, + irqtrigger | IRQF_ONESHOT, + "stmfx", stmfx); + if (ret) +- stmfx_irq_exit(client); ++ goto irq_exit; ++ ++ stmfx->irq = client->irq; ++ ++ return 0; ++ ++irq_exit: ++ stmfx_irq_exit(client); + + return ret; + } +@@ -481,6 +488,8 @@ static int stmfx_suspend(struct device *dev) + if (ret) + return ret; + ++ disable_irq(stmfx->irq); ++ + if (stmfx->vdd) + return regulator_disable(stmfx->vdd); + +@@ -501,6 +510,13 @@ static int stmfx_resume(struct device *dev) + } + } + ++ /* Reset STMFX - supply has been stopped during suspend */ ++ ret = stmfx_chip_reset(stmfx); ++ if (ret) { ++ dev_err(stmfx->dev, "Failed to reset chip: %d\n", ret); ++ return ret; ++ } ++ + ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL, + &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); + if (ret) +@@ -517,6 +533,8 @@ static int stmfx_resume(struct device *dev) + if (ret) + return ret; + ++ enable_irq(stmfx->irq); ++ + return 0; + } + #endif +diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c +index 7dfbe8906..766c3217f 100644 +--- a/drivers/mfd/stpmic1.c ++++ b/drivers/mfd/stpmic1.c +@@ -170,6 +170,9 @@ static int stpmic1_suspend(struct device *dev) + + disable_irq(pmic_dev->irq); + ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(pmic_dev->irq); ++ + return 0; + } + +@@ -183,6 +186,9 @@ static int stpmic1_resume(struct device *dev) + if (ret) + return ret; + ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(pmic_dev->irq); ++ + enable_irq(pmic_dev->irq); + + return 0; +diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c +index 1e9fe7d92..b110c8ac1 100644 +--- a/drivers/mfd/wm8994-core.c ++++ b/drivers/mfd/wm8994-core.c +@@ -7,6 +7,7 @@ + * Author: Mark Brown + */ + ++#include + #include + #include + #include +@@ -185,6 +186,12 @@ static int wm8994_resume(struct device *dev) + if (!wm8994->suspended) + return 0; + ++ /* ++ * LDO1/2 minimum cycle time is 36ms according to codec specification ++ * Wait before enabling regulator to make sure we fit this requirement ++ */ ++ msleep(40); ++ + ret = regulator_bulk_enable(wm8994->num_supplies, + wm8994->supplies); + if (ret != 0) { +@@ -300,6 +307,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) + + pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd"); + ++ ++ pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1"); ++ if (IS_ERR(pdata->mclk1)) { ++ if (PTR_ERR(pdata->mclk1) != -ENOENT) ++ return PTR_ERR(pdata->mclk1); ++ pdata->mclk1 = NULL; ++ } ++ ++ pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2"); ++ if (IS_ERR(pdata->mclk2)) { ++ if (PTR_ERR(pdata->mclk2) != -ENOENT) ++ return PTR_ERR(pdata->mclk2); ++ pdata->mclk2 = NULL; ++ } + return 0; + } + #else +diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h +index 067d14655..f8db83aed 100644 +--- a/include/linux/mfd/stm32-timers.h ++++ b/include/linux/mfd/stm32-timers.h +@@ -70,14 +70,11 @@ + #define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */ + #define TIM_CCER_CC4P BIT(13) /* Capt/Comp 4 Polarity */ + #define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12)) +-#define TIM_BDTR_BKE BIT(12) /* Break input enable */ +-#define TIM_BDTR_BKP BIT(13) /* Break input polarity */ ++#define TIM_BDTR_BKE(x) BIT(12 + (x) * 12) /* Break input enable */ ++#define TIM_BDTR_BKP(x) BIT(13 + (x) * 12) /* Break input polarity */ + #define TIM_BDTR_AOE BIT(14) /* Automatic Output Enable */ + #define TIM_BDTR_MOE BIT(15) /* Main Output Enable */ +-#define TIM_BDTR_BKF (BIT(16) | BIT(17) | BIT(18) | BIT(19)) +-#define TIM_BDTR_BK2F (BIT(20) | BIT(21) | BIT(22) | BIT(23)) +-#define TIM_BDTR_BK2E BIT(24) /* Break 2 input enable */ +-#define TIM_BDTR_BK2P BIT(25) /* Break 2 input polarity */ ++#define TIM_BDTR_BKF(x) (0xf << (16 + (x) * 4)) + #define TIM_DCR_DBA GENMASK(4, 0) /* DMA base addr */ + #define TIM_DCR_DBL GENMASK(12, 8) /* DMA burst len */ + +@@ -87,8 +84,7 @@ + #define TIM_CR2_MMS2_SHIFT 20 + #define TIM_SMCR_TS_SHIFT 4 + #define TIM_BDTR_BKF_MASK 0xF +-#define TIM_BDTR_BKF_SHIFT 16 +-#define TIM_BDTR_BK2F_SHIFT 20 ++#define TIM_BDTR_BKF_SHIFT(x) (16 + (x) * 4) + + enum stm32_timers_dmas { + STM32_TIMERS_DMA_CH1, +diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h +index 3c6798367..744dce639 100644 +--- a/include/linux/mfd/stmfx.h ++++ b/include/linux/mfd/stmfx.h +@@ -109,6 +109,7 @@ struct stmfx { + struct device *dev; + struct regmap *map; + struct regulator *vdd; ++ int irq; + struct irq_domain *irq_domain; + struct mutex lock; /* IRQ bus lock */ + u8 irq_src; +diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h +index 81e7dcbd9..addb2fede 100644 +--- a/include/linux/mfd/wm8994/pdata.h ++++ b/include/linux/mfd/wm8994/pdata.h +@@ -231,6 +231,12 @@ struct wm8994_pdata { + * GPIO for the IRQ pin if host only supports edge triggering + */ + int irq_gpio; ++ ++ /* MCLK1 clock provider */ ++ struct clk *mclk1; ++ ++ /* MCLK2 clock provider */ ++ struct clk *mclk2; + }; + + #endif +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch new file mode 100644 index 0000000..8ebd040 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch @@ -0,0 +1,1187 @@ +From 157e4fd4d369ee81ded975d5ccd3d7c56cb045d0 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:45:40 +0200 +Subject: [PATCH 14/23] ARM-stm32mp1-r1-MMC-NAND + +--- + drivers/mmc/core/block.c | 11 + + drivers/mmc/core/core.c | 31 ++- + drivers/mmc/host/mmci.c | 281 +++++++++++++++++-------- + drivers/mmc/host/mmci.h | 17 +- + drivers/mmc/host/mmci_stm32_sdmmc.c | 259 +++++++++++++++++++++-- + drivers/mtd/nand/raw/nand_base.c | 2 + + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 46 +++- + include/linux/mmc/core.h | 1 + + include/linux/mmc/host.h | 6 + + 9 files changed, 537 insertions(+), 117 deletions(-) + +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 95b41c089..d6a7cc042 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -1762,6 +1762,17 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) + u32 blocks; + int err; + ++ /* ++ * the host is in a bad state, and can't sent a new command ++ * without be unstuck ++ */ ++ if (brq->sbc.error == -EDEADLK || brq->cmd.error == -EDEADLK || ++ brq->stop.error == -EDEADLK || brq->data.error == -EDEADLK) { ++ pr_err("%s: host is in bad state, must be unstuck\n", ++ req->rq_disk->disk_name); ++ mmc_hw_unstuck(card->host); ++ } ++ + /* + * Some errors the host driver might not have seen. Set the number of + * bytes transferred to zero in that case. +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 26644b7ec..6d00eed17 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -397,6 +397,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) + void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + { + struct mmc_command *cmd; ++ int sbc_err, stop_err, data_err; + + while (1) { + wait_for_completion(&mrq->completion); +@@ -420,8 +421,20 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + mmc_hostname(host), __func__); + } + } +- if (!cmd->error || !cmd->retries || +- mmc_card_removed(host->card)) ++ ++ sbc_err = mrq->sbc ? mrq->sbc->error : 0; ++ stop_err = mrq->stop ? mrq->stop->error : 0; ++ data_err = mrq->data ? mrq->data->error : 0; ++ ++ if (cmd->error == -EDEADLK || sbc_err == -EDEADLK || ++ stop_err == -EDEADLK || data_err == -EDEADLK) { ++ pr_debug("%s: host is in bad state, must be unstuck\n", ++ mmc_hostname(host)); ++ mmc_hw_unstuck(host); ++ } ++ ++ if ((!cmd->error && !sbc_err && !stop_err && !data_err) || ++ !cmd->retries || mmc_card_removed(host->card)) + break; + + mmc_retune_recheck(host); +@@ -430,6 +443,12 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + mmc_hostname(host), cmd->opcode, cmd->error); + cmd->retries--; + cmd->error = 0; ++ if (mrq->sbc) ++ mrq->sbc->error = 0; ++ if (mrq->stop) ++ mrq->stop->error = 0; ++ if (mrq->data) ++ mrq->data->error = 0; + __mmc_start_request(host, mrq); + } + +@@ -2163,6 +2182,14 @@ int mmc_sw_reset(struct mmc_host *host) + } + EXPORT_SYMBOL(mmc_sw_reset); + ++void mmc_hw_unstuck(struct mmc_host *host) ++{ ++ if (!host->ops->hw_unstuck) ++ return; ++ host->ops->hw_unstuck(host); ++} ++EXPORT_SYMBOL(mmc_hw_unstuck); ++ + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) + { + host->f_init = freq; +diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c +index c37e70dbe..d4b7880fc 100644 +--- a/drivers/mmc/host/mmci.c ++++ b/drivers/mmc/host/mmci.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -44,6 +45,7 @@ + #define DRIVER_NAME "mmci-pl18x" + + static void mmci_variant_init(struct mmci_host *host); ++static void ux500_variant_init(struct mmci_host *host); + static void ux500v2_variant_init(struct mmci_host *host); + + static unsigned int fmax = 515633; +@@ -175,7 +177,6 @@ static struct variant_data variant_ux500 = { + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, +- .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, +@@ -184,7 +185,7 @@ static struct variant_data variant_ux500 = { + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, +- .init = mmci_variant_init, ++ .init = ux500_variant_init, + }; + + static struct variant_data variant_ux500v2 = { +@@ -208,7 +209,6 @@ static struct variant_data variant_ux500v2 = { + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, +- .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, +@@ -260,7 +260,38 @@ static struct variant_data variant_stm32_sdmmc = { + .datacnt_useless = true, + .datalength_bits = 25, + .datactrl_blocksz = 14, ++ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, ++ .pwrreg_nopower = true, + .stm32_idmabsize_mask = GENMASK(12, 5), ++ .busy_timeout = true, ++ .busy_detect_flag = MCI_STM32_BUSYD0, ++ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, ++ .init = sdmmc_variant_init, ++}; ++ ++static struct variant_data variant_stm32_sdmmcv2 = { ++ .fifosize = 16 * 4, ++ .fifohalfsize = 8 * 4, ++ .f_max = 208000000, ++ .stm32_clkdiv = true, ++ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, ++ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, ++ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, ++ .cmdreg_srsp = MCI_CPSM_STM32_SRSP, ++ .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, ++ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, ++ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, ++ .datactrl_first = true, ++ .datacnt_useless = true, ++ .datalength_bits = 25, ++ .datactrl_blocksz = 14, ++ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, ++ .pwrreg_nopower = true, ++ .stm32_idmabsize_mask = GENMASK(16, 5), ++ .dma_lli = true, ++ .busy_timeout = true, ++ .busy_detect_flag = MCI_STM32_BUSYD0, ++ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, + .init = sdmmc_variant_init, + }; + +@@ -357,6 +388,24 @@ static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) + } + } + ++static void mmci_restore(struct mmci_host *host) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->variant->pwrreg_nopower) { ++ writel(host->clk_reg, host->base + MMCICLOCK); ++ writel(host->datactrl_reg, host->base + MMCIDATACTRL); ++ writel(host->pwr_reg, host->base + MMCIPOWER); ++ } ++ writel(MCI_IRQENABLE | host->variant->start_err, ++ host->base + MMCIMASK0); ++ mmci_reg_delay(host); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ + /* + * This must be called with host->lock held + */ +@@ -450,7 +499,8 @@ static int mmci_validate_data(struct mmci_host *host, + if (!data) + return 0; + +- if (!is_power_of_2(data->blksz)) { ++ if ((host->mmc->card && !mmc_card_sdio(host->mmc->card)) && ++ !is_power_of_2(data->blksz)) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; +@@ -610,6 +660,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) + return MCI_DPSM_ENABLE | (host->data->blksz << 16); + } + ++static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) ++{ ++ void __iomem *base = host->base; ++ ++ /* ++ * Before unmasking for the busy end IRQ, confirm that the ++ * command was sent successfully. To keep track of having a ++ * command in-progress, waiting for busy signaling to end, ++ * store the status in host->busy_status. ++ * ++ * Note that, the card may need a couple of clock cycles before ++ * it starts signaling busy on DAT0, hence re-read the ++ * MMCISTATUS register here, to allow the busy bit to be set. ++ * Potentially we may even need to poll the register for a ++ * while, to allow it to be set, but tests indicates that it ++ * isn't needed. ++ */ ++ if (!host->busy_status && !(status & err_msk) && ++ (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { ++ writel(readl(base + MMCIMASK0) | ++ host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ ++ host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); ++ return false; ++ } ++ ++ /* ++ * If there is a command in-progress that has been successfully ++ * sent, then bail out if busy status is set and wait for the ++ * busy end IRQ. ++ * ++ * Note that, the HW triggers an IRQ on both edges while ++ * monitoring DAT0 for busy completion, but there is only one ++ * status bit in MMCISTATUS for the busy state. Therefore ++ * both the start and the end interrupts needs to be cleared, ++ * one after the other. So, clear the busy start IRQ here. ++ */ ++ if (host->busy_status && ++ (status & host->variant->busy_detect_flag)) { ++ writel(host->variant->busy_detect_mask, base + MMCICLEAR); ++ return false; ++ } ++ ++ /* ++ * If there is a command in-progress that has been successfully ++ * sent and the busy bit isn't set, it means we have received ++ * the busy end IRQ. Clear and mask the IRQ, then continue to ++ * process the command. ++ */ ++ if (host->busy_status) { ++ writel(host->variant->busy_detect_mask, base + MMCICLEAR); ++ ++ writel(readl(base + MMCIMASK0) & ++ ~host->variant->busy_detect_mask, base + MMCIMASK0); ++ host->busy_status = 0; ++ } ++ ++ return true; ++} ++ + /* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, +@@ -953,9 +1064,16 @@ void mmci_variant_init(struct mmci_host *host) + host->ops = &mmci_variant_ops; + } + ++void ux500_variant_init(struct mmci_host *host) ++{ ++ host->ops = &mmci_variant_ops; ++ host->ops->busy_complete = ux500_busy_complete; ++} ++ + void ux500v2_variant_init(struct mmci_host *host) + { + host->ops = &mmci_variant_ops; ++ host->ops->busy_complete = ux500_busy_complete; + host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; + } + +@@ -1075,6 +1193,7 @@ static void + mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) + { + void __iomem *base = host->base; ++ unsigned long long clks; + + dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", + cmd->opcode, cmd->arg, cmd->flags); +@@ -1097,6 +1216,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) + else + c |= host->variant->cmdreg_srsp; + } ++ ++ if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { ++ if (!cmd->busy_timeout) ++ cmd->busy_timeout = 1000; ++ ++ clks = (unsigned long long)cmd->busy_timeout * host->cclk; ++ do_div(clks, MSEC_PER_SEC); ++ writel_relaxed(clks, host->base + MMCIDATATIMER); ++ } ++ ++ if (host->ops->prep_volt_switch && cmd->opcode == SD_SWITCH_VOLTAGE) ++ host->ops->prep_volt_switch(host); ++ + if (/*interrupt*/0) + c |= MCI_CPSM_INTERRUPT; + +@@ -1201,6 +1333,7 @@ static void + mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + unsigned int status) + { ++ u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; + void __iomem *base = host->base; + bool sbc, busy_resp; + +@@ -1215,74 +1348,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + * handling. Note that we tag on any latent IRQs postponed + * due to waiting for busy status. + */ +- if (!((status|host->busy_status) & +- (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) ++ if (host->variant->busy_timeout && busy_resp) ++ err_msk |= MCI_DATATIMEOUT; ++ ++ if (!((status | host->busy_status) & ++ (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) + return; + + /* Handle busy detection on DAT0 if the variant supports it. */ +- if (busy_resp && host->variant->busy_detect) { +- +- /* +- * Before unmasking for the busy end IRQ, confirm that the +- * command was sent successfully. To keep track of having a +- * command in-progress, waiting for busy signaling to end, +- * store the status in host->busy_status. +- * +- * Note that, the card may need a couple of clock cycles before +- * it starts signaling busy on DAT0, hence re-read the +- * MMCISTATUS register here, to allow the busy bit to be set. +- * Potentially we may even need to poll the register for a +- * while, to allow it to be set, but tests indicates that it +- * isn't needed. +- */ +- if (!host->busy_status && +- !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && +- (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { +- +- writel(readl(base + MMCIMASK0) | +- host->variant->busy_detect_mask, +- base + MMCIMASK0); +- +- host->busy_status = +- status & (MCI_CMDSENT|MCI_CMDRESPEND); ++ if (busy_resp && host->ops->busy_complete) ++ if (!host->ops->busy_complete(host, status, err_msk)) + return; +- } +- +- /* +- * If there is a command in-progress that has been successfully +- * sent, then bail out if busy status is set and wait for the +- * busy end IRQ. +- * +- * Note that, the HW triggers an IRQ on both edges while +- * monitoring DAT0 for busy completion, but there is only one +- * status bit in MMCISTATUS for the busy state. Therefore +- * both the start and the end interrupts needs to be cleared, +- * one after the other. So, clear the busy start IRQ here. +- */ +- if (host->busy_status && +- (status & host->variant->busy_detect_flag)) { +- writel(host->variant->busy_detect_mask, +- host->base + MMCICLEAR); +- return; +- } +- +- /* +- * If there is a command in-progress that has been successfully +- * sent and the busy bit isn't set, it means we have received +- * the busy end IRQ. Clear and mask the IRQ, then continue to +- * process the command. +- */ +- if (host->busy_status) { +- +- writel(host->variant->busy_detect_mask, +- host->base + MMCICLEAR); +- +- writel(readl(base + MMCIMASK0) & +- ~host->variant->busy_detect_mask, +- base + MMCIMASK0); +- host->busy_status = 0; +- } +- } + + host->cmd = NULL; + +@@ -1290,6 +1366,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + cmd->error = -ETIMEDOUT; + } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { + cmd->error = -EILSEQ; ++ } else if (host->variant->busy_timeout && busy_resp && ++ status & MCI_DATATIMEOUT) { ++ cmd->error = -EDEADLK; + } else { + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); +@@ -1301,7 +1380,6 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + if (host->data) { + /* Terminate the DMA transfer */ + mmci_dma_error(host); +- + mmci_stop_data(host); + if (host->variant->cmdreg_stop && cmd->error) { + mmci_stop_command(host); +@@ -1520,7 +1598,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) + * clear the corresponding IRQ. + */ + status &= readl(host->base + MMCIMASK0); +- if (host->variant->busy_detect) ++ if (host->ops->busy_complete) + writel(status & ~host->variant->busy_detect_mask, + host->base + MMCICLEAR); + else +@@ -1583,6 +1661,20 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) + spin_unlock_irqrestore(&host->lock, flags); + } + ++static void mmci_set_max_busy_timeout(struct mmc_host *mmc) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ u32 max_busy_timeout = 0; ++ ++ if (!host->ops->busy_complete) ++ return; ++ ++ if (host->variant->busy_timeout && mmc->actual_clock) ++ max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); ++ ++ mmc->max_busy_timeout = max_busy_timeout; ++} ++ + static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { + struct mmci_host *host = mmc_priv(mmc); +@@ -1687,6 +1779,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + else + mmci_set_clkreg(host, ios->clock); + ++ mmci_set_max_busy_timeout(mmc); ++ + if (host->ops && host->ops->set_pwrreg) + host->ops->set_pwrreg(host, pwr); + else +@@ -1714,6 +1808,7 @@ static int mmci_get_cd(struct mmc_host *mmc) + + static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + { ++ struct mmci_host *host = mmc_priv(mmc); + int ret = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { +@@ -1733,6 +1828,9 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + break; + } + ++ if (!ret && host->ops && host->ops->volt_switch) ++ ret = host->ops->volt_switch(host, ios); ++ + if (ret) + dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); + } +@@ -1740,6 +1838,19 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + return ret; + } + ++static void mmci_hw_unstuck(struct mmc_host *mmc) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ ++ if (host->rst) { ++ reset_control_assert(host->rst); ++ udelay(2); ++ reset_control_deassert(host->rst); ++ } ++ ++ mmci_restore(host); ++} ++ + static struct mmc_host_ops mmci_ops = { + .request = mmci_request, + .pre_req = mmci_pre_request, +@@ -1748,6 +1859,7 @@ static struct mmc_host_ops mmci_ops = { + .get_ro = mmc_gpio_get_ro, + .get_cd = mmci_get_cd, + .start_signal_voltage_switch = mmci_sig_volt_switch, ++ .hw_unstuck = mmci_hw_unstuck, + }; + + static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) +@@ -1817,6 +1929,7 @@ static int mmci_probe(struct amba_device *dev, + + host = mmc_priv(mmc); + host->mmc = mmc; ++ host->mmc_ops = &mmci_ops; + + /* + * Some variant (STM32) doesn't have opendrain bit, nevertheless +@@ -1941,13 +2054,15 @@ static int mmci_probe(struct amba_device *dev, + else if (plat->ocr_mask) + dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); + ++ host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); ++ + /* We support these capabilities. */ + mmc->caps |= MMC_CAP_CMD23; + + /* + * Enable busy detection. + */ +- if (variant->busy_detect) { ++ if (host->ops->busy_complete) { + mmci_ops.card_busy = mmci_card_busy; + /* + * Not all variants have a flag to enable busy detection +@@ -1957,7 +2072,6 @@ static int mmci_probe(struct amba_device *dev, + mmci_write_datactrlreg(host, + host->variant->busy_dpsm_flag); + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; +- mmc->max_busy_timeout = 0; + } + + /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ +@@ -2115,24 +2229,6 @@ static void mmci_save(struct mmci_host *host) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void mmci_restore(struct mmci_host *host) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&host->lock, flags); +- +- if (host->variant->pwrreg_nopower) { +- writel(host->clk_reg, host->base + MMCICLOCK); +- writel(host->datactrl_reg, host->base + MMCIDATACTRL); +- writel(host->pwr_reg, host->base + MMCIPOWER); +- } +- writel(MCI_IRQENABLE | host->variant->start_err, +- host->base + MMCIMASK0); +- mmci_reg_delay(host); +- +- spin_unlock_irqrestore(&host->lock, flags); +-} +- + static int mmci_runtime_suspend(struct device *dev) + { + struct amba_device *adev = to_amba_device(dev); +@@ -2227,6 +2323,11 @@ static const struct amba_id mmci_ids[] = { + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmc, + }, ++ { ++ .id = 0x00253180, ++ .mask = 0xf0ffffff, ++ .data = &variant_stm32_sdmmcv2, ++ }, + /* Qualcomm variants */ + { + .id = 0x00051180, +diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h +index 833236ecb..ed12592cc 100644 +--- a/drivers/mmc/host/mmci.h ++++ b/drivers/mmc/host/mmci.h +@@ -133,6 +133,8 @@ + #define MCI_DPSM_STM32_MODE_SDIO (1 << 2) + #define MCI_DPSM_STM32_MODE_STREAM (2 << 2) + #define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2) ++#define MCI_DPSM_STM32_SDIOEN BIT(11) ++ + + #define MMCIDATACNT 0x030 + #define MMCISTATUS 0x034 +@@ -164,6 +166,8 @@ + #define MCI_ST_CARDBUSY (1 << 24) + /* Extended status bits for the STM32 variants */ + #define MCI_STM32_BUSYD0 BIT(20) ++#define MCI_STM32_BUSYD0END BIT(21) ++#define MCI_STM32_VSWEND BIT(25) + + #define MMCICLEAR 0x038 + #define MCI_CMDCRCFAILCLR (1 << 0) +@@ -181,6 +185,9 @@ + #define MCI_ST_SDIOITC (1 << 22) + #define MCI_ST_CEATAENDC (1 << 23) + #define MCI_ST_BUSYENDC (1 << 24) ++/* Extended clear bits for the STM32 variants */ ++#define MCI_STM32_VSWENDC (1 << 25) ++#define MCI_STM32_CKSTOPC (1 << 26) + + #define MMCIMASK0 0x03c + #define MCI_CMDCRCFAILMASK (1 << 0) +@@ -286,7 +293,8 @@ struct mmci_host; + * @f_max: maximum clk frequency supported by the controller. + * @signal_direction: input/out direction of bus signals can be indicated + * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock +- * @busy_detect: true if the variant supports busy detection on DAT0. ++ * @busy_timeout: true if the variant starts data timer when the DPSM ++ * enter in Wait_R or Busy state. + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register + * indicating that the card is busy +@@ -332,7 +340,7 @@ struct variant_data { + u32 f_max; + u8 signal_direction:1; + u8 pwrreg_clkgate:1; +- u8 busy_detect:1; ++ u8 busy_timeout:1; + u32 busy_dpsm_flag; + u32 busy_detect_flag; + u32 busy_detect_mask; +@@ -366,6 +374,9 @@ struct mmci_host_ops { + void (*dma_error)(struct mmci_host *host); + void (*set_clkreg)(struct mmci_host *host, unsigned int desired); + void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); ++ bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk); ++ void (*prep_volt_switch)(struct mmci_host *host); ++ int (*volt_switch)(struct mmci_host *host, struct mmc_ios *ios); + }; + + struct mmci_host { +@@ -396,8 +407,10 @@ struct mmci_host { + u32 mask1_reg; + u8 vqmmc_enabled:1; + struct mmci_platform_data *plat; ++ struct mmc_host_ops *mmc_ops; + struct mmci_host_ops *ops; + struct variant_data *variant; ++ void *variant_priv; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_opendrain; +diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c +index 8e83ae692..7c6ba518b 100644 +--- a/drivers/mmc/host/mmci_stm32_sdmmc.c ++++ b/drivers/mmc/host/mmci_stm32_sdmmc.c +@@ -3,10 +3,13 @@ + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Ludovic.barre@st.com for STMicroelectronics. + */ ++#include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include "mmci.h" +@@ -14,17 +17,36 @@ + #define SDMMC_LLI_BUF_LEN PAGE_SIZE + #define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) + ++#define DLYB_CR 0x0 ++#define DLYB_CR_DEN BIT(0) ++#define DLYB_CR_SEN BIT(1) ++ ++#define DLYB_CFGR 0x4 ++#define DLYB_CFGR_SEL_MASK GENMASK(3, 0) ++#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8) ++#define DLYB_CFGR_LNG_MASK GENMASK(27, 16) ++#define DLYB_CFGR_LNGF BIT(31) ++ ++#define DLYB_CFGR_SEL_MAX 12 ++#define DLYB_CFGR_UNIT_MAX 127 ++ + struct sdmmc_lli_desc { + u32 idmalar; + u32 idmabase; + u32 idmasize; + }; + +-struct sdmmc_priv { ++struct sdmmc_idma { + dma_addr_t sg_dma; + void *sg_cpu; + }; + ++struct sdmmc_dlyb { ++ void __iomem *base; ++ u32 unit; ++ u32 max; ++}; ++ + int sdmmc_idma_validate_data(struct mmci_host *host, + struct mmc_data *data) + { +@@ -36,8 +58,8 @@ int sdmmc_idma_validate_data(struct mmci_host *host, + * excepted the last element which has no constraint on idmasize + */ + for_each_sg(data->sg, sg, data->sg_len - 1, i) { +- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) || +- !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) { ++ if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) || ++ !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) { + dev_err(mmc_dev(host->mmc), + "unaligned scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); +@@ -45,7 +67,7 @@ int sdmmc_idma_validate_data(struct mmci_host *host, + } + } + +- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) { ++ if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) { + dev_err(mmc_dev(host->mmc), + "unaligned last scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); +@@ -92,21 +114,21 @@ static void sdmmc_idma_unprep_data(struct mmci_host *host, + + static int sdmmc_idma_setup(struct mmci_host *host) + { +- struct sdmmc_priv *idma; ++ struct sdmmc_idma *idma; ++ struct device *dev = mmc_dev(host->mmc); + +- idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); +- if (!idma) ++ idma = devm_kzalloc(dev, sizeof(*idma), GFP_KERNEL); ++ dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); ++ if (!idma || !dev->dma_parms) + return -ENOMEM; + + host->dma_priv = idma; + + if (host->variant->dma_lli) { +- idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), +- SDMMC_LLI_BUF_LEN, ++ idma->sg_cpu = dmam_alloc_coherent(dev, SDMMC_LLI_BUF_LEN, + &idma->sg_dma, GFP_KERNEL); + if (!idma->sg_cpu) { +- dev_err(mmc_dev(host->mmc), +- "Failed to alloc IDMA descriptor\n"); ++ dev_err(dev, "Failed to alloc IDMA descriptor\n"); + return -ENOMEM; + } + host->mmc->max_segs = SDMMC_LLI_BUF_LEN / +@@ -117,13 +139,15 @@ static int sdmmc_idma_setup(struct mmci_host *host) + host->mmc->max_seg_size = host->mmc->max_req_size; + } + ++ dma_set_max_seg_size(dev, host->mmc->max_seg_size); ++ + return 0; + } + + static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) + + { +- struct sdmmc_priv *idma = host->dma_priv; ++ struct sdmmc_idma *idma = host->dma_priv; + struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; + struct mmc_data *data = host->data; + struct scatterlist *sg; +@@ -162,6 +186,9 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) + static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) + { + writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); ++ ++ if (!data->host_cookie) ++ sdmmc_idma_unprep_data(host, data, 0); + } + + static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) +@@ -226,12 +253,25 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) + mmci_write_clkreg(host, clk); + } + ++static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb) ++{ ++ if (!dlyb || !dlyb->base) ++ return; ++ ++ /* Output clock = Input clock */ ++ writel_relaxed(0, dlyb->base + DLYB_CR); ++} ++ + static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) + { + struct mmc_ios ios = host->mmc->ios; ++ struct sdmmc_dlyb *dlyb = host->variant_priv; + ++ /* adds OF options */ + pwr = host->pwr_reg_add; + ++ sdmmc_dlyb_input_ck(dlyb); ++ + if (ios.power_mode == MMC_POWER_OFF) { + /* Only a reset could power-off sdmmc */ + reset_control_assert(host->rst); +@@ -254,6 +294,10 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); + ++ /* preserves voltage switch bits */ ++ pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN | ++ MCI_STM32_VSWITCH); ++ + /* + * After a power-cycle state, we must set the SDMMC in + * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are +@@ -282,6 +326,178 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) + return datactrl; + } + ++bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) ++{ ++ void __iomem *base = host->base; ++ u32 busy_d0, busy_d0end, mask; ++ ++ mask = readl_relaxed(base + MMCIMASK0); ++ busy_d0end = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0END; ++ busy_d0 = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0; ++ ++ /* complete if there is an error or busy_d0end */ ++ if ((status & err_msk) || busy_d0end) ++ goto complete; ++ ++ /* ++ * On response the busy signaling is reflected in the BUSYD0 flag. ++ * if busy_d0 is in-progress we must activate busyd0end interrupt ++ * to wait this completion. Else this request has no busy step. ++ */ ++ if (busy_d0) { ++ if (!host->busy_status) { ++ writel_relaxed(mask | host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ host->busy_status = status & ++ (MCI_CMDSENT | MCI_CMDRESPEND); ++ } ++ return false; ++ } ++ ++complete: ++ writel_relaxed(mask & ~host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ writel_relaxed(host->variant->busy_detect_mask, base + MMCICLEAR); ++ host->busy_status = 0; ++ ++ return true; ++} ++ ++static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, ++ int unit, int phase, bool sampler) ++{ ++ u32 cfgr; ++ ++ writel_relaxed(DLYB_CR_SEN | DLYB_CR_DEN, dlyb->base + DLYB_CR); ++ ++ cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) | ++ FIELD_PREP(DLYB_CFGR_SEL_MASK, phase); ++ writel_relaxed(cfgr, dlyb->base + DLYB_CFGR); ++ ++ if (!sampler) ++ writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); ++} ++ ++static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) ++{ ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ u32 cfgr; ++ int i, lng, ret; ++ ++ for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { ++ sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true); ++ ++ ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, ++ (cfgr & DLYB_CFGR_LNGF), ++ 1, 1000); ++ if (ret) { ++ dev_warn(mmc_dev(host->mmc), ++ "delay line cfg timeout unit:%d cfgr:%d\n", ++ i, cfgr); ++ continue; ++ } ++ ++ lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr); ++ if (lng < (BIT(11) | BIT(10)) && (lng & ~BIT(11)) > 0) ++ break; ++ } ++ ++ if (i > DLYB_CFGR_UNIT_MAX) ++ return -EINVAL; ++ ++ dlyb->unit = i; ++ dlyb->max = __fls(lng & ~BIT(11)); ++ ++ return 0; ++} ++ ++static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) ++{ ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ int cur_len = 0, max_len = 0, end_of_len = 0; ++ int phase; ++ ++ for (phase = 0; phase <= dlyb->max; phase++) { ++ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ++ ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) { ++ cur_len = 0; ++ } else { ++ cur_len++; ++ if (cur_len > max_len) { ++ max_len = cur_len; ++ end_of_len = phase; ++ } ++ } ++ } ++ ++ if (!max_len) { ++ dev_err(mmc_dev(host->mmc), "no tuning point found\n"); ++ return -EINVAL; ++ } ++ ++ writel_relaxed(0, dlyb->base + DLYB_CR); ++ ++ phase = end_of_len - max_len / 2; ++ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ++ ++ dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", ++ dlyb->unit, dlyb->max, phase); ++ ++ return 0; ++} ++ ++static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ ++ if (!dlyb || !dlyb->base) ++ return -EINVAL; ++ ++ if (sdmmc_dlyb_lng_tuning(host)) ++ return -EINVAL; ++ ++ return sdmmc_dlyb_phase_tuning(host, opcode); ++} ++ ++static void sdmmc_prep_vswitch(struct mmci_host *host) ++{ ++ /* clear the voltage switch completion flag */ ++ writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR); ++ /* enable Voltage switch procedure */ ++ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); ++} ++ ++static int sdmmc_vswitch(struct mmci_host *host, struct mmc_ios *ios) ++{ ++ unsigned long flags; ++ u32 status; ++ int ret = 0; ++ ++ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { ++ spin_lock_irqsave(&host->lock, flags); ++ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ /* wait voltage switch completion while 10ms */ ++ ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS, ++ status, ++ (status & MCI_STM32_VSWEND), ++ 10, 10000); ++ ++ writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, ++ host->base + MMCICLEAR); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ mmci_write_pwrreg(host, host->pwr_reg & ++ ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++ ++ return ret; ++} ++ + static struct mmci_host_ops sdmmc_variant_ops = { + .validate_data = sdmmc_idma_validate_data, + .prep_data = sdmmc_idma_prep_data, +@@ -292,9 +508,28 @@ static struct mmci_host_ops sdmmc_variant_ops = { + .dma_finalize = sdmmc_idma_finalize, + .set_clkreg = mmci_sdmmc_set_clkreg, + .set_pwrreg = mmci_sdmmc_set_pwrreg, ++ .busy_complete = sdmmc_busy_complete, ++ .prep_volt_switch = sdmmc_prep_vswitch, ++ .volt_switch = sdmmc_vswitch, + }; + + void sdmmc_variant_init(struct mmci_host *host) + { ++ struct device_node *np = host->mmc->parent->of_node; ++ void __iomem *base_dlyb; ++ struct sdmmc_dlyb *dlyb; ++ + host->ops = &sdmmc_variant_ops; ++ ++ base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); ++ if (IS_ERR(base_dlyb)) ++ return; ++ ++ dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL); ++ if (!dlyb) ++ return; ++ ++ dlyb->base = base_dlyb; ++ host->variant_priv = dlyb; ++ host->mmc_ops->execute_tuning = sdmmc_execute_tuning; + } +diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c +index f64e3b660..47c63968f 100644 +--- a/drivers/mtd/nand/raw/nand_base.c ++++ b/drivers/mtd/nand/raw/nand_base.c +@@ -5907,6 +5907,8 @@ void nand_cleanup(struct nand_chip *chip) + chip->ecc.algo == NAND_ECC_BCH) + nand_bch_free((struct nand_bch_control *)chip->ecc.priv); + ++ nanddev_cleanup(&chip->base); ++ + /* Free bad block table memory */ + kfree(chip->bbt); + kfree(chip->data_buf); +diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c +index 5c06e0b4d..982b1935d 100644 +--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c ++++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c +@@ -1606,17 +1606,36 @@ static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, + /* DMA configuration */ + static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) + { +- int ret; ++ struct dma_chan *rx, *tx, *ecc; ++ int ret = 0; + +- fmc2->dma_tx_ch = dma_request_slave_channel(fmc2->dev, "tx"); +- fmc2->dma_rx_ch = dma_request_slave_channel(fmc2->dev, "rx"); +- fmc2->dma_ecc_ch = dma_request_slave_channel(fmc2->dev, "ecc"); ++ tx = dma_request_chan(fmc2->dev, "tx"); ++ rx = dma_request_chan(fmc2->dev, "rx"); ++ ecc = dma_request_chan(fmc2->dev, "ecc"); + +- if (!fmc2->dma_tx_ch || !fmc2->dma_rx_ch || !fmc2->dma_ecc_ch) { +- dev_warn(fmc2->dev, "DMAs not defined in the device tree, polling mode is used\n"); +- return 0; ++ /* DMAs are not mandatory but at least wait for them to be probeb */ ++ if (PTR_ERR(tx) == -EPROBE_DEFER || PTR_ERR(rx) == -EPROBE_DEFER || ++ PTR_ERR(ecc) == -EPROBE_DEFER) ++ ret = -EPROBE_DEFER; ++ ++ if (IS_ERR(tx) || IS_ERR(rx) || IS_ERR(ecc)) { ++ if (!IS_ERR(tx)) ++ dma_release_channel(tx); ++ if (!IS_ERR(rx)) ++ dma_release_channel(rx); ++ if (!IS_ERR(ecc)) ++ dma_release_channel(ecc); ++ ++ if (ret != -EPROBE_DEFER) ++ dev_warn(fmc2->dev, "DMAs missing, use polling mode\n"); ++ ++ return ret; + } + ++ fmc2->dma_tx_ch = tx; ++ fmc2->dma_rx_ch = rx; ++ fmc2->dma_ecc_ch = ecc; ++ + ret = sg_alloc_table(&fmc2->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); + if (ret) + return ret; +@@ -1940,7 +1959,11 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + } + + rstc = devm_reset_control_get(dev, NULL); +- if (!IS_ERR(rstc)) { ++ if (IS_ERR(rstc)) { ++ ret = PTR_ERR(rstc); ++ if (ret == -EPROBE_DEFER) ++ goto err_clk_disable; ++ } else { + reset_control_assert(rstc); + reset_control_deassert(rstc); + } +@@ -1948,7 +1971,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + /* DMA setup */ + ret = stm32_fmc2_dma_setup(fmc2); + if (ret) +- return ret; ++ goto err_dma_setup; + + /* FMC2 init routine */ + stm32_fmc2_init(fmc2); +@@ -1970,7 +1993,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + /* Scan to find existence of the device */ + ret = nand_scan(chip, nand->ncs); + if (ret) +- goto err_scan; ++ goto err_dma_setup; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) +@@ -1983,7 +2006,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + err_device_register: + nand_cleanup(chip); + +-err_scan: ++err_dma_setup: + if (fmc2->dma_ecc_ch) + dma_release_channel(fmc2->dma_ecc_ch); + if (fmc2->dma_tx_ch) +@@ -1994,6 +2017,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + sg_free_table(&fmc2->dma_data_sg); + sg_free_table(&fmc2->dma_ecc_sg); + ++err_clk_disable: + clk_disable_unprepare(fmc2->clk); + + return ret; +diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +index b7ba8810a..eb10b8194 100644 +--- a/include/linux/mmc/core.h ++++ b/include/linux/mmc/core.h +@@ -173,6 +173,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq); + int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, + int retries); + ++void mmc_hw_unstuck(struct mmc_host *host); + int mmc_hw_reset(struct mmc_host *host); + int mmc_sw_reset(struct mmc_host *host); + void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index 4c5eb3aa8..feac3431b 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -163,6 +163,12 @@ struct mmc_host_ops { + void (*hw_reset)(struct mmc_host *host); + void (*card_event)(struct mmc_host *host); + ++ /* ++ * Optional callback, if your host is in deadlock after a command and ++ * must done specific action before sent new command. ++ */ ++ void (*hw_unstuck)(struct mmc_host *host); ++ + /* + * Optional callback to support controllers with HW issues for multiple + * I/O. Returns the number of supported blocks for the request. +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch new file mode 100644 index 0000000..b60eb20 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch @@ -0,0 +1,2124 @@ +From d367a94623ae3c7e9707fe10e25ab06a8b0ea00b Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:46:34 +0200 +Subject: [PATCH 15/23] ARM-stm32mp1-r1-NET-TTY + +--- + .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 98 +- + .../net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- + .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 +- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 29 +- + .../ethernet/stmicro/stmmac/stmmac_platform.c | 4 +- + drivers/net/phy/realtek.c | 5 + + .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + + drivers/tty/serial/stm32-usart.c | 996 +++++++++++------- + drivers/tty/serial/stm32-usart.h | 20 +- + 9 files changed, 728 insertions(+), 434 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +index 4ef041bdf..f67842bfc 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +@@ -95,7 +95,6 @@ struct stm32_dwmac { + struct clk *syscfg_clk; + int eth_clk_sel_reg; + int eth_ref_clk_sel_reg; +- int irq_pwr_wakeup; + u32 mode_reg; /* MAC glue-logic mode register */ + struct regmap *regmap; + u32 speed; +@@ -152,30 +151,39 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) + int ret = 0; + + if (prepare) { +- ret = clk_prepare_enable(dwmac->syscfg_clk); +- if (ret) +- return ret; +- ++ if (dwmac->syscfg_clk) { ++ ret = clk_prepare_enable(dwmac->syscfg_clk); ++ if (ret) ++ return ret; ++ } + if (dwmac->clk_eth_ck) { + ret = clk_prepare_enable(dwmac->clk_eth_ck); + if (ret) { +- clk_disable_unprepare(dwmac->syscfg_clk); ++ if (dwmac->syscfg_clk) ++ goto unprepare_syscfg; + return ret; + } + } + } else { +- clk_disable_unprepare(dwmac->syscfg_clk); ++ if (dwmac->syscfg_clk) ++ clk_disable_unprepare(dwmac->syscfg_clk); ++ + if (dwmac->clk_eth_ck) + clk_disable_unprepare(dwmac->clk_eth_ck); + } + return ret; ++ ++unprepare_syscfg: ++ clk_disable_unprepare(dwmac->syscfg_clk); ++ ++ return ret; + } + + static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) + { + struct stm32_dwmac *dwmac = plat_dat->bsp_priv; + u32 reg = dwmac->mode_reg; +- int val, ret; ++ int val; + + switch (plat_dat->interface) { + case PHY_INTERFACE_MODE_MII: +@@ -211,7 +219,7 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) + } + + /* Need to update PMCCLRR (clear register) */ +- ret = regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, ++ regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, + dwmac->ops->syscfg_eth_mask); + + /* Update PMCSETR (set register) */ +@@ -294,9 +302,8 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, + static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, + struct device *dev) + { +- struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = dev->of_node; +- int err = 0; ++ int err; + + /* Gigabit Ethernet 125MHz clock selection. */ + dwmac->eth_clk_sel_reg = of_property_read_bool(np, "st,eth-clk-sel"); +@@ -308,7 +315,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, + /* Get ETH_CLK clocks */ + dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); + if (IS_ERR(dwmac->clk_eth_ck)) { +- dev_warn(dev, "No phy clock provided...\n"); ++ dev_info(dev, "No phy clock provided...\n"); + dwmac->clk_eth_ck = NULL; + } + +@@ -320,38 +327,36 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, + return PTR_ERR(dwmac->clk_ethstp); + } + +- /* Clock for sysconfig */ ++ /* Optional Clock for sysconfig */ + dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk"); + if (IS_ERR(dwmac->syscfg_clk)) { +- dev_err(dev, "No syscfg clock provided...\n"); +- return PTR_ERR(dwmac->syscfg_clk); +- } +- +- /* Get IRQ information early to have an ability to ask for deferred +- * probe if needed before we went too far with resource allocation. +- */ +- dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev, +- "stm32_pwr_wakeup"); +- if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER) +- return -EPROBE_DEFER; +- +- if (!dwmac->clk_eth_ck && dwmac->irq_pwr_wakeup >= 0) { +- err = device_init_wakeup(&pdev->dev, true); +- if (err) { +- dev_err(&pdev->dev, "Failed to init wake up irq\n"); ++ err = PTR_ERR(dwmac->syscfg_clk); ++ if (err != -ENOENT) + return err; +- } +- err = dev_pm_set_dedicated_wake_irq(&pdev->dev, +- dwmac->irq_pwr_wakeup); +- if (err) { +- dev_err(&pdev->dev, "Failed to set wake up irq\n"); +- device_init_wakeup(&pdev->dev, false); +- } +- device_set_wakeup_enable(&pdev->dev, false); ++ dwmac->syscfg_clk = NULL; ++ err = 0; + } ++ + return err; + } + ++static int stm32_dwmac_wake_init(struct device *dev, ++ struct stmmac_resources *stmmac_res) ++{ ++ int err; ++ ++ device_set_wakeup_capable(dev, true); ++ ++ err = dev_pm_set_wake_irq(dev, stmmac_res->wol_irq); ++ if (err) { ++ dev_err(dev, "Failed to set wake up irq\n"); ++ device_set_wakeup_capable(dev, false); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int stm32_dwmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -390,6 +395,12 @@ static int stm32_dwmac_probe(struct platform_device *pdev) + goto err_remove_config_dt; + } + ++ if (stmmac_res.wol_irq && !dwmac->clk_eth_ck) { ++ ret = stm32_dwmac_wake_init(&pdev->dev, &stmmac_res); ++ if (ret) ++ return ret; ++ } ++ + plat_dat->bsp_priv = dwmac; + + ret = stm32_dwmac_init(plat_dat); +@@ -415,14 +426,14 @@ static int stm32_dwmac_remove(struct platform_device *pdev) + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + int ret = stmmac_dvr_remove(&pdev->dev); +- struct stm32_dwmac *dwmac = priv->plat->bsp_priv; ++ ++ if (ret) ++ return ret; + + stm32_dwmac_clk_disable(priv->plat->bsp_priv); + +- if (dwmac->irq_pwr_wakeup >= 0) { +- dev_pm_clear_wake_irq(&pdev->dev); +- device_init_wakeup(&pdev->dev, false); +- } ++ dev_pm_clear_wake_irq(&pdev->dev); ++ ret = device_init_wakeup(&pdev->dev, false); + + return ret; + } +@@ -436,7 +447,8 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) + return ret; + + clk_disable_unprepare(dwmac->clk_tx); +- clk_disable_unprepare(dwmac->syscfg_clk); ++ if (dwmac->syscfg_clk) ++ clk_disable_unprepare(dwmac->syscfg_clk); + if (dwmac->clk_eth_ck) + clk_disable_unprepare(dwmac->clk_eth_ck); + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +index f2a29a90e..2df6705cd 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +@@ -19,7 +19,7 @@ int dwmac4_dma_reset(void __iomem *ioaddr) + /* DMA SW reset */ + value |= DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + DMA_BUS_MODE); +- limit = 10; ++ limit = 100; + while (limit--) { + if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) + break; +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +index 1a768837c..43532e207 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +@@ -706,7 +706,7 @@ static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv) + return 0; + } + +- return (riwt * 256) / (clk / 1000000); ++ return DIV_ROUND_UP(riwt * 256, clk / 1000000); + } + + static int stmmac_get_coalesce(struct net_device *dev, +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 89a6ae2b1..413b6f234 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -4846,6 +4846,7 @@ int stmmac_resume(struct device *dev) + { + struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); ++ int ret; + + if (!netif_running(ndev)) + return 0; +@@ -4879,7 +4880,25 @@ int stmmac_resume(struct device *dev) + + stmmac_reset_queues_param(priv); + +- stmmac_clear_descriptors(priv); ++ /* Stop TX/RX DMA and clear the descriptors */ ++ stmmac_stop_all_dma(priv); ++ ++ /* Release and free the Rx/Tx resources */ ++ free_dma_desc_resources(priv); ++ ++ ret = alloc_dma_desc_resources(priv); ++ if (ret < 0) { ++ netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", ++ __func__); ++ goto dma_desc_error; ++ } ++ ++ ret = init_dma_desc_rings(ndev, GFP_KERNEL); ++ if (ret < 0) { ++ netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", ++ __func__); ++ goto init_error; ++ } + + stmmac_hw_setup(ndev, false); + stmmac_init_coalesce(priv); +@@ -4900,6 +4919,14 @@ int stmmac_resume(struct device *dev) + phylink_mac_change(priv->phylink, true); + + return 0; ++init_error: ++ free_dma_desc_resources(priv); ++dma_desc_error: ++ if (ndev->phydev) ++ phy_disconnect(ndev->phydev); ++ mutex_unlock(&priv->lock); ++ ++ return -1; + } + EXPORT_SYMBOL_GPL(stmmac_resume); + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index 5150551c2..a6225534a 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -588,7 +588,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) + if (IS_ERR(plat->clk_ptp_ref)) { + plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk); + plat->clk_ptp_ref = NULL; +- dev_warn(&pdev->dev, "PTP uses main clock\n"); ++ dev_info(&pdev->dev, "PTP uses main clock\n"); + } else { + plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref); + dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate); +@@ -670,7 +670,7 @@ int stmmac_get_platform_resources(struct platform_device *pdev, + stmmac_res->wol_irq = stmmac_res->irq; + } + +- stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); ++ stmmac_res->lpi_irq = platform_get_irq_byname_optional(pdev, "eth_lpi"); + if (stmmac_res->lpi_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index c76df51dd..45a112016 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -175,6 +175,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) + u16 val; + int ret; + ++ /* Set green LED for Link, yellow LED for Active */ ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0xd04); ++ phy_write(phydev, 0x10, 0x617f); ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); ++ + /* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and + * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin. + */ +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +index fc12598b2..041a215aa 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -1128,7 +1128,10 @@ static int brcmf_ops_sdio_suspend(struct device *dev) + enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); + else + sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; ++ } else { ++ brcmf_sdiod_intr_unregister(sdiodev); + } ++ + if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) + brcmf_err("Failed to set pm_flags %x\n", sdio_flags); + return 0; +@@ -1144,6 +1147,9 @@ static int brcmf_ops_sdio_resume(struct device *dev) + if (func->num != 2) + return 0; + ++ if (!sdiodev->wowl_enabled) ++ brcmf_sdiod_intr_register(sdiodev); ++ + brcmf_sdiod_freezer_off(sdiodev); + return 0; + } +diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c +index 2f72514d6..6592e5cdb 100644 +--- a/drivers/tty/serial/stm32-usart.c ++++ b/drivers/tty/serial/stm32-usart.c +@@ -4,6 +4,7 @@ + * Copyright (C) STMicroelectronics SA 2017 + * Authors: Maxime Coquelin + * Gerald Baeza ++ * Erwan Le Ray + * + * Inspired by st-asc.c from STMicroelectronics (c) + */ +@@ -37,15 +38,15 @@ + + #include "stm32-usart.h" + +-static void stm32_stop_tx(struct uart_port *port); +-static void stm32_transmit_chars(struct uart_port *port); ++static void stm32_usart_stop_tx(struct uart_port *port); ++static void stm32_usart_transmit_chars(struct uart_port *port); + + static inline struct stm32_port *to_stm32_port(struct uart_port *port) + { + return container_of(port, struct stm32_port, port); + } + +-static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) ++static void stm32_usart_set_bits(struct uart_port *port, u32 reg, u32 bits) + { + u32 val; + +@@ -54,7 +55,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) + writel_relaxed(val, port->membase + reg); + } + +-static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) ++static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) + { + u32 val; + +@@ -63,8 +64,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) + writel_relaxed(val, port->membase + reg); + } + +-static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, +- u32 delay_DDE, u32 baud) ++static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, ++ u32 delay_DDE, u32 baud) + { + u32 rs485_deat_dedt; + u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); +@@ -98,8 +99,8 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + *cr1 |= rs485_deat_dedt; + } + +-static int stm32_config_rs485(struct uart_port *port, +- struct serial_rs485 *rs485conf) ++static int stm32_usart_config_rs485(struct uart_port *port, ++ struct serial_rs485 *rs485conf) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -107,7 +108,7 @@ static int stm32_config_rs485(struct uart_port *port, + u32 usartdiv, baud, cr1, cr3; + bool over8; + +- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); ++ stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + port->rs485 = *rs485conf; + +@@ -125,9 +126,10 @@ static int stm32_config_rs485(struct uart_port *port, + << USART_BRR_04_R_SHIFT; + + baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); +- stm32_config_reg_rs485(&cr1, &cr3, +- rs485conf->delay_rts_before_send, +- rs485conf->delay_rts_after_send, baud); ++ stm32_usart_config_reg_rs485(&cr1, &cr3, ++ rs485conf->delay_rts_before_send, ++ rs485conf->delay_rts_after_send, ++ baud); + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; +@@ -140,18 +142,19 @@ static int stm32_config_rs485(struct uart_port *port, + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr1, port->membase + ofs->cr1); + } else { +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); +- stm32_clr_bits(port, ofs->cr1, +- USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); ++ stm32_usart_clr_bits(port, ofs->cr3, ++ USART_CR3_DEM | USART_CR3_DEP); ++ stm32_usart_clr_bits(port, ofs->cr1, ++ USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + +- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); ++ stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + return 0; + } + +-static int stm32_init_rs485(struct uart_port *port, +- struct platform_device *pdev) ++static int stm32_usart_init_rs485(struct uart_port *port, ++ struct platform_device *pdev) + { + struct serial_rs485 *rs485conf = &port->rs485; + +@@ -167,64 +170,66 @@ static int stm32_init_rs485(struct uart_port *port, + return 0; + } + +-static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, +- bool threaded) ++static bool stm32_usart_rx_dma_enabled(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ ++ if (!stm32_port->rx_ch) ++ return false; ++ ++ return !!(readl_relaxed(port->membase + ofs->cr3) & USART_CR3_DMAR); ++} ++ ++/* ++ * Return true when data is pending (in pio mode), and false when no data is ++ * pending. ++ */ ++static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- enum dma_status status; +- struct dma_tx_state state; + + *sr = readl_relaxed(port->membase + ofs->isr); ++ /* Get pending characters in RDR or FIFO */ ++ if (*sr & USART_SR_RXNE) { ++ /* ++ * Get all pending characters from the RDR or the FIFO when ++ * using interrupts ++ */ ++ if (!stm32_usart_rx_dma_enabled(port)) ++ return true; + +- if (threaded && stm32_port->rx_ch) { +- status = dmaengine_tx_status(stm32_port->rx_ch, +- stm32_port->rx_ch->cookie, +- &state); +- if ((status == DMA_IN_PROGRESS) && +- (*last_res != state.residue)) +- return 1; +- else +- return 0; +- } else if (*sr & USART_SR_RXNE) { +- return 1; ++ /* Handle only RX data errors when using DMA */ ++ if (*sr & USART_SR_ERR_MASK) ++ return true; + } +- return 0; ++ ++ return false; + } + +-static unsigned long stm32_get_char(struct uart_port *port, u32 *sr, +- int *last_res) ++static unsigned long stm32_usart_get_char_pio(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long c; + +- if (stm32_port->rx_ch) { +- c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; +- if ((*last_res) == 0) +- *last_res = RX_BUF_L; +- } else { +- c = readl_relaxed(port->membase + ofs->rdr); +- /* apply RDR data mask */ +- c &= stm32_port->rdr_mask; +- } ++ c = readl_relaxed(port->membase + ofs->rdr); ++ /* Apply RDR data mask */ ++ c &= stm32_port->rdr_mask; + + return c; + } + +-static void stm32_receive_chars(struct uart_port *port, bool threaded) ++static void stm32_usart_receive_chars_pio(struct uart_port *port) + { +- struct tty_port *tport = &port->state->port; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long c; + u32 sr; + char flag; + +- if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) +- pm_wakeup_event(tport->tty->dev, 0); +- +- while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { ++ while (stm32_usart_pending_rx_pio(port, &sr)) { + sr |= USART_SR_DUMMY_RX; + flag = TTY_NORMAL; + +@@ -243,7 +248,7 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) + writel_relaxed(sr & USART_SR_ERR_MASK, + port->membase + ofs->icr); + +- c = stm32_get_char(port, &sr, &stm32_port->last_res); ++ c = stm32_usart_get_char_pio(port); + port->icount.rx++; + if (sr & USART_SR_ERR_MASK) { + if (sr & USART_SR_ORE) { +@@ -277,26 +282,116 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) + continue; + uart_insert_char(port, sr, USART_SR_ORE, c, flag); + } ++} ++ ++static void stm32_usart_push_buffer_dma(struct uart_port *port, ++ unsigned int dma_size) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct tty_port *ttyport = &stm32_port->port.state->port; ++ unsigned char *dma_start; ++ int dma_count; ++ ++ dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); ++ dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); ++ port->icount.rx += dma_count; ++ stm32_port->last_res -= dma_count; ++ if (stm32_port->last_res == 0) ++ stm32_port->last_res = RX_BUF_L; ++} ++ ++static void stm32_usart_receive_chars_dma(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ unsigned int dma_size; ++ ++ /* ++ * DMA buffer is configured in cyclic mode and handles the rollback of ++ * the buffer. ++ */ ++ if (stm32_port->state.residue > stm32_port->last_res) { ++ /* Conditional first part: from last_res to end of DMA buffer */ ++ dma_size = stm32_port->last_res; ++ stm32_usart_push_buffer_dma(port, dma_size); ++ } ++ ++ dma_size = stm32_port->last_res - stm32_port->state.residue; ++ stm32_usart_push_buffer_dma(port, dma_size); ++} ++ ++static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) ++{ ++ struct tty_port *tport = &port->state->port; ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ unsigned long flags = 0; ++ u32 sr; ++ ++ if (threaded) ++ spin_lock_irqsave(&port->lock, flags); ++ else ++ spin_lock(&port->lock); ++ ++ if (stm32_usart_rx_dma_enabled(port)) { ++ stm32_port->status = ++ dmaengine_tx_status(stm32_port->rx_ch, ++ stm32_port->rx_ch->cookie, ++ &stm32_port->state); ++ if (stm32_port->status == DMA_IN_PROGRESS) { ++ /* Empty DMA buffer */ ++ stm32_usart_receive_chars_dma(port); ++ sr = readl_relaxed(port->membase + ofs->isr); ++ if (sr & USART_SR_ERR_MASK) { ++ /* Disable DMA request line */ ++ stm32_usart_clr_bits(port, ofs->cr3, ++ USART_CR3_DMAR); ++ ++ /* Switch to PIO mode to handle the errors */ ++ stm32_usart_receive_chars_pio(port); ++ ++ /* Switch back to DMA mode */ ++ stm32_usart_set_bits(port, ofs->cr3, ++ USART_CR3_DMAR); ++ } ++ } else { ++ /* Disable RX DMA */ ++ dmaengine_terminate_async(stm32_port->rx_ch); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ /* Fall back to interrupt mode */ ++ dev_dbg(port->dev, ++ "DMA error, fallback to irq mode\n"); ++ stm32_usart_receive_chars_pio(port); ++ } ++ } else { ++ stm32_usart_receive_chars_pio(port); ++ } ++ ++ if (threaded) ++ spin_unlock_irqrestore(&port->lock, flags); ++ else ++ spin_unlock(&port->lock); + +- spin_unlock(&port->lock); + tty_flip_buffer_push(tport); +- spin_lock(&port->lock); + } + +-static void stm32_tx_dma_complete(void *arg) ++static void stm32_usart_tx_dma_complete(void *arg) + { + struct uart_port *port = arg; + struct stm32_port *stm32port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ unsigned long flags; + +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ dmaengine_terminate_async(stm32port->tx_ch); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32port->tx_dma_busy = false; + + /* Let's see if we have pending data to send */ +- stm32_transmit_chars(port); ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_usart_transmit_chars(port); ++ spin_unlock_irqrestore(&port->lock, flags); + } + +-static void stm32_tx_interrupt_enable(struct uart_port *port) ++static void stm32_usart_tx_interrupt_enable(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -306,30 +401,37 @@ static void stm32_tx_interrupt_enable(struct uart_port *port) + * or TX empty irq when FIFO is disabled + */ + if (stm32_port->fifoen) +- stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else +- stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); ++ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); ++} ++ ++static void stm32_usart_rx_dma_complete(void *arg) ++{ ++ struct uart_port *port = arg; ++ ++ stm32_usart_receive_chars(port, true); + } + +-static void stm32_tx_interrupt_disable(struct uart_port *port) ++static void stm32_usart_tx_interrupt_disable(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (stm32_port->fifoen) +- stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else +- stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); ++ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + } + +-static void stm32_transmit_chars_pio(struct uart_port *port) ++static void stm32_usart_transmit_chars_pio(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct circ_buf *xmit = &port->state->xmit; + + if (stm32_port->tx_dma_busy) { +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_port->tx_dma_busy = false; + } + +@@ -344,19 +446,19 @@ static void stm32_transmit_chars_pio(struct uart_port *port) + + /* rely on TXE irq (mask or unmask) for sending remaining data */ + if (uart_circ_empty(xmit)) +- stm32_tx_interrupt_disable(port); ++ stm32_usart_tx_interrupt_disable(port); + else +- stm32_tx_interrupt_enable(port); ++ stm32_usart_tx_interrupt_enable(port); + } + +-static void stm32_transmit_chars_dma(struct uart_port *port) ++static void stm32_usart_transmit_chars_dma(struct uart_port *port) + { + struct stm32_port *stm32port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct circ_buf *xmit = &port->state->xmit; + struct dma_async_tx_descriptor *desc = NULL; + dma_cookie_t cookie; +- unsigned int count, i; ++ unsigned int count, i, ret; + + if (stm32port->tx_dma_busy) + return; +@@ -389,28 +491,36 @@ static void stm32_transmit_chars_dma(struct uart_port *port) + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); + +- if (!desc) { +- for (i = count; i > 0; i--) +- stm32_transmit_chars_pio(port); +- return; +- } ++ if (!desc) ++ goto fallback_err; + +- desc->callback = stm32_tx_dma_complete; ++ desc->callback = stm32_usart_tx_dma_complete; + desc->callback_param = port; + + /* Push current DMA TX transaction in the pending queue */ + cookie = dmaengine_submit(desc); ++ ret = dma_submit_error(cookie); ++ if (ret) { ++ /* dma no yet started, safe to free resources */ ++ dmaengine_terminate_async(stm32port->tx_ch); ++ goto fallback_err; ++ } + + /* Issue pending DMA TX requests */ + dma_async_issue_pending(stm32port->tx_ch); + +- stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); + + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + port->icount.tx += count; ++ return; ++ ++fallback_err: ++ for (i = count; i > 0; i--) ++ stm32_usart_transmit_chars_pio(port); + } + +-static void stm32_transmit_chars(struct uart_port *port) ++static void stm32_usart_transmit_chars(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -418,211 +528,276 @@ static void stm32_transmit_chars(struct uart_port *port) + + if (port->x_char) { + if (stm32_port->tx_dma_busy) +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + writel_relaxed(port->x_char, port->membase + ofs->tdr); + port->x_char = 0; + port->icount.tx++; + if (stm32_port->tx_dma_busy) +- stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { +- stm32_tx_interrupt_disable(port); ++ stm32_usart_tx_interrupt_disable(port); + return; + } + + if (ofs->icr == UNDEF_REG) +- stm32_clr_bits(port, ofs->isr, USART_SR_TC); ++ stm32_usart_clr_bits(port, ofs->isr, USART_SR_TC); + else + writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); + + if (stm32_port->tx_ch) +- stm32_transmit_chars_dma(port); ++ stm32_usart_transmit_chars_dma(port); + else +- stm32_transmit_chars_pio(port); ++ stm32_usart_transmit_chars_pio(port); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) +- stm32_tx_interrupt_disable(port); ++ stm32_usart_tx_interrupt_disable(port); + } + +-static irqreturn_t stm32_interrupt(int irq, void *ptr) ++static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; ++ struct tty_port *tport = &port->state->port; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + u32 sr; + +- spin_lock(&port->lock); +- + sr = readl_relaxed(port->membase + ofs->isr); + + if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) + writel_relaxed(USART_ICR_RTOCF, + port->membase + ofs->icr); + +- if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) ++ if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) { ++ /* Clear wake up flag and disable wake up interrupt */ + writel_relaxed(USART_ICR_WUCF, + port->membase + ofs->icr); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); ++ if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) ++ pm_wakeup_event(tport->tty->dev, 0); ++ } + +- if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) +- stm32_receive_chars(port, false); +- +- if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) +- stm32_transmit_chars(port); ++ /* ++ * rx errors in dma mode has to be handled ASAP to avoid overrun as the ++ * DMA request line has been masked by HW and rx data are stacking in ++ * FIFO. ++ */ ++ if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || ++ ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) ++ stm32_usart_receive_chars(port, false); + +- spin_unlock(&port->lock); ++ if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { ++ spin_lock(&port->lock); ++ stm32_usart_transmit_chars(port); ++ spin_unlock(&port->lock); ++ } + +- if (stm32_port->rx_ch) ++ if (stm32_usart_rx_dma_enabled(port)) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; + } + +-static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) ++static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; +- struct stm32_port *stm32_port = to_stm32_port(port); +- +- spin_lock(&port->lock); +- +- if (stm32_port->rx_ch) +- stm32_receive_chars(port, true); + +- spin_unlock(&port->lock); ++ /* Receiver timeout irq for DMA RX */ ++ stm32_usart_receive_chars(port, true); + + return IRQ_HANDLED; + } + +-static unsigned int stm32_tx_empty(struct uart_port *port) ++static unsigned int stm32_usart_tx_empty(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + +- return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; ++ if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) ++ return TIOCSER_TEMT; ++ ++ return 0; + } + +-static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) ++static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) +- stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_RTSE); + else +- stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_RTSE); + } + +-static unsigned int stm32_get_mctrl(struct uart_port *port) ++static unsigned int stm32_usart_get_mctrl(struct uart_port *port) + { + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + } + + /* Transmit stop */ +-static void stm32_stop_tx(struct uart_port *port) ++static void stm32_usart_stop_tx(struct uart_port *port) + { +- stm32_tx_interrupt_disable(port); ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ ++ stm32_usart_tx_interrupt_disable(port); ++ if (stm32_port->tx_dma_busy) { ++ dmaengine_terminate_async(stm32_port->tx_ch); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ } + } + + /* There are probably characters waiting to be transmitted. */ +-static void stm32_start_tx(struct uart_port *port) ++static void stm32_usart_start_tx(struct uart_port *port) + { + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit)) + return; + +- stm32_transmit_chars(port); ++ stm32_usart_transmit_chars(port); ++} ++ ++/* Flush the transmit buffer. */ ++static void stm32_usart_flush_buffer(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ ++ if (stm32_port->tx_ch) { ++ /* Avoid deadlock with the DMA engine callback */ ++ spin_unlock(&port->lock); ++ dmaengine_terminate_async(stm32_port->tx_ch); ++ spin_lock(&port->lock); ++ ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_port->tx_dma_busy = false; ++ } + } + + /* Throttle the remote when input buffer is about to overflow. */ +-static void stm32_throttle(struct uart_port *port) ++static void stm32_usart_throttle(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +- stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); ++ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) +- stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); ++ stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + + spin_unlock_irqrestore(&port->lock, flags); + } + + /* Unthrottle the remote, the input buffer can now accept data. */ +-static void stm32_unthrottle(struct uart_port *port) ++static void stm32_usart_unthrottle(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +- stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq); ++ stm32_usart_set_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) +- stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); ++ stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + + spin_unlock_irqrestore(&port->lock, flags); + } + + /* Receive stop */ +-static void stm32_stop_rx(struct uart_port *port) ++static void stm32_usart_stop_rx(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + +- stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); ++ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) +- stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); +- ++ stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + } + + /* Handle breaks - ignored by us */ +-static void stm32_break_ctl(struct uart_port *port, int break_state) ++static void stm32_usart_break_ctl(struct uart_port *port, int break_state) ++{ ++} ++ ++static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) + { ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct dma_async_tx_descriptor *desc; ++ int ret; ++ ++ stm32_port->last_res = RX_BUF_L; ++ /* Prepare a DMA cyclic transaction */ ++ desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, ++ stm32_port->rx_dma_buf, ++ RX_BUF_L, RX_BUF_P, ++ DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT); ++ if (!desc) { ++ dev_err(port->dev, "rx dma prep cyclic failed\n"); ++ return -ENODEV; ++ } ++ ++ desc->callback = stm32_usart_rx_dma_complete; ++ desc->callback_param = port; ++ ++ /* Push current DMA transaction in the pending queue */ ++ ret = dma_submit_error(dmaengine_submit(desc)); ++ if (ret) { ++ dmaengine_terminate_sync(stm32_port->rx_ch); ++ return ret; ++ } ++ ++ /* Issue pending DMA requests */ ++ dma_async_issue_pending(stm32_port->rx_ch); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); ++ ++ return 0; + } + +-static int stm32_startup(struct uart_port *port) ++static int stm32_usart_startup(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32_port->info->cfg; + const char *name = to_platform_device(port->dev)->name; + u32 val; + int ret; + +- ret = request_threaded_irq(port->irq, stm32_interrupt, +- stm32_threaded_interrupt, ++ ret = request_threaded_irq(port->irq, stm32_usart_interrupt, ++ stm32_usart_threaded_interrupt, + IRQF_NO_SUSPEND, name, port); + if (ret) + return ret; + + /* RX FIFO Flush */ + if (ofs->rqr != UNDEF_REG) +- stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); ++ stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); + +- /* Tx and RX FIFO configuration */ +- if (stm32_port->fifoen) { +- val = readl_relaxed(port->membase + ofs->cr3); +- val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); +- val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; +- val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; +- writel_relaxed(val, port->membase + ofs->cr3); ++ if (stm32_port->rx_ch) { ++ ret = stm32_usart_start_rx_dma_cyclic(port); ++ if (ret) { ++ free_irq(port->irq, port); ++ return ret; ++ } + } +- +- /* RX FIFO enabling */ +- val = stm32_port->cr1_irq | USART_CR1_RE; +- if (stm32_port->fifoen) +- val |= USART_CR1_FIFOEN; +- stm32_set_bits(port, ofs->cr1, val); ++ /* RX enabling */ ++ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); ++ stm32_usart_set_bits(port, ofs->cr1, val); + + return 0; + } + +-static void stm32_shutdown(struct uart_port *port) ++static void stm32_usart_shutdown(struct uart_port *port) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -643,12 +818,17 @@ static void stm32_shutdown(struct uart_port *port) + if (ret) + dev_err(port->dev, "transmission complete not set\n"); + +- stm32_clr_bits(port, ofs->cr1, val); ++ stm32_usart_clr_bits(port, ofs->cr1, val); ++ ++ if (stm32_port->rx_ch) { ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ dmaengine_terminate_sync(stm32_port->rx_ch); ++ } + + free_irq(port->irq, port); + } + +-static unsigned int stm32_get_databits(struct ktermios *termios) ++static unsigned int stm32_usart_get_databits(struct ktermios *termios) + { + unsigned int bits; + +@@ -678,8 +858,9 @@ static unsigned int stm32_get_databits(struct ktermios *termios) + return bits; + } + +-static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +- struct ktermios *old) ++static void stm32_usart_set_termios(struct uart_port *port, ++ struct ktermios *termios, ++ struct ktermios *old) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -688,8 +869,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned int baud, bits; + u32 usartdiv, mantissa, fraction, oversampling; + tcflag_t cflag = termios->c_cflag; +- u32 cr1, cr2, cr3; ++ u32 cr1, cr2, cr3, isr; + unsigned long flags; ++ int ret; + + if (!stm32_port->hw_flow_control) + cflag &= ~CRTSCTS; +@@ -698,26 +880,39 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + + spin_lock_irqsave(&port->lock, flags); + ++ ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, ++ isr, ++ (isr & USART_SR_TC), ++ 10, 100000); ++ ++ if (ret) ++ dev_err(port->dev, "transmission complete not set\n"); ++ + /* Stop serial port and reset value */ + writel_relaxed(0, port->membase + ofs->cr1); + + /* flush RX & TX FIFO */ + if (ofs->rqr != UNDEF_REG) +- stm32_set_bits(port, ofs->rqr, +- USART_RQR_TXFRQ | USART_RQR_RXFRQ); ++ stm32_usart_set_bits(port, ofs->rqr, ++ USART_RQR_TXFRQ | USART_RQR_RXFRQ); + + cr1 = USART_CR1_TE | USART_CR1_RE; + if (stm32_port->fifoen) + cr1 |= USART_CR1_FIFOEN; + cr2 = 0; ++ ++ /* Tx and RX FIFO configuration */ + cr3 = readl_relaxed(port->membase + ofs->cr3); +- cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE +- | USART_CR3_TXFTCFG_MASK; ++ cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; ++ if (stm32_port->fifoen) { ++ cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; ++ cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; ++ } + + if (cflag & CSTOPB) + cr2 |= USART_CR2_STOP_2B; + +- bits = stm32_get_databits(termios); ++ bits = stm32_usart_get_databits(termios); + stm32_port->rdr_mask = (BIT(bits) - 1); + + if (cflag & PARENB) { +@@ -751,9 +946,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + stm32_port->cr1_irq = USART_CR1_RTOIE; + writel_relaxed(bits, port->membase + ofs->rtor); + cr2 |= USART_CR2_RTOEN; +- /* Not using dma, enable fifo threshold irq */ +- if (!stm32_port->rx_ch) +- stm32_port->cr3_irq = USART_CR3_RXFTIE; ++ /* ++ * Enable fifo threshold irq in two cases, either when there ++ * is no DMA, or when wake up over usart, from low power ++ * state until the DMA gets re-enabled by resume. ++ */ ++ stm32_port->cr3_irq = USART_CR3_RXFTIE; + } + + cr1 |= stm32_port->cr1_irq; +@@ -779,11 +977,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + if (usartdiv < 16) { + oversampling = 8; + cr1 |= USART_CR1_OVER8; +- stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); ++ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); + } else { + oversampling = 16; + cr1 &= ~USART_CR1_OVER8; +- stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); ++ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + } + + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; +@@ -816,13 +1014,22 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= USART_SR_DUMMY_RX; + +- if (stm32_port->rx_ch) ++ if (stm32_port->rx_ch) { ++ /* ++ * Setup DMA to collect only valid data and enable error irqs. ++ * This also enables break reception when using DMA. ++ */ ++ cr1 |= USART_CR1_PEIE; ++ cr3 |= USART_CR3_EIE; + cr3 |= USART_CR3_DMAR; ++ cr3 |= USART_CR3_DDRE; ++ } + + if (rs485conf->flags & SER_RS485_ENABLED) { +- stm32_config_reg_rs485(&cr1, &cr3, +- rs485conf->delay_rts_before_send, +- rs485conf->delay_rts_after_send, baud); ++ stm32_usart_config_reg_rs485(&cr1, &cr3, ++ rs485conf->delay_rts_before_send, ++ rs485conf->delay_rts_after_send, ++ baud); + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; +@@ -836,43 +1043,49 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + ++ /* Enable wake up from low power on start bit detection */ ++ if (stm32_port->wakeup_src) { ++ cr3 &= ~USART_CR3_WUS_MASK; ++ cr3 |= USART_CR3_WUS_START_BIT; ++ } ++ + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr2, port->membase + ofs->cr2); + writel_relaxed(cr1, port->membase + ofs->cr1); + +- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); ++ stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + spin_unlock_irqrestore(&port->lock, flags); + } + +-static const char *stm32_type(struct uart_port *port) ++static const char *stm32_usart_type(struct uart_port *port) + { + return (port->type == PORT_STM32) ? DRIVER_NAME : NULL; + } + +-static void stm32_release_port(struct uart_port *port) ++static void stm32_usart_release_port(struct uart_port *port) + { + } + +-static int stm32_request_port(struct uart_port *port) ++static int stm32_usart_request_port(struct uart_port *port) + { + return 0; + } + +-static void stm32_config_port(struct uart_port *port, int flags) ++static void stm32_usart_config_port(struct uart_port *port, int flags) + { + if (flags & UART_CONFIG_TYPE) + port->type = PORT_STM32; + } + + static int +-stm32_verify_port(struct uart_port *port, struct serial_struct *ser) ++stm32_usart_verify_port(struct uart_port *port, struct serial_struct *ser) + { + /* No user changeable parameters */ + return -EINVAL; + } + +-static void stm32_pm(struct uart_port *port, unsigned int state, +- unsigned int oldstate) ++static void stm32_usart_pm(struct uart_port *port, unsigned int state, ++ unsigned int oldstate) + { + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); +@@ -886,7 +1099,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state, + break; + case UART_PM_STATE_OFF: + spin_lock_irqsave(&port->lock, flags); +- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); ++ stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + spin_unlock_irqrestore(&port->lock, flags); + pm_runtime_put_sync(port->dev); + break; +@@ -894,53 +1107,56 @@ static void stm32_pm(struct uart_port *port, unsigned int state, + } + + static const struct uart_ops stm32_uart_ops = { +- .tx_empty = stm32_tx_empty, +- .set_mctrl = stm32_set_mctrl, +- .get_mctrl = stm32_get_mctrl, +- .stop_tx = stm32_stop_tx, +- .start_tx = stm32_start_tx, +- .throttle = stm32_throttle, +- .unthrottle = stm32_unthrottle, +- .stop_rx = stm32_stop_rx, +- .break_ctl = stm32_break_ctl, +- .startup = stm32_startup, +- .shutdown = stm32_shutdown, +- .set_termios = stm32_set_termios, +- .pm = stm32_pm, +- .type = stm32_type, +- .release_port = stm32_release_port, +- .request_port = stm32_request_port, +- .config_port = stm32_config_port, +- .verify_port = stm32_verify_port, ++ .tx_empty = stm32_usart_tx_empty, ++ .set_mctrl = stm32_usart_set_mctrl, ++ .get_mctrl = stm32_usart_get_mctrl, ++ .stop_tx = stm32_usart_stop_tx, ++ .start_tx = stm32_usart_start_tx, ++ .throttle = stm32_usart_throttle, ++ .unthrottle = stm32_usart_unthrottle, ++ .stop_rx = stm32_usart_stop_rx, ++ .break_ctl = stm32_usart_break_ctl, ++ .startup = stm32_usart_startup, ++ .shutdown = stm32_usart_shutdown, ++ .flush_buffer = stm32_usart_flush_buffer, ++ .set_termios = stm32_usart_set_termios, ++ .pm = stm32_usart_pm, ++ .type = stm32_usart_type, ++ .release_port = stm32_usart_release_port, ++ .request_port = stm32_usart_request_port, ++ .config_port = stm32_usart_config_port, ++ .verify_port = stm32_usart_verify_port, + }; + +-static int stm32_init_port(struct stm32_port *stm32port, +- struct platform_device *pdev) ++static void stm32_usart_deinit_port(struct stm32_port *stm32port) ++{ ++ clk_disable_unprepare(stm32port->clk); ++} ++ ++static int stm32_usart_init_port(struct stm32_port *stm32port, ++ struct platform_device *pdev) + { + struct uart_port *port = &stm32port->port; + struct resource *res; + int ret; + ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) ++ return ret ? : -ENODEV; ++ + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &stm32_uart_ops; + port->dev = &pdev->dev; + port->fifosize = stm32port->info->cfg.fifosize; +- +- ret = platform_get_irq(pdev, 0); +- if (ret <= 0) +- return ret ? : -ENODEV; + port->irq = ret; ++ port->rs485_config = stm32_usart_config_rs485; + +- port->rs485_config = stm32_config_rs485; ++ stm32_usart_init_rs485(port, pdev); + +- stm32_init_rs485(port, pdev); +- +- if (stm32port->info->cfg.has_wakeup) { +- stm32port->wakeirq = platform_get_irq(pdev, 1); +- if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) +- return stm32port->wakeirq ? : -ENODEV; +- } ++ if (stm32port->info->cfg.has_wakeup) ++ stm32port->wakeup_src = of_property_read_bool(pdev->dev.of_node, ++ "wakeup-source"); + + stm32port->fifoen = stm32port->info->cfg.has_fifo; + +@@ -970,7 +1186,7 @@ static int stm32_init_port(struct stm32_port *stm32port, + return ret; + } + +-static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) ++static struct stm32_port *stm32_usart_of_get_port(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; + int id; +@@ -987,12 +1203,14 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) + if (WARN_ON(id >= STM32_MAX_PORTS)) + return NULL; + +- stm32_ports[id].hw_flow_control = of_property_read_bool(np, +- "st,hw-flow-ctrl"); ++ stm32_ports[id].hw_flow_control = ++ of_property_read_bool(np, "uart-has-rtscts"); + stm32_ports[id].port.line = id; + stm32_ports[id].cr1_irq = USART_CR1_RXNEIE; + stm32_ports[id].cr3_irq = 0; + stm32_ports[id].last_res = RX_BUF_L; ++ stm32_ports[id].rx_dma_buf = 0; ++ stm32_ports[id].tx_dma_buf = 0; + return &stm32_ports[id]; + } + +@@ -1007,30 +1225,28 @@ static const struct of_device_id stm32_match[] = { + MODULE_DEVICE_TABLE(of, stm32_match); + #endif + +-static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, +- struct platform_device *pdev) ++static void stm32_usart_of_dma_rx_remove(struct stm32_port *stm32port, ++ struct platform_device *pdev) ++{ ++ if (stm32port->rx_buf) ++ dma_free_coherent(&pdev->dev, RX_BUF_L, stm32port->rx_buf, ++ stm32port->rx_dma_buf); ++} ++ ++static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, ++ struct platform_device *pdev) + { + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct uart_port *port = &stm32port->port; + struct device *dev = &pdev->dev; + struct dma_slave_config config; +- struct dma_async_tx_descriptor *desc = NULL; +- dma_cookie_t cookie; + int ret; + +- /* Request DMA RX channel */ +- stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); +- if (!stm32port->rx_ch) { +- dev_info(dev, "rx dma alloc failed\n"); +- return -ENODEV; +- } + stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, +- &stm32port->rx_dma_buf, +- GFP_KERNEL); +- if (!stm32port->rx_buf) { +- ret = -ENOMEM; +- goto alloc_err; +- } ++ &stm32port->rx_dma_buf, ++ GFP_KERNEL); ++ if (!stm32port->rx_buf) ++ return -ENOMEM; + + /* Configure DMA channel */ + memset(&config, 0, sizeof(config)); +@@ -1040,47 +1256,23 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + ret = dmaengine_slave_config(stm32port->rx_ch, &config); + if (ret < 0) { + dev_err(dev, "rx dma channel config failed\n"); +- ret = -ENODEV; +- goto config_err; +- } +- +- /* Prepare a DMA cyclic transaction */ +- desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, +- stm32port->rx_dma_buf, +- RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, +- DMA_PREP_INTERRUPT); +- if (!desc) { +- dev_err(dev, "rx dma prep cyclic failed\n"); +- ret = -ENODEV; +- goto config_err; ++ stm32_usart_of_dma_rx_remove(stm32port, pdev); ++ return ret; + } + +- /* No callback as dma buffer is drained on usart interrupt */ +- desc->callback = NULL; +- desc->callback_param = NULL; +- +- /* Push current DMA transaction in the pending queue */ +- cookie = dmaengine_submit(desc); +- +- /* Issue pending DMA requests */ +- dma_async_issue_pending(stm32port->rx_ch); +- + return 0; ++} + +-config_err: +- dma_free_coherent(&pdev->dev, +- RX_BUF_L, stm32port->rx_buf, +- stm32port->rx_dma_buf); +- +-alloc_err: +- dma_release_channel(stm32port->rx_ch); +- stm32port->rx_ch = NULL; +- +- return ret; ++static void stm32_usart_of_dma_tx_remove(struct stm32_port *stm32port, ++ struct platform_device *pdev) ++{ ++ if (stm32port->tx_buf) ++ dma_free_coherent(&pdev->dev, TX_BUF_L, stm32port->tx_buf, ++ stm32port->tx_dma_buf); + } + +-static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, +- struct platform_device *pdev) ++static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, ++ struct platform_device *pdev) + { + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct uart_port *port = &stm32port->port; +@@ -1090,19 +1282,11 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, + + stm32port->tx_dma_busy = false; + +- /* Request DMA TX channel */ +- stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); +- if (!stm32port->tx_ch) { +- dev_info(dev, "tx dma alloc failed\n"); +- return -ENODEV; +- } + stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, +- &stm32port->tx_dma_buf, +- GFP_KERNEL); +- if (!stm32port->tx_buf) { +- ret = -ENOMEM; +- goto alloc_err; +- } ++ &stm32port->tx_dma_buf, ++ GFP_KERNEL); ++ if (!stm32port->tx_buf) ++ return -ENOMEM; + + /* Configure DMA channel */ + memset(&config, 0, sizeof(config)); +@@ -1112,31 +1296,20 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, + ret = dmaengine_slave_config(stm32port->tx_ch, &config); + if (ret < 0) { + dev_err(dev, "tx dma channel config failed\n"); +- ret = -ENODEV; +- goto config_err; ++ stm32_usart_of_dma_tx_remove(stm32port, pdev); ++ return ret; + } + + return 0; +- +-config_err: +- dma_free_coherent(&pdev->dev, +- TX_BUF_L, stm32port->tx_buf, +- stm32port->tx_dma_buf); +- +-alloc_err: +- dma_release_channel(stm32port->tx_ch); +- stm32port->tx_ch = NULL; +- +- return ret; + } + +-static int stm32_serial_probe(struct platform_device *pdev) ++static int stm32_usart_serial_probe(struct platform_device *pdev) + { + const struct of_device_id *match; + struct stm32_port *stm32port; + int ret; + +- stm32port = stm32_of_get_stm32_port(pdev); ++ stm32port = stm32_usart_of_get_port(pdev); + if (!stm32port) + return -ENODEV; + +@@ -1146,105 +1319,145 @@ static int stm32_serial_probe(struct platform_device *pdev) + else + return -EINVAL; + +- ret = stm32_init_port(stm32port, pdev); ++ ret = stm32_usart_init_port(stm32port, pdev); + if (ret) + return ret; + +- if (stm32port->wakeirq > 0) { +- ret = device_init_wakeup(&pdev->dev, true); ++ if (stm32port->wakeup_src) { ++ device_set_wakeup_capable(&pdev->dev, true); ++ ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq); + if (ret) +- goto err_uninit; +- +- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, +- stm32port->wakeirq); +- if (ret) +- goto err_nowup; +- +- device_set_wakeup_enable(&pdev->dev, false); ++ goto err_deinit_port; + } + +- ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); +- if (ret) +- goto err_wirq; ++ stm32port->rx_ch = dma_request_chan_linked(&pdev->dev, "rx"); ++ if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ goto err_wakeirq; ++ } ++ /* Fall back in interrupt mode for any non-deferral error */ ++ if (IS_ERR(stm32port->rx_ch)) ++ stm32port->rx_ch = NULL; ++ ++ stm32port->tx_ch = dma_request_chan(&pdev->dev, "tx"); ++ if (PTR_ERR(stm32port->tx_ch) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ goto err_dma_rx; ++ } ++ /* Fall back in interrupt mode for any non-deferral error */ ++ if (IS_ERR(stm32port->tx_ch)) ++ stm32port->tx_ch = NULL; ++ ++ if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) { ++ /* Fall back in interrupt mode */ ++ dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); ++ stm32port->rx_ch = NULL; ++ } + +- ret = stm32_of_dma_rx_probe(stm32port, pdev); +- if (ret) +- dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); ++ if (stm32port->tx_ch && stm32_usart_of_dma_tx_probe(stm32port, pdev)) { ++ /* Fall back in interrupt mode */ ++ dma_release_channel(stm32port->tx_ch); ++ stm32port->tx_ch = NULL; ++ } + +- ret = stm32_of_dma_tx_probe(stm32port, pdev); +- if (ret) +- dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n"); ++ if (!stm32port->rx_ch) ++ dev_info(&pdev->dev, "interrupt mode for rx (no dma)\n"); ++ if (!stm32port->tx_ch) ++ dev_info(&pdev->dev, "interrupt mode for tx (no dma)\n"); + + platform_set_drvdata(pdev, &stm32port->port); + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); ++ ++ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); ++ if (ret) ++ goto err_port; ++ + pm_runtime_put_sync(&pdev->dev); + + return 0; + +-err_wirq: +- if (stm32port->wakeirq > 0) ++err_port: ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ ++ if (stm32port->tx_ch) { ++ stm32_usart_of_dma_tx_remove(stm32port, pdev); ++ dma_release_channel(stm32port->tx_ch); ++ } ++ ++ if (stm32port->rx_ch) ++ stm32_usart_of_dma_rx_remove(stm32port, pdev); ++ ++err_dma_rx: ++ if (stm32port->rx_ch) ++ dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); ++ ++err_wakeirq: ++ if (stm32port->wakeup_src) + dev_pm_clear_wake_irq(&pdev->dev); + +-err_nowup: +- if (stm32port->wakeirq > 0) +- device_init_wakeup(&pdev->dev, false); ++err_deinit_port: ++ if (stm32port->wakeup_src) ++ device_set_wakeup_capable(&pdev->dev, false); + +-err_uninit: +- clk_disable_unprepare(stm32port->clk); ++ stm32_usart_deinit_port(stm32port); + + return ret; + } + +-static int stm32_serial_remove(struct platform_device *pdev) ++static int stm32_usart_serial_remove(struct platform_device *pdev) + { + struct uart_port *port = platform_get_drvdata(pdev); + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + int err; ++ u32 cr3; + + pm_runtime_get_sync(&pdev->dev); ++ err = uart_remove_one_port(&stm32_usart_driver, port); ++ if (err) ++ return(err); + +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); +- +- if (stm32_port->rx_ch) +- dma_release_channel(stm32_port->rx_ch); +- +- if (stm32_port->rx_dma_buf) +- dma_free_coherent(&pdev->dev, +- RX_BUF_L, stm32_port->rx_buf, +- stm32_port->rx_dma_buf); ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); + +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); ++ cr3 = readl_relaxed(port->membase + ofs->cr3); ++ cr3 &= ~USART_CR3_EIE; ++ cr3 &= ~USART_CR3_DMAR; ++ cr3 &= ~USART_CR3_DDRE; ++ writel_relaxed(cr3, port->membase + ofs->cr3); + +- if (stm32_port->tx_ch) ++ if (stm32_port->tx_ch) { ++ dmaengine_terminate_async(stm32_port->tx_ch); ++ stm32_usart_of_dma_tx_remove(stm32_port, pdev); + dma_release_channel(stm32_port->tx_ch); ++ } + +- if (stm32_port->tx_dma_buf) +- dma_free_coherent(&pdev->dev, +- TX_BUF_L, stm32_port->tx_buf, +- stm32_port->tx_dma_buf); ++ if (stm32_port->rx_ch) { ++ stm32_usart_of_dma_rx_remove(stm32_port, pdev); ++ dma_release_chan_linked(&pdev->dev, stm32_port->rx_ch); ++ } + +- if (stm32_port->wakeirq > 0) { ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ ++ if (stm32_port->wakeup_src) { + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + } + +- clk_disable_unprepare(stm32_port->clk); +- +- err = uart_remove_one_port(&stm32_usart_driver, port); +- +- pm_runtime_disable(&pdev->dev); +- pm_runtime_put_noidle(&pdev->dev); ++ stm32_usart_deinit_port(stm32_port); + +- return err; ++ return 0; + } + +- + #ifdef CONFIG_SERIAL_STM32_CONSOLE +-static void stm32_console_putchar(struct uart_port *port, int ch) ++static void stm32_usart_console_putchar(struct uart_port *port, int ch) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -1255,7 +1468,8 @@ static void stm32_console_putchar(struct uart_port *port, int ch) + writel_relaxed(ch, port->membase + ofs->tdr); + } + +-static void stm32_console_write(struct console *co, const char *s, unsigned cnt) ++static void stm32_usart_console_write(struct console *co, const char *s, ++ unsigned int cnt) + { + struct uart_port *port = &stm32_ports[co->index].port; + struct stm32_port *stm32_port = to_stm32_port(port); +@@ -1279,7 +1493,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) + new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit); + writel_relaxed(new_cr1, port->membase + ofs->cr1); + +- uart_console_write(port, s, cnt, stm32_console_putchar); ++ uart_console_write(port, s, cnt, stm32_usart_console_putchar); + + /* Restore interrupt state */ + writel_relaxed(old_cr1, port->membase + ofs->cr1); +@@ -1289,7 +1503,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) + local_irq_restore(flags); + } + +-static int stm32_console_setup(struct console *co, char *options) ++static int stm32_usart_console_setup(struct console *co, char *options) + { + struct stm32_port *stm32port; + int baud = 9600; +@@ -1308,7 +1522,7 @@ static int stm32_console_setup(struct console *co, char *options) + * this to be called during the uart port registration when the + * driver gets probed and the port should be mapped at that point. + */ +- if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL) ++ if (stm32port->port.mapbase == 0 || !stm32port->port.membase) + return -ENXIO; + + if (options) +@@ -1320,8 +1534,8 @@ static int stm32_console_setup(struct console *co, char *options) + static struct console stm32_console = { + .name = STM32_SERIAL_NAME, + .device = uart_console_device, +- .write = stm32_console_write, +- .setup = stm32_console_setup, ++ .write = stm32_usart_console_write, ++ .setup = stm32_usart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &stm32_usart_driver, +@@ -1342,60 +1556,89 @@ static struct uart_driver stm32_usart_driver = { + .cons = STM32_SERIAL_CONSOLE, + }; + +-static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, +- bool enable) ++static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, ++ bool enable) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- struct stm32_usart_config *cfg = &stm32_port->info->cfg; +- u32 val; + +- if (stm32_port->wakeirq <= 0) ++ if (!stm32_port->wakeup_src) + return; + ++ /* ++ * Enable low-power wake-up and wake-up irq if argument is set to ++ * "enable", disable low-power wake-up and wake-up irq otherwise ++ */ + if (enable) { +- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); +- stm32_set_bits(port, ofs->cr1, USART_CR1_UESM); +- val = readl_relaxed(port->membase + ofs->cr3); +- val &= ~USART_CR3_WUS_MASK; +- /* Enable Wake up interrupt from low power on start bit */ +- val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; +- writel_relaxed(val, port->membase + ofs->cr3); +- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); ++ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + } else { +- stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); ++ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); + } + } + +-static int __maybe_unused stm32_serial_suspend(struct device *dev) ++static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) + { + struct uart_port *port = dev_get_drvdata(dev); ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct tty_port *tport = &port->state->port; + + uart_suspend_port(&stm32_usart_driver, port); + +- if (device_may_wakeup(dev)) +- stm32_serial_enable_wakeup(port, true); +- else +- stm32_serial_enable_wakeup(port, false); ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) { ++ stm32_usart_serial_en_wakeup(port, true); ++ /* ++ * DMA can't suspend while DMA channels are still active. ++ * Terminate DMA transfer at suspend, and then restart a new ++ * DMA transfer at resume. ++ */ ++ if (stm32_port->rx_ch && tty_port_initialized(tport)) { ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ dmaengine_terminate_sync(stm32_port->rx_ch); ++ } ++ } + +- pinctrl_pm_select_sleep_state(dev); ++ /* ++ * When "no_console_suspend" is enabled, keep the pinctrl default state ++ * and rely on bootloader stage to restore this state upon resume. ++ * Otherwise, apply the idle or sleep states depending on wakeup ++ * capabilities. ++ */ ++ if (console_suspend_enabled || !uart_console(port)) { ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) ++ pinctrl_pm_select_idle_state(dev); ++ else ++ pinctrl_pm_select_sleep_state(dev); ++ } + + return 0; + } + +-static int __maybe_unused stm32_serial_resume(struct device *dev) ++static int __maybe_unused stm32_usart_serial_resume(struct device *dev) + { + struct uart_port *port = dev_get_drvdata(dev); ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct tty_port *tport = &port->state->port; ++ int ret; + + pinctrl_pm_select_default_state(dev); + +- if (device_may_wakeup(dev)) +- stm32_serial_enable_wakeup(port, false); ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) { ++ stm32_usart_serial_en_wakeup(port, false); ++ ++ if (stm32_port->rx_ch && tty_port_initialized(tport)) { ++ ret = stm32_usart_start_rx_dma_cyclic(port); ++ if (ret) ++ return ret; ++ } ++ } + + return uart_resume_port(&stm32_usart_driver, port); + } + +-static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) ++static int __maybe_unused stm32_usart_runtime_suspend(struct device *dev) + { + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, +@@ -1406,7 +1649,7 @@ static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) + return 0; + } + +-static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) ++static int __maybe_unused stm32_usart_runtime_resume(struct device *dev) + { + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, +@@ -1416,14 +1659,15 @@ static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) + } + + static const struct dev_pm_ops stm32_serial_pm_ops = { +- SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, +- stm32_serial_runtime_resume, NULL) +- SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) ++ SET_RUNTIME_PM_OPS(stm32_usart_runtime_suspend, ++ stm32_usart_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(stm32_usart_serial_suspend, ++ stm32_usart_serial_resume) + }; + + static struct platform_driver stm32_serial_driver = { +- .probe = stm32_serial_probe, +- .remove = stm32_serial_remove, ++ .probe = stm32_usart_serial_probe, ++ .remove = stm32_usart_serial_remove, + .driver = { + .name = DRIVER_NAME, + .pm = &stm32_serial_pm_ops, +@@ -1431,7 +1675,7 @@ static struct platform_driver stm32_serial_driver = { + }, + }; + +-static int __init usart_init(void) ++static int __init stm32_usart_init(void) + { + static char banner[] __initdata = "STM32 USART driver initialized"; + int ret; +@@ -1449,14 +1693,14 @@ static int __init usart_init(void) + return ret; + } + +-static void __exit usart_exit(void) ++static void __exit stm32_usart_exit(void) + { + platform_driver_unregister(&stm32_serial_driver); + uart_unregister_driver(&stm32_usart_driver); + } + +-module_init(usart_init); +-module_exit(usart_exit); ++module_init(stm32_usart_init); ++module_exit(stm32_usart_exit); + + MODULE_ALIAS("platform:" DRIVER_NAME); + MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); +diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h +index a175c1094..969b0c6dd 100644 +--- a/drivers/tty/serial/stm32-usart.h ++++ b/drivers/tty/serial/stm32-usart.h +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0 ++/* SPDX-License-Identifier: GPL-2.0 */ + /* + * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics SA 2017 +@@ -106,7 +106,7 @@ struct stm32_usart_info stm32h7_info = { + /* USART_SR (F4) / USART_ISR (F7) */ + #define USART_SR_PE BIT(0) + #define USART_SR_FE BIT(1) +-#define USART_SR_NF BIT(2) ++#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ + #define USART_SR_ORE BIT(3) + #define USART_SR_IDLE BIT(4) + #define USART_SR_RXNE BIT(5) +@@ -123,13 +123,11 @@ struct stm32_usart_info stm32h7_info = { + #define USART_SR_SBKF BIT(18) /* F7 */ + #define USART_SR_WUF BIT(20) /* H7 */ + #define USART_SR_TEACK BIT(21) /* F7 */ +-#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) ++#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\ ++ USART_SR_PE) + /* Dummy bits */ + #define USART_SR_DUMMY_RX BIT(16) + +-/* USART_ICR (F7) */ +-#define USART_CR_TC BIT(6) +- + /* USART_DR */ + #define USART_DR_MASK GENMASK(8, 0) + +@@ -252,9 +250,9 @@ struct stm32_usart_info stm32h7_info = { + #define STM32_SERIAL_NAME "ttySTM" + #define STM32_MAX_PORTS 8 + +-#define RX_BUF_L 200 /* dma rx buffer length */ +-#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ +-#define TX_BUF_L 200 /* dma tx buffer length */ ++#define RX_BUF_L 4096 /* dma rx buffer length */ ++#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ ++#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ + + struct stm32_port { + struct uart_port port; +@@ -272,8 +270,10 @@ struct stm32_port { + bool tx_dma_busy; /* dma tx busy */ + bool hw_flow_control; + bool fifoen; +- int wakeirq; ++ bool wakeup_src; + int rdr_mask; /* receive data register mask */ ++ struct dma_tx_state state; ++ enum dma_status status; + }; + + static struct stm32_port stm32_ports[STM32_MAX_PORTS]; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch new file mode 100644 index 0000000..67f61c6 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch @@ -0,0 +1,2943 @@ +From cad7f0ae4c464edf0d139218f06c9d46e18fb62b Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:47:01 +0200 +Subject: [PATCH 16/23] ARM-stm32mp1-r1-PHY-USB + +--- + drivers/phy/phy-core.c | 48 +- + drivers/phy/st/phy-stm32-usbphyc.c | 485 ++++++++++--- + drivers/usb/dwc2/Kconfig | 1 + + drivers/usb/dwc2/Makefile | 2 +- + drivers/usb/dwc2/core.c | 123 ++-- + drivers/usb/dwc2/core.h | 20 + + drivers/usb/dwc2/core_intr.c | 7 +- + drivers/usb/dwc2/drd.c | 189 +++++ + drivers/usb/dwc2/gadget.c | 7 +- + drivers/usb/dwc2/hcd.c | 6 +- + drivers/usb/dwc2/hw.h | 8 + + drivers/usb/dwc2/params.c | 39 ++ + drivers/usb/dwc2/platform.c | 134 +++- + drivers/usb/gadget/function/f_acm.c | 16 + + drivers/usb/gadget/function/f_serial.c | 16 + + drivers/usb/gadget/function/u_serial.c | 53 +- + drivers/usb/gadget/function/u_serial.h | 2 + + drivers/usb/host/ehci-platform.c | 7 + + drivers/usb/renesas_usbhs/rcar2.c | 2 +- + drivers/usb/renesas_usbhs/rza2.c | 2 +- + drivers/usb/typec/Kconfig | 9 + + drivers/usb/typec/Makefile | 1 + + drivers/usb/typec/class.c | 15 + + drivers/usb/typec/typec_stusb.c | 910 +++++++++++++++++++++++++ + include/linux/phy/phy.h | 9 +- + include/linux/usb/typec.h | 1 + + 26 files changed, 1959 insertions(+), 153 deletions(-) + create mode 100644 drivers/usb/dwc2/drd.c + create mode 100644 drivers/usb/typec/typec_stusb.c + +diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c +index b04f4fe85..8dfb4868c 100644 +--- a/drivers/phy/phy-core.c ++++ b/drivers/phy/phy-core.c +@@ -29,7 +29,7 @@ static void devm_phy_release(struct device *dev, void *res) + { + struct phy *phy = *(struct phy **)res; + +- phy_put(phy); ++ phy_put(dev, phy); + } + + static void devm_phy_provider_release(struct device *dev, void *res) +@@ -566,12 +566,12 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id) + EXPORT_SYMBOL_GPL(of_phy_get); + + /** +- * phy_put() - release the PHY +- * @phy: the phy returned by phy_get() ++ * of_phy_put() - release the PHY ++ * @phy: the phy returned by of_phy_get() + * +- * Releases a refcount the caller received from phy_get(). ++ * Releases a refcount the caller received from of_phy_get(). + */ +-void phy_put(struct phy *phy) ++void of_phy_put(struct phy *phy) + { + if (!phy || IS_ERR(phy)) + return; +@@ -584,6 +584,20 @@ void phy_put(struct phy *phy) + module_put(phy->ops->owner); + put_device(&phy->dev); + } ++EXPORT_SYMBOL_GPL(of_phy_put); ++ ++/** ++ * phy_put() - release the PHY ++ * @dev: device that wants to release this phy ++ * @phy: the phy returned by phy_get() ++ * ++ * Releases a refcount the caller received from phy_get(). ++ */ ++void phy_put(struct device *dev, struct phy *phy) ++{ ++ device_link_remove(dev, &phy->dev); ++ of_phy_put(phy); ++} + EXPORT_SYMBOL_GPL(phy_put); + + /** +@@ -651,6 +665,7 @@ struct phy *phy_get(struct device *dev, const char *string) + { + int index = 0; + struct phy *phy; ++ struct device_link *link; + + if (string == NULL) { + dev_WARN(dev, "missing string\n"); +@@ -672,6 +687,13 @@ struct phy *phy_get(struct device *dev, const char *string) + + get_device(&phy->dev); + ++ link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); ++ if (!link) { ++ dev_err(dev, "failed to create device link to %s\n", ++ dev_name(phy->dev.parent)); ++ return ERR_PTR(-EINVAL); ++ } ++ + return phy; + } + EXPORT_SYMBOL_GPL(phy_get); +@@ -765,6 +787,7 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, + const char *con_id) + { + struct phy **ptr, *phy; ++ struct device_link *link; + + ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) +@@ -778,6 +801,13 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, + devres_free(ptr); + } + ++ link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); ++ if (!link) { ++ dev_err(dev, "failed to create device link to %s\n", ++ dev_name(phy->dev.parent)); ++ return ERR_PTR(-EINVAL); ++ } ++ + return phy; + } + EXPORT_SYMBOL_GPL(devm_of_phy_get); +@@ -798,6 +828,7 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index) + { + struct phy **ptr, *phy; ++ struct device_link *link; + + ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) +@@ -819,6 +850,13 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + *ptr = phy; + devres_add(dev, ptr); + ++ link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); ++ if (!link) { ++ dev_err(dev, "failed to create device link to %s\n", ++ dev_name(phy->dev.parent)); ++ return ERR_PTR(-EINVAL); ++ } ++ + return phy; + } + EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index); +diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c +index 56bdea4b0..4e029c008 100644 +--- a/drivers/phy/st/phy-stm32-usbphyc.c ++++ b/drivers/phy/st/phy-stm32-usbphyc.c +@@ -7,8 +7,9 @@ + */ + #include + #include ++#include + #include +-#include ++#include + #include + #include + #include +@@ -17,6 +18,8 @@ + + #define STM32_USBPHYC_PLL 0x0 + #define STM32_USBPHYC_MISC 0x8 ++#define STM32_USBPHYC_MONITOR(X) (0x108 + (X * 0x100)) ++#define STM32_USBPHYC_TUNE(X) (0x10C + (X * 0x100)) + #define STM32_USBPHYC_VERSION 0x3F4 + + /* STM32_USBPHYC_PLL bit fields */ +@@ -32,19 +35,93 @@ + /* STM32_USBPHYC_MISC bit fields */ + #define SWITHOST BIT(0) + +-/* STM32_USBPHYC_VERSION bit fields */ +-#define MINREV GENMASK(3, 0) +-#define MAJREV GENMASK(7, 4) ++/* STM32_USBPHYC_MONITOR bit fields */ ++#define STM32_USBPHYC_MON_OUT GENMASK(3, 0) ++#define STM32_USBPHYC_MON_SEL GENMASK(8, 4) ++#define STM32_USBPHYC_MON_SEL_LOCKP 0x1F ++#define STM32_USBPHYC_MON_OUT_LOCKP BIT(3) ++ ++/* STM32_USBPHYC_TUNE bit fields */ ++#define INCURREN BIT(0) ++#define INCURRINT BIT(1) ++#define LFSCAPEN BIT(2) ++#define HSDRVSLEW BIT(3) ++#define HSDRVDCCUR BIT(4) ++#define HSDRVDCLEV BIT(5) ++#define HSDRVCURINCR BIT(6) ++#define FSDRVRFADJ BIT(7) ++#define HSDRVRFRED BIT(8) ++#define HSDRVCHKITRM GENMASK(12, 9) ++#define HSDRVCHKZTRM GENMASK(14, 13) ++#define OTPCOMP GENMASK(19, 15) ++#define SQLCHCTL GENMASK(21, 20) ++#define HDRXGNEQEN BIT(22) ++#define HSRXOFF GENMASK(24, 23) ++#define HSFALLPREEM BIT(25) ++#define SHTCCTCTLPROT BIT(26) ++#define STAGSEL BIT(27) ++ ++enum boosting_vals { ++ BOOST_1_MA = 1, ++ BOOST_2_MA, ++ BOOST_MAX, ++}; ++ ++enum dc_level_vals { ++ DC_MINUS_5_TO_7_MV, ++ DC_PLUS_5_TO_7_MV, ++ DC_PLUS_10_TO_14_MV, ++ DC_MAX, ++}; + +-static const char * const supplies_names[] = { +- "vdda1v1", /* 1V1 */ +- "vdda1v8", /* 1V8 */ ++enum current_trim { ++ CUR_NOMINAL, ++ CUR_PLUS_1_56_PCT, ++ CUR_PLUS_3_12_PCT, ++ CUR_PLUS_4_68_PCT, ++ CUR_PLUS_6_24_PCT, ++ CUR_PLUS_7_8_PCT, ++ CUR_PLUS_9_36_PCT, ++ CUR_PLUS_10_92_PCT, ++ CUR_PLUS_12_48_PCT, ++ CUR_PLUS_14_04_PCT, ++ CUR_PLUS_15_6_PCT, ++ CUR_PLUS_17_16_PCT, ++ CUR_PLUS_19_01_PCT, ++ CUR_PLUS_20_58_PCT, ++ CUR_PLUS_22_16_PCT, ++ CUR_PLUS_23_73_PCT, ++ CUR_MAX, + }; + +-#define NUM_SUPPLIES ARRAY_SIZE(supplies_names) ++enum impedance_trim { ++ IMP_NOMINAL, ++ IMP_MINUS_2_OHMS, ++ IMP_MINUS_4_OMHS, ++ IMP_MINUS_6_OHMS, ++ IMP_MAX, ++}; ++ ++enum squelch_level { ++ SQLCH_NOMINAL, ++ SQLCH_PLUS_7_MV, ++ SQLCH_MINUS_5_MV, ++ SQLCH_PLUS_14_MV, ++ SQLCH_MAX, ++}; ++ ++enum rx_offset { ++ NO_RX_OFFSET, ++ RX_OFFSET_PLUS_5_MV, ++ RX_OFFSET_PLUS_10_MV, ++ RX_OFFSET_MINUS_5_MV, ++ RX_OFFSET_MAX, ++}; ++ ++/* STM32_USBPHYC_VERSION bit fields */ ++#define MINREV GENMASK(3, 0) ++#define MAJREV GENMASK(7, 4) + +-#define PLL_LOCK_TIME_US 100 +-#define PLL_PWR_DOWN_TIME_US 5 + #define PLL_FVCO_MHZ 2880 + #define PLL_INFF_MIN_RATE_HZ 19200000 + #define PLL_INFF_MAX_RATE_HZ 38400000 +@@ -58,7 +135,6 @@ struct pll_params { + struct stm32_usbphyc_phy { + struct phy *phy; + struct stm32_usbphyc *usbphyc; +- struct regulator_bulk_data supplies[NUM_SUPPLIES]; + u32 index; + bool active; + }; +@@ -70,6 +146,10 @@ struct stm32_usbphyc { + struct reset_control *rst; + struct stm32_usbphyc_phy **phys; + int nphys; ++ struct regulator *vdda1v1; ++ struct regulator *vdda1v8; ++ atomic_t n_pll_cons; ++ struct clk_hw clk48_hw; + int switch_setup; + }; + +@@ -83,6 +163,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) + writel_relaxed(readl_relaxed(reg) & ~bits, reg); + } + ++static int stm32_usbphyc_regulators_enable(struct stm32_usbphyc *usbphyc) ++{ ++ int ret; ++ ++ ret = regulator_enable(usbphyc->vdda1v1); ++ if (ret) ++ return ret; ++ ++ ret = regulator_enable(usbphyc->vdda1v8); ++ if (ret) ++ goto vdda1v1_disable; ++ ++ return 0; ++ ++vdda1v1_disable: ++ regulator_disable(usbphyc->vdda1v1); ++ ++ return ret; ++} ++ ++static int stm32_usbphyc_regulators_disable(struct stm32_usbphyc *usbphyc) ++{ ++ int ret; ++ ++ ret = regulator_disable(usbphyc->vdda1v8); ++ if (ret) ++ return ret; ++ ++ ret = regulator_disable(usbphyc->vdda1v1); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + static void stm32_usbphyc_get_pll_params(u32 clk_rate, + struct pll_params *pll_params) + { +@@ -142,83 +257,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) + return 0; + } + +-static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) ++static int __stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) + { +- int i; ++ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; ++ u32 pllen; + +- for (i = 0; i < usbphyc->nphys; i++) +- if (usbphyc->phys[i]->active) +- return true; ++ stm32_usbphyc_clr_bits(pll_reg, PLLEN); ++ ++ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ ++ if (readl_relaxed_poll_timeout(pll_reg, pllen, !(pllen & PLLEN), 5, 50)) ++ dev_err(usbphyc->dev, "PLL not reset\n"); + +- return false; ++ return stm32_usbphyc_regulators_disable(usbphyc); ++} ++ ++static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) ++{ ++ /* Check if a phy port is still active or clk48 in use */ ++ if (atomic_dec_return(&usbphyc->n_pll_cons) > 0) ++ return 0; ++ ++ return __stm32_usbphyc_pll_disable(usbphyc); + } + + static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) + { + void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; +- bool pllen = (readl_relaxed(pll_reg) & PLLEN); ++ bool pllen = readl_relaxed(pll_reg) & PLLEN; + int ret; + +- /* Check if one phy port has already configured the pll */ +- if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc)) ++ /* ++ * Check if a phy port or clk48 prepare has configured the pll ++ * and ensure the PLL is enabled ++ */ ++ if(atomic_inc_return(&usbphyc->n_pll_cons) > 1 && pllen) + return 0; + + if (pllen) { +- stm32_usbphyc_clr_bits(pll_reg, PLLEN); +- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ +- udelay(PLL_PWR_DOWN_TIME_US); ++ /* ++ * PLL shouldn't be enabled without known consumer, ++ * disable it and reinit n_pll_cons ++ */ ++ dev_warn(usbphyc->dev, "PLL enabled without known consumers\n"); ++ ++ ret = __stm32_usbphyc_pll_disable(usbphyc); ++ if (ret) ++ return ret; + } + ++ ret = stm32_usbphyc_regulators_enable(usbphyc); ++ if (ret) ++ goto dec_n_pll_cons; ++ + ret = stm32_usbphyc_pll_init(usbphyc); + if (ret) +- return ret; ++ goto reg_disable; + + stm32_usbphyc_set_bits(pll_reg, PLLEN); + +- /* Wait for maximum lock time */ +- udelay(PLL_LOCK_TIME_US); +- +- if (!(readl_relaxed(pll_reg) & PLLEN)) { +- dev_err(usbphyc->dev, "PLLEN not set\n"); +- return -EIO; +- } +- + return 0; +-} + +-static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) +-{ +- void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; ++reg_disable: ++ stm32_usbphyc_regulators_disable(usbphyc); + +- /* Check if other phy port active */ +- if (stm32_usbphyc_has_one_phy_active(usbphyc)) +- return 0; +- +- stm32_usbphyc_clr_bits(pll_reg, PLLEN); +- /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ +- udelay(PLL_PWR_DOWN_TIME_US); +- +- if (readl_relaxed(pll_reg) & PLLEN) { +- dev_err(usbphyc->dev, "PLL not reset\n"); +- return -EIO; +- } ++dec_n_pll_cons: ++ atomic_dec(&usbphyc->n_pll_cons); + +- return 0; ++ return ret; + } + + static int stm32_usbphyc_phy_init(struct phy *phy) + { + struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); + struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc; ++ u32 reg_mon = STM32_USBPHYC_MONITOR(usbphyc_phy->index); ++ u32 monsel = FIELD_PREP(STM32_USBPHYC_MON_SEL, ++ STM32_USBPHYC_MON_SEL_LOCKP); ++ u32 monout; + int ret; + + ret = stm32_usbphyc_pll_enable(usbphyc); + if (ret) + return ret; + ++ /* Check that PLL Lock input to PHY is High */ ++ writel_relaxed(monsel, usbphyc->base + reg_mon); ++ ret = readl_relaxed_poll_timeout(usbphyc->base + reg_mon, monout, ++ monout & STM32_USBPHYC_MON_OUT_LOCKP, ++ 100, 1000); ++ if (ret) { ++ dev_err(usbphyc->dev, "PLL Lock input to PHY is Low (val=%x)\n", ++ (u32)(monout & STM32_USBPHYC_MON_OUT)); ++ goto pll_disable; ++ } ++ + usbphyc_phy->active = true; + + return 0; ++ ++pll_disable: ++ return stm32_usbphyc_pll_disable(usbphyc); + } + + static int stm32_usbphyc_phy_exit(struct phy *phy) +@@ -231,28 +369,168 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) + return stm32_usbphyc_pll_disable(usbphyc); + } + +-static int stm32_usbphyc_phy_power_on(struct phy *phy) ++static const struct phy_ops stm32_usbphyc_phy_ops = { ++ .init = stm32_usbphyc_phy_init, ++ .exit = stm32_usbphyc_phy_exit, ++ .owner = THIS_MODULE, ++}; ++ ++static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) + { +- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); ++ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, ++ clk48_hw); + +- return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies); ++ return stm32_usbphyc_pll_enable(usbphyc); + } + +-static int stm32_usbphyc_phy_power_off(struct phy *phy) ++static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) + { +- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); ++ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, ++ clk48_hw); + +- return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies); ++ stm32_usbphyc_pll_disable(usbphyc); + } + +-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, +- .owner = THIS_MODULE, ++static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return 48000000; ++} ++ ++static const struct clk_ops usbphyc_clk48_ops = { ++ .prepare = stm32_usbphyc_clk48_prepare, ++ .unprepare = stm32_usbphyc_clk48_unprepare, ++ .recalc_rate = stm32_usbphyc_clk48_recalc_rate, + }; + ++static void stm32_usbphyc_clk48_unregister(void *data) ++{ ++ struct stm32_usbphyc *usbphyc = data; ++ ++ of_clk_del_provider(usbphyc->dev->of_node); ++ clk_hw_unregister(&usbphyc->clk48_hw); ++} ++ ++static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) ++{ ++ struct device_node *node = usbphyc->dev->of_node; ++ struct clk_init_data init = { }; ++ int ret = 0; ++ ++ init.name = "ck_usbo_48m"; ++ init.ops = &usbphyc_clk48_ops; ++ ++ usbphyc->clk48_hw.init = &init; ++ ++ ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); ++ if (ret) ++ return ret; ++ ++ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, ++ &usbphyc->clk48_hw); ++ if (ret) ++ clk_hw_unregister(&usbphyc->clk48_hw); ++ ++ return ret; ++} ++ ++static void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc, ++ struct device_node *np, u32 index) ++{ ++ struct device_node *tune_np; ++ u32 reg = STM32_USBPHYC_TUNE(index); ++ u32 otpcomp, val, tune = 0; ++ int ret; ++ ++ tune_np = of_parse_phandle(np, "st,phy-tuning", 0); ++ if (!tune_np) ++ return; ++ ++ /* Backup OTP compensation code */ ++ otpcomp = FIELD_GET(OTPCOMP, readl_relaxed(usbphyc->base + reg)); ++ ++ ret = of_property_read_u32(tune_np, "st,current-boost", &val); ++ if (!ret && val < BOOST_MAX) { ++ val = (val == BOOST_2_MA) ? 1 : 0; ++ tune |= INCURREN | FIELD_PREP(INCURRINT, val); ++ } else if (ret != -EINVAL) { ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid st,current-boost value\n", index); ++ } ++ ++ if (!of_property_read_bool(tune_np, "st,no-lsfs-fb-cap")) ++ tune |= LFSCAPEN; ++ ++ if (of_property_read_bool(tune_np, "st,hs-slew-ctrl")) ++ tune |= HSDRVSLEW; ++ ++ ret = of_property_read_u32(tune_np, "st,hs-dc-level", &val); ++ if (!ret && val < DC_MAX) { ++ if (val == DC_MINUS_5_TO_7_MV) { ++ tune |= HSDRVDCCUR; ++ } else { ++ val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; ++ tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); ++ } ++ } else if (ret != -EINVAL) { ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid st,hs-dc-level value\n", index); ++ } ++ ++ if (of_property_read_bool(tune_np, "st,fs-rftime-tuning")) ++ tune |= FSDRVRFADJ; ++ ++ if (of_property_read_bool(tune_np, "st,hs-rftime-reduction")) ++ tune |= HSDRVRFRED; ++ ++ ret = of_property_read_u32(tune_np, "st,hs-current-trim", &val); ++ if (!ret && val < CUR_MAX) ++ tune |= FIELD_PREP(HSDRVCHKITRM, val); ++ else if (ret != -EINVAL) ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid st,hs-current-trim value\n", index); ++ ++ ret = of_property_read_u32(tune_np, "st,hs-impedance-trim", &val); ++ if (!ret && val < IMP_MAX) ++ tune |= FIELD_PREP(HSDRVCHKZTRM, val); ++ else if (ret != -EINVAL) ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid hs-impedance-trim value\n", index); ++ ++ ret = of_property_read_u32(tune_np, "st,squelch-level", &val); ++ if (!ret && val < SQLCH_MAX) ++ tune |= FIELD_PREP(SQLCHCTL, val); ++ else if (ret != -EINVAL) ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid st,squelch-level value\n", index); ++ ++ if (of_property_read_bool(tune_np, "st,hs-rx-gain-eq")) ++ tune |= HDRXGNEQEN; ++ ++ ret = of_property_read_u32(tune_np, "st,hs-rx-offset", &val); ++ if (!ret && val < RX_OFFSET_MAX) ++ tune |= FIELD_PREP(HSRXOFF, val); ++ else if (ret != -EINVAL) ++ dev_warn(usbphyc->dev, ++ "phy%d: invalid st,hs-rx-offset value\n", index); ++ ++ if (of_property_read_bool(tune_np, "st,no-hs-ftime-ctrl")) ++ tune |= HSFALLPREEM; ++ ++ if (!of_property_read_bool(tune_np, "st,no-lsfs-sc")) ++ tune |= SHTCCTCTLPROT; ++ ++ if (of_property_read_bool(tune_np, "st,hs-tx-staggering")) ++ tune |= STAGSEL; ++ ++ of_node_put(tune_np); ++ ++ /* Restore OTP compensation code */ ++ tune |= FIELD_PREP(OTPCOMP, otpcomp); ++ ++ writel_relaxed(tune, usbphyc->base + reg); ++} ++ + static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, + u32 utmi_switch) + { +@@ -313,7 +591,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + struct device_node *child, *np = dev->of_node; + struct resource *res; + struct phy_provider *phy_provider; +- u32 version; ++ u32 pllen, version; + int ret, port = 0; + + usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); +@@ -330,7 +608,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + usbphyc->clk = devm_clk_get(dev, 0); + if (IS_ERR(usbphyc->clk)) { + ret = PTR_ERR(usbphyc->clk); +- dev_err(dev, "clk get failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "clk get failed: %d\n", ret); + return ret; + } + +@@ -345,6 +624,24 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + reset_control_assert(usbphyc->rst); + udelay(2); + reset_control_deassert(usbphyc->rst); ++ } else { ++ ret = PTR_ERR(usbphyc->rst); ++ if (ret == -EPROBE_DEFER) ++ goto clk_disable; ++ ++ stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_PLL, ++ PLLEN); ++ } ++ ++ /* ++ * Wait for minimum width of powerdown pulse (ENABLE = Low): ++ * we have to ensure the PLL is disabled before phys initialization. ++ */ ++ if (readl_relaxed_poll_timeout(usbphyc->base + STM32_USBPHYC_PLL, ++ pllen, !(pllen & PLLEN), 5, 50)) { ++ dev_warn(usbphyc->dev, "PLL not reset\n"); ++ ret = -EPROBE_DEFER; ++ goto clk_disable; + } + + usbphyc->switch_setup = -EINVAL; +@@ -356,11 +653,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + goto clk_disable; + } + ++ usbphyc->vdda1v1 = devm_regulator_get(dev, "vdda1v1"); ++ if (IS_ERR(usbphyc->vdda1v1)) { ++ ret = PTR_ERR(usbphyc->vdda1v1); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to get vdda1v1 supply: %d\n", ret); ++ goto clk_disable; ++ } ++ ++ usbphyc->vdda1v8 = devm_regulator_get(dev, "vdda1v8"); ++ if (IS_ERR(usbphyc->vdda1v8)) { ++ ret = PTR_ERR(usbphyc->vdda1v8); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to get vdda1v8 supply: %d\n", ret); ++ goto clk_disable; ++ } ++ + for_each_child_of_node(np, child) { + struct stm32_usbphyc_phy *usbphyc_phy; + struct phy *phy; + u32 index; +- int i; + + phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); + if (IS_ERR(phy)) { +@@ -378,24 +690,15 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + goto put_child; + } + +- for (i = 0; i < NUM_SUPPLIES; i++) +- usbphyc_phy->supplies[i].supply = supplies_names[i]; +- +- ret = devm_regulator_bulk_get(&phy->dev, NUM_SUPPLIES, +- usbphyc_phy->supplies); +- if (ret) { +- if (ret != -EPROBE_DEFER) +- dev_err(&phy->dev, +- "failed to get regulators: %d\n", ret); +- goto put_child; +- } +- + ret = of_property_read_u32(child, "reg", &index); + if (ret || index > usbphyc->nphys) { + dev_err(&phy->dev, "invalid reg property: %d\n", ret); + goto put_child; + } + ++ /* Configure phy tuning */ ++ stm32_usbphyc_phy_tuning(usbphyc, child, index); ++ + usbphyc->phys[port] = usbphyc_phy; + phy_set_bus_width(phy, 8); + phy_set_drvdata(phy, usbphyc_phy); +@@ -416,6 +719,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + goto clk_disable; + } + ++ ret = stm32_usbphyc_clk48_register(usbphyc); ++ if (ret) { ++ dev_err(dev, ++ "failed to register ck_usbo_48m clock: %d\n", ret); ++ goto clk_disable; ++ } ++ + version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); + dev_info(dev, "registered rev:%lu.%lu\n", + FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); +@@ -433,12 +743,34 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + static int stm32_usbphyc_remove(struct platform_device *pdev) + { + struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); ++ int port; ++ ++ stm32_usbphyc_clk48_unregister(usbphyc); ++ ++ /* Ensure PHYs are not active, to allow PLL disabling */ ++ for (port = 0; port < usbphyc->nphys; port++) ++ if (usbphyc->phys[port]->active) ++ stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); + + clk_disable_unprepare(usbphyc->clk); + + return 0; + } + ++#ifdef CONFIG_PM_SLEEP ++static int stm32_usbphyc_resume(struct device *dev) ++{ ++ struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); ++ ++ if (usbphyc->switch_setup >= 0) ++ stm32_usbphyc_switch_setup(usbphyc, usbphyc->switch_setup); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(stm32_usbphyc_pm_ops, NULL, stm32_usbphyc_resume); ++ + static const struct of_device_id stm32_usbphyc_of_match[] = { + { .compatible = "st,stm32mp1-usbphyc", }, + { }, +@@ -451,6 +783,7 @@ static struct platform_driver stm32_usbphyc_driver = { + .driver = { + .of_match_table = stm32_usbphyc_of_match, + .name = "stm32-usbphyc", ++ .pm = &stm32_usbphyc_pm_ops, + } + }; + module_platform_driver(stm32_usbphyc_driver); +diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig +index 16e1aa304..dceb8f324 100644 +--- a/drivers/usb/dwc2/Kconfig ++++ b/drivers/usb/dwc2/Kconfig +@@ -47,6 +47,7 @@ config USB_DWC2_PERIPHERAL + config USB_DWC2_DUAL_ROLE + bool "Dual Role mode" + depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET) ++ select USB_ROLE_SWITCH + help + Select this option if you want the driver to work in a dual-role + mode. In this mode both host and gadget features are enabled, and +diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile +index 440320cc2..2bcd6945d 100644 +--- a/drivers/usb/dwc2/Makefile ++++ b/drivers/usb/dwc2/Makefile +@@ -3,7 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG + ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG + + obj-$(CONFIG_USB_DWC2) += dwc2.o +-dwc2-y := core.o core_intr.o platform.o ++dwc2-y := core.o core_intr.o platform.o drd.o + dwc2-y += params.o + + ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) +diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c +index 78a4925aa..d1c6a8a9d 100644 +--- a/drivers/usb/dwc2/core.c ++++ b/drivers/usb/dwc2/core.c +@@ -83,6 +83,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) + gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); + gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); + gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); ++ gr->ggpio = dwc2_readl(hsotg, GGPIO); + gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); + + gr->valid = true; +@@ -112,21 +113,82 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) + gr->valid = false; + + dwc2_writel(hsotg, 0xffffffff, GINTSTS); ++ dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); ++ dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); + dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); + dwc2_writel(hsotg, gr->gintmsk, GINTMSK); +- dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); +- dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); + dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); + dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); + dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); + dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); + dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); + dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); ++ dwc2_writel(hsotg, gr->ggpio, GGPIO); + dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); + + return 0; + } + ++int dwc2_backup_registers(struct dwc2_hsotg *hsotg) ++{ ++ int ret; ++ ++ /* Backup all registers */ ++ ret = dwc2_backup_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup global registers\n", ++ __func__); ++ return ret; ++ } ++ ++ if (dwc2_is_host_mode(hsotg)) { ++ ret = dwc2_backup_host_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup host registers\n", ++ __func__); ++ return ret; ++ } ++ } else { ++ ret = dwc2_backup_device_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup device registers\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int dwc2_restore_registers(struct dwc2_hsotg *hsotg) ++{ ++ int ret; ++ ++ ret = dwc2_restore_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore registers\n", ++ __func__); ++ return ret; ++ } ++ if (dwc2_is_host_mode(hsotg)) { ++ ret = dwc2_restore_host_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore host registers\n", ++ __func__); ++ return ret; ++ } ++ } else { ++ ret = dwc2_restore_device_registers(hsotg, 0); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore device registers\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + /** + * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. + * +@@ -136,7 +198,6 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) + int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) + { + u32 pcgcctl; +- int ret = 0; + + if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) + return -ENOTSUPP; +@@ -154,31 +215,11 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) + dwc2_writel(hsotg, pcgcctl, PCGCTL); + + udelay(100); +- if (restore) { +- ret = dwc2_restore_global_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore registers\n", +- __func__); +- return ret; +- } +- if (dwc2_is_host_mode(hsotg)) { +- ret = dwc2_restore_host_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore host registers\n", +- __func__); +- return ret; +- } +- } else { +- ret = dwc2_restore_device_registers(hsotg, 0); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore device registers\n", +- __func__); +- return ret; +- } +- } +- } + +- return ret; ++ if (restore) ++ return dwc2_restore_registers(hsotg); ++ ++ return 0; + } + + /** +@@ -189,34 +230,14 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) + int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) + { + u32 pcgcctl; +- int ret = 0; ++ int ret; + + if (!hsotg->params.power_down) + return -ENOTSUPP; + +- /* Backup all registers */ +- ret = dwc2_backup_global_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup global registers\n", +- __func__); ++ ret = dwc2_backup_registers(hsotg); ++ if (ret) + return ret; +- } +- +- if (dwc2_is_host_mode(hsotg)) { +- ret = dwc2_backup_host_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup host registers\n", +- __func__); +- return ret; +- } +- } else { +- ret = dwc2_backup_device_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup device registers\n", +- __func__); +- return ret; +- } +- } + + /* + * Clear any pending interrupts since dwc2 will not be able to +@@ -238,7 +259,7 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) + pcgcctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + +- return ret; ++ return 0; + } + + /** +diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h +index d08d070a0..ab67c2127 100644 +--- a/drivers/usb/dwc2/core.h ++++ b/drivers/usb/dwc2/core.h +@@ -411,6 +411,10 @@ enum dwc2_ep0_state { + * register. + * 0 - Deactivate the transceiver (default) + * 1 - Activate the transceiver ++ * @activate_stm_id_vb_detection: Activate external ID pin and Vbuslevel ++ * detection using GGPIO register. ++ * 0 - Deactivate the external level detection (default) ++ * 1 - Activate the external level detection + * @g_dma: Enables gadget dma usage (default: autodetect). + * @g_dma_desc: Enables gadget descriptor DMA (default: autodetect). + * @g_rx_fifo_size: The periodic rx fifo size for the device, in +@@ -481,6 +485,7 @@ struct dwc2_core_params { + bool service_interval; + u8 hird_threshold; + bool activate_stm_fs_transceiver; ++ bool activate_stm_id_vb_detection; + bool ipg_isoc_en; + u16 max_packet_count; + u32 max_transfer_size; +@@ -680,6 +685,7 @@ struct dwc2_hw_params { + * @grxfsiz: Backup of GRXFSIZ register + * @gnptxfsiz: Backup of GNPTXFSIZ register + * @gi2cctl: Backup of GI2CCTL register ++ * @ggpio: Backup of GGPIO register + * @glpmcfg: Backup of GLPMCFG register + * @gdfifocfg: Backup of GDFIFOCFG register + * @pcgcctl: Backup of PCGCCTL register +@@ -696,6 +702,7 @@ struct dwc2_gregs_backup { + u32 grxfsiz; + u32 gnptxfsiz; + u32 gi2cctl; ++ u32 ggpio; + u32 glpmcfg; + u32 pcgcctl; + u32 pcgcctl1; +@@ -855,6 +862,7 @@ struct dwc2_hregs_backup { + * - USB_DR_MODE_PERIPHERAL + * - USB_DR_MODE_HOST + * - USB_DR_MODE_OTG ++ * @role_sw: usb_role_switch handle + * @hcd_enabled: Host mode sub-driver initialization indicator. + * @gadget_enabled: Peripheral mode sub-driver initialization indicator. + * @ll_hw_enabled: Status of low-level hardware resources. +@@ -874,6 +882,8 @@ struct dwc2_hregs_backup { + * removed once all SoCs support usb transceiver. + * @supplies: Definition of USB power supplies + * @vbus_supply: Regulator supplying vbus. ++ * @usb33d: Optional 3.3v regulator used on some stm32 devices to ++ * supply ID and VBUS detection hardware. + * @lock: Spinlock that protects all the driver data structures + * @priv: Stores a pointer to the struct usb_hcd + * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth +@@ -1047,6 +1057,7 @@ struct dwc2_hsotg { + struct dwc2_core_params params; + enum usb_otg_state op_state; + enum usb_dr_mode dr_mode; ++ struct usb_role_switch *role_sw; + unsigned int hcd_enabled:1; + unsigned int gadget_enabled:1; + unsigned int ll_hw_enabled:1; +@@ -1061,6 +1072,7 @@ struct dwc2_hsotg { + struct dwc2_hsotg_plat *plat; + struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; + struct regulator *vbus_supply; ++ struct regulator *usb33d; + + spinlock_t lock; + void *priv; +@@ -1315,6 +1327,8 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); + + void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, + int is_host); ++int dwc2_backup_registers(struct dwc2_hsotg *hsotg); ++int dwc2_restore_registers(struct dwc2_hsotg *hsotg); + int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg); + int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg); + +@@ -1364,6 +1378,11 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) + return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0; + } + ++int dwc2_drd_init(struct dwc2_hsotg *hsotg); ++void dwc2_drd_suspend(struct dwc2_hsotg *hsotg); ++void dwc2_drd_resume(struct dwc2_hsotg *hsotg); ++void dwc2_drd_exit(struct dwc2_hsotg *hsotg); ++ + /* + * Dump core registers and SPRAM + */ +@@ -1380,6 +1399,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); + int dwc2_gadget_init(struct dwc2_hsotg *hsotg); + void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, + bool reset); ++void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg); + void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); + void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); + int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); +diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c +index 6af6add3d..6272b4ae4 100644 +--- a/drivers/usb/dwc2/core_intr.c ++++ b/drivers/usb/dwc2/core_intr.c +@@ -421,10 +421,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) + if (ret && (ret != -ENOTSUPP)) + dev_err(hsotg->dev, "exit power_down failed\n"); + ++ /* Change to L0 state */ ++ hsotg->lx_state = DWC2_L0; + call_gadget(hsotg, resume); ++ } else { ++ /* Change to L0 state */ ++ hsotg->lx_state = DWC2_L0; + } +- /* Change to L0 state */ +- hsotg->lx_state = DWC2_L0; + } else { + if (hsotg->params.power_down) + return; +diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c +new file mode 100644 +index 000000000..8de90d7b2 +--- /dev/null ++++ b/drivers/usb/dwc2/drd.c +@@ -0,0 +1,189 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * drd.c - DesignWare USB2 DRD Controller Dual-role support ++ * ++ * Copyright (C) 2019 STMicroelectronics ++ * ++ * Author(s): Amelie Delaunay ++ */ ++ ++#include ++#include ++#include ++#include "core.h" ++ ++static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) ++{ ++ unsigned long flags; ++ u32 gotgctl; ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ ++ gotgctl = dwc2_readl(hsotg, GOTGCTL); ++ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN; ++ gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; ++ gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); ++ dwc2_writel(hsotg, gotgctl, GOTGCTL); ++ ++ dwc2_force_mode(hsotg, false); ++ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++} ++ ++static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) ++{ ++ u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); ++ ++ /* Check if A-Session is already in the right state */ ++ if ((valid && (gotgctl & GOTGCTL_ASESVLD)) || ++ (!valid && !(gotgctl & GOTGCTL_ASESVLD))) ++ return -EALREADY; ++ ++ if (valid) ++ gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; ++ else ++ gotgctl &= ~(GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); ++ dwc2_writel(hsotg, gotgctl, GOTGCTL); ++ ++ return 0; ++} ++ ++static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) ++{ ++ u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); ++ ++ /* Check if B-Session is already in the right state */ ++ if ((valid && (gotgctl & GOTGCTL_BSESVLD)) || ++ (!valid && !(gotgctl & GOTGCTL_BSESVLD))) ++ return -EALREADY; ++ ++ if (valid) ++ gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; ++ else ++ gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL); ++ dwc2_writel(hsotg, gotgctl, GOTGCTL); ++ ++ return 0; ++} ++ ++static int dwc2_drd_role_sw_set(struct device *dev, enum usb_role role) ++{ ++ struct dwc2_hsotg *hsotg = dev_get_drvdata(dev); ++ unsigned long flags; ++ ++ /* Skip session not in line with dr_mode */ ++ if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) || ++ (role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) ++ return -EINVAL; ++ ++ /* Skip session if core is in test mode */ ++ if (role == USB_ROLE_NONE && hsotg->test_mode) { ++ dev_dbg(hsotg->dev, "Core is in test mode\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ ++ if (role == USB_ROLE_HOST) { ++ if (dwc2_ovr_avalid(hsotg, true)) ++ goto unlock; ++ ++ if (hsotg->dr_mode == USB_DR_MODE_OTG) ++ /* ++ * This will raise a Connector ID Status Change ++ * Interrupt - connID A ++ */ ++ dwc2_force_mode(hsotg, true); ++ } else if (role == USB_ROLE_DEVICE) { ++ if (dwc2_ovr_bvalid(hsotg, true)) ++ goto unlock; ++ ++ if (hsotg->dr_mode == USB_DR_MODE_OTG) ++ /* ++ * This will raise a Connector ID Status Change ++ * Interrupt - connID B ++ */ ++ dwc2_force_mode(hsotg, false); ++ ++ /* This clear DCTL.SFTDISCON bit */ ++ dwc2_hsotg_core_connect(hsotg); ++ } else { ++ if (dwc2_is_device_mode(hsotg)) { ++ if (!dwc2_ovr_bvalid(hsotg, false)) ++ /* This set DCTL.SFTDISCON bit */ ++ dwc2_hsotg_core_disconnect(hsotg); ++ } else { ++ dwc2_ovr_avalid(hsotg, false); ++ } ++ } ++ ++unlock: ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ ++ dev_dbg(hsotg->dev, "%s-session valid\n", ++ role == USB_ROLE_NONE ? "No" : ++ role == USB_ROLE_HOST ? "A" : "B"); ++ ++ return 0; ++} ++ ++int dwc2_drd_init(struct dwc2_hsotg *hsotg) ++{ ++ int ret; ++ ++ if (device_property_read_bool(hsotg->dev, "usb-role-switch")) { ++ struct usb_role_switch_desc role_sw_desc = {0}; ++ struct usb_role_switch *role_sw; ++ ++ role_sw_desc.fwnode = dev_fwnode(hsotg->dev); ++ role_sw_desc.set = dwc2_drd_role_sw_set; ++ role_sw_desc.allow_userspace_control = true; ++ ++ role_sw = usb_role_switch_register(hsotg->dev, &role_sw_desc); ++ if (IS_ERR(role_sw)) { ++ ret = PTR_ERR(role_sw); ++ dev_err(hsotg->dev, ++ "unable to register role switch: %d\n", ret); ++ return ret; ++ } ++ ++ hsotg->role_sw = role_sw; ++ ++ /* Enable override and initialize values */ ++ dwc2_ovr_init(hsotg); ++ } ++ ++ return 0; ++} ++ ++void dwc2_drd_suspend(struct dwc2_hsotg *hsotg) ++{ ++ u32 gintsts, gintmsk; ++ ++ if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { ++ gintmsk = dwc2_readl(hsotg, GINTMSK); ++ gintmsk &= ~GINTSTS_CONIDSTSCHNG; ++ dwc2_writel(hsotg, gintmsk, GINTMSK); ++ gintsts = dwc2_readl(hsotg, GINTSTS); ++ dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); ++ } ++} ++ ++void dwc2_drd_resume(struct dwc2_hsotg *hsotg) ++{ ++ u32 gintsts, gintmsk; ++ ++ if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { ++ gintsts = dwc2_readl(hsotg, GINTSTS); ++ dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); ++ gintmsk = dwc2_readl(hsotg, GINTMSK); ++ gintmsk |= GINTSTS_CONIDSTSCHNG; ++ dwc2_writel(hsotg, gintmsk, GINTMSK); ++ } ++} ++ ++void dwc2_drd_exit(struct dwc2_hsotg *hsotg) ++{ ++ if (hsotg->role_sw) ++ usb_role_switch_unregister(hsotg->role_sw); ++} +diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c +index 7fd0900a9..f1e8323c0 100644 +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -3531,7 +3531,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, + dwc2_readl(hsotg, DOEPCTL0)); + } + +-static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) ++void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) + { + /* set the soft-disconnect bit */ + dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); +@@ -3540,7 +3540,8 @@ static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) + void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) + { + /* remove the soft-disconnect and let's go */ +- dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); ++ if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) ++ dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); + } + + /** +@@ -4930,7 +4931,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); + +- for (ep = 0; ep < hsotg->num_of_eps; ep++) { ++ for (ep = 1; ep < hsotg->num_of_eps; ep++) { + if (hsotg->eps_in[ep]) + dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); + if (hsotg->eps_out[ep]) +diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c +index 81afe553a..f89e6d003 100644 +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -1735,7 +1735,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) + * release_channel_ddma(), which is called from ep_disable when + * device disconnects + */ +- channel->qh = NULL; ++ if (hsotg->params.host_dma && hsotg->params.dma_desc_enable) ++ channel->qh = NULL; + } + /* All channels have been freed, mark them available */ + if (hsotg->params.uframe_sched) { +@@ -3611,7 +3612,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) + goto error; + +- if (!hsotg->flags.b.port_connect_status) { ++ if (!hsotg->flags.b.port_connect_status && ++ !dwc2_is_host_mode(hsotg)) { + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just +diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h +index 510e87ec0..c4027bbce 100644 +--- a/drivers/usb/dwc2/hw.h ++++ b/drivers/usb/dwc2/hw.h +@@ -54,6 +54,12 @@ + #define GOTGCTL_HSTSETHNPEN BIT(10) + #define GOTGCTL_HNPREQ BIT(9) + #define GOTGCTL_HSTNEGSCS BIT(8) ++#define GOTGCTL_BVALOVAL BIT(7) ++#define GOTGCTL_BVALOEN BIT(6) ++#define GOTGCTL_AVALOVAL BIT(5) ++#define GOTGCTL_AVALOEN BIT(4) ++#define GOTGCTL_VBVALOVAL BIT(3) ++#define GOTGCTL_VBVALOEN BIT(2) + #define GOTGCTL_SESREQ BIT(1) + #define GOTGCTL_SESREQSCS BIT(0) + +@@ -227,6 +233,8 @@ + #define GPVNDCTL HSOTG_REG(0x0034) + #define GGPIO HSOTG_REG(0x0038) + #define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) ++#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) ++#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) + + #define GUID HSOTG_REG(0x003c) + #define GSNPSID HSOTG_REG(0x0040) +diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c +index 31e090ac9..f7c947cdc 100644 +--- a/drivers/usb/dwc2/params.c ++++ b/drivers/usb/dwc2/params.c +@@ -163,6 +163,41 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) + p->host_perio_tx_fifo_size = 256; + } + ++static void dwc2_set_stm32mp1_fsotg_params(struct dwc2_hsotg *hsotg) ++{ ++ struct dwc2_core_params *p = &hsotg->params; ++ ++ p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ p->speed = DWC2_SPEED_PARAM_FULL; ++ p->host_rx_fifo_size = 128; ++ p->host_nperio_tx_fifo_size = 96; ++ p->host_perio_tx_fifo_size = 96; ++ p->max_packet_count = 256; ++ p->phy_type = DWC2_PHY_TYPE_PARAM_FS; ++ p->i2c_enable = false; ++ p->activate_stm_fs_transceiver = true; ++ p->activate_stm_id_vb_detection = true; ++ p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; ++ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; ++ p->host_support_fs_ls_low_power = true; ++ p->host_ls_low_power_phy_clk = true; ++} ++ ++static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg) ++{ ++ struct dwc2_core_params *p = &hsotg->params; ++ struct device_node *np = hsotg->dev->of_node; ++ ++ p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ p->activate_stm_id_vb_detection = ++ !of_property_read_bool(np, "usb-role-switch"); ++ p->host_rx_fifo_size = 440; ++ p->host_nperio_tx_fifo_size = 256; ++ p->host_perio_tx_fifo_size = 256; ++ p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; ++ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; ++} ++ + const struct of_device_id dwc2_of_match_table[] = { + { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, + { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, +@@ -186,6 +221,10 @@ const struct of_device_id dwc2_of_match_table[] = { + { .compatible = "st,stm32f4x9-hsotg" }, + { .compatible = "st,stm32f7-hsotg", + .data = dwc2_set_stm32f7_hsotg_params }, ++ { .compatible = "st,stm32mp1-fsotg", ++ .data = dwc2_set_stm32mp1_fsotg_params }, ++ { .compatible = "st,stm32mp1-hsotg", ++ .data = dwc2_set_stm32mp1_hsotg_params }, + {}, + }; + MODULE_DEVICE_TABLE(of, dwc2_of_match_table); +diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c +index 3c6ce09a6..5691d8281 100644 +--- a/drivers/usb/dwc2/platform.c ++++ b/drivers/usb/dwc2/platform.c +@@ -312,6 +312,11 @@ static int dwc2_driver_remove(struct platform_device *dev) + if (hsotg->gadget_enabled) + dwc2_hsotg_remove(hsotg); + ++ if (hsotg->params.activate_stm_id_vb_detection) ++ regulator_disable(hsotg->usb33d); ++ ++ dwc2_drd_exit(hsotg); ++ + if (hsotg->ll_hw_enabled) + dwc2_lowlevel_hw_disable(hsotg); + +@@ -445,8 +450,11 @@ static int dwc2_driver_probe(struct platform_device *dev) + * reset value form registers. + */ + retval = dwc2_core_reset(hsotg, false); +- if (retval) ++ if (retval) { ++ /* TEMPORARY WORKAROUND */ ++ retval = -EPROBE_DEFER; + goto error; ++ } + + /* Detect config values from hardware */ + retval = dwc2_get_hwparams(hsotg); +@@ -464,10 +472,40 @@ static int dwc2_driver_probe(struct platform_device *dev) + if (retval) + goto error; + ++ if (hsotg->params.activate_stm_id_vb_detection) { ++ u32 ggpio; ++ ++ hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); ++ if (IS_ERR(hsotg->usb33d)) { ++ retval = PTR_ERR(hsotg->usb33d); ++ dev_err(hsotg->dev, ++ "can't get voltage level detector supply\n"); ++ goto error; ++ } ++ retval = regulator_enable(hsotg->usb33d); ++ if (retval) { ++ dev_err(hsotg->dev, ++ "can't enable voltage level detector supply\n"); ++ goto error; ++ } ++ ++ ggpio = dwc2_readl(hsotg, GGPIO); ++ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; ++ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; ++ dwc2_writel(hsotg, ggpio, GGPIO); ++ } ++ ++ retval = dwc2_drd_init(hsotg); ++ if (retval) { ++ if (retval != -EPROBE_DEFER) ++ dev_err(hsotg->dev, "failed to initialize dual-role\n"); ++ goto error_init; ++ } ++ + if (hsotg->dr_mode != USB_DR_MODE_HOST) { + retval = dwc2_gadget_init(hsotg); + if (retval) +- goto error; ++ goto error_init; + hsotg->gadget_enabled = 1; + } + +@@ -493,7 +531,7 @@ static int dwc2_driver_probe(struct platform_device *dev) + if (retval) { + if (hsotg->gadget_enabled) + dwc2_hsotg_remove(hsotg); +- goto error; ++ goto error_init; + } + hsotg->hcd_enabled = 1; + } +@@ -509,6 +547,9 @@ static int dwc2_driver_probe(struct platform_device *dev) + + return 0; + ++error_init: ++ if (hsotg->params.activate_stm_id_vb_detection) ++ regulator_disable(hsotg->usb33d); + error: + dwc2_lowlevel_hw_disable(hsotg); + return retval; +@@ -523,12 +564,61 @@ static int __maybe_unused dwc2_suspend(struct device *dev) + if (is_device_mode) + dwc2_hsotg_suspend(dwc2); + ++ dwc2_drd_suspend(dwc2); ++ ++ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { ++ /* ++ * Backup host registers when power_down param is 'none', if ++ * controller power is disabled. ++ * This shouldn't be needed, when using other power_down modes. ++ */ ++ ret = dwc2_backup_registers(dwc2); ++ if (ret) { ++ dev_err(dwc2->dev, "backup regs failed %d\n", ret); ++ return ret; ++ } ++ } ++ ++ if (dwc2->params.activate_stm_id_vb_detection) { ++ unsigned long flags; ++ u32 ggpio, gotgctl; ++ ++ /* ++ * Need to force the mode to the current mode to avoid Mode ++ * Mismatch Interrupt when ID detection will be disabled. ++ */ ++ dwc2_force_mode(dwc2, !is_device_mode); ++ ++ spin_lock_irqsave(&dwc2->lock, flags); ++ gotgctl = dwc2_readl(dwc2, GOTGCTL); ++ /* bypass debounce filter, enable overrides */ ++ gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; ++ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; ++ /* Force A / B session if needed */ ++ if (gotgctl & GOTGCTL_ASESVLD) ++ gotgctl |= GOTGCTL_AVALOVAL; ++ if (gotgctl & GOTGCTL_BSESVLD) ++ gotgctl |= GOTGCTL_BVALOVAL; ++ dwc2_writel(dwc2, gotgctl, GOTGCTL); ++ spin_unlock_irqrestore(&dwc2->lock, flags); ++ ++ ggpio = dwc2_readl(dwc2, GGPIO); ++ ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; ++ ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; ++ dwc2_writel(dwc2, ggpio, GGPIO); ++ ++ regulator_disable(dwc2->usb33d); ++ } ++ + if (dwc2->ll_hw_enabled && + (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { + ret = __dwc2_lowlevel_hw_disable(dwc2); + dwc2->phy_off_for_suspend = true; + } + ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) ++ enable_irq_wake(dwc2->irq); ++ + return ret; + } + +@@ -537,6 +627,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) + struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); + int ret = 0; + ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) ++ disable_irq_wake(dwc2->irq); ++ + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { + ret = __dwc2_lowlevel_hw_enable(dwc2); + if (ret) +@@ -544,6 +637,41 @@ static int __maybe_unused dwc2_resume(struct device *dev) + } + dwc2->phy_off_for_suspend = false; + ++ if (dwc2->params.activate_stm_id_vb_detection) { ++ unsigned long flags; ++ u32 ggpio, gotgctl; ++ ++ ret = regulator_enable(dwc2->usb33d); ++ if (ret) ++ return ret; ++ ++ ggpio = dwc2_readl(dwc2, GGPIO); ++ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; ++ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; ++ dwc2_writel(dwc2, ggpio, GGPIO); ++ ++ /* ID/VBUS detection startup time */ ++ usleep_range(5000, 7000); ++ ++ spin_lock_irqsave(&dwc2->lock, flags); ++ gotgctl = dwc2_readl(dwc2, GOTGCTL); ++ gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; ++ gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | ++ GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); ++ dwc2_writel(dwc2, gotgctl, GOTGCTL); ++ spin_unlock_irqrestore(&dwc2->lock, flags); ++ } ++ ++ if (dwc2->params.power_down == DWC2_POWER_DOWN_PARAM_NONE) { ++ ret = dwc2_restore_registers(dwc2); ++ if (ret) { ++ dev_err(dwc2->dev, "restore regs failed %d\n", ret); ++ return ret; ++ } ++ } ++ ++ dwc2_drd_resume(dwc2); ++ + if (dwc2_is_device_mode(dwc2)) + ret = dwc2_hsotg_resume(dwc2); + +diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c +index 9fc98de83..780059373 100644 +--- a/drivers/usb/gadget/function/f_acm.c ++++ b/drivers/usb/gadget/function/f_acm.c +@@ -723,6 +723,20 @@ static void acm_free_func(struct usb_function *f) + kfree(acm); + } + ++static void acm_resume(struct usb_function *f) ++{ ++ struct f_acm *acm = func_to_acm(f); ++ ++ gserial_resume(&acm->port); ++} ++ ++static void acm_suspend(struct usb_function *f) ++{ ++ struct f_acm *acm = func_to_acm(f); ++ ++ gserial_suspend(&acm->port); ++} ++ + static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) + { + struct f_serial_opts *opts; +@@ -750,6 +764,8 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) + acm->port_num = opts->port_num; + acm->port.func.unbind = acm_unbind; + acm->port.func.free_func = acm_free_func; ++ acm->port.func.resume = acm_resume; ++ acm->port.func.suspend = acm_suspend; + + return &acm->port.func; + } +diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c +index c860f30a0..b2fb6b742 100644 +--- a/drivers/usb/gadget/function/f_serial.c ++++ b/drivers/usb/gadget/function/f_serial.c +@@ -327,6 +327,20 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f) + usb_free_all_descriptors(f); + } + ++static void gser_resume(struct usb_function *f) ++{ ++ struct f_gser *gser = func_to_gser(f); ++ ++ gserial_resume(&gser->port); ++} ++ ++static void gser_suspend(struct usb_function *f) ++{ ++ struct f_gser *gser = func_to_gser(f); ++ ++ gserial_suspend(&gser->port); ++} ++ + static struct usb_function *gser_alloc(struct usb_function_instance *fi) + { + struct f_gser *gser; +@@ -348,6 +362,8 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi) + gser->port.func.set_alt = gser_set_alt; + gser->port.func.disable = gser_disable; + gser->port.func.free_func = gser_free; ++ gser->port.func.resume = gser_resume; ++ gser->port.func.suspend = gser_suspend; + + return &gser->port.func; + } +diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c +index 038c445a4..3c144621a 100644 +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -119,6 +119,8 @@ struct gs_port { + wait_queue_head_t drain_wait; /* wait while writes drain */ + bool write_busy; + wait_queue_head_t close_wait; ++ bool suspended; /* port suspended */ ++ bool start_delayed; /* delay start when suspended */ + + /* REVISIT this state ... */ + struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ +@@ -666,13 +668,19 @@ static int gs_open(struct tty_struct *tty, struct file *file) + + /* if connected, start the I/O stream */ + if (port->port_usb) { +- struct gserial *gser = port->port_usb; ++ /* if port is suspended, wait resume to start I/0 stream */ ++ if (!port->suspended) { ++ struct gserial *gser = port->port_usb; + +- pr_debug("gs_open: start ttyGS%d\n", port->port_num); +- gs_start_io(port); ++ pr_debug("gs_open: start ttyGS%d\n", port->port_num); ++ gs_start_io(port); + +- if (gser->connect) +- gser->connect(gser); ++ if (gser->connect) ++ gser->connect(gser); ++ } else { ++ pr_debug("delay start of ttyGS%d\n", port->port_num); ++ port->start_delayed = true; ++ } + } + + pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); +@@ -720,7 +728,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) + port->port.count = 0; + + gser = port->port_usb; +- if (gser && gser->disconnect) ++ if (gser && !port->suspended && gser->disconnect) + gser->disconnect(gser); + + /* wait for circular write buffer to drain, disconnect, or at +@@ -744,6 +752,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) + else + kfifo_reset(&port->port_write_buf); + ++ port->start_delayed = false; + port->port.tty = NULL; + + port->openclose = false; +@@ -1395,6 +1404,38 @@ void gserial_disconnect(struct gserial *gser) + } + EXPORT_SYMBOL_GPL(gserial_disconnect); + ++void gserial_suspend(struct gserial *gser) ++{ ++ struct gs_port *port = gser->ioport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->port_lock, flags); ++ port->suspended = true; ++ spin_unlock_irqrestore(&port->port_lock, flags); ++} ++EXPORT_SYMBOL_GPL(gserial_suspend); ++ ++void gserial_resume(struct gserial *gser) ++{ ++ struct gs_port *port = gser->ioport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->port_lock, flags); ++ port->suspended = false; ++ if (!port->start_delayed) { ++ spin_unlock_irqrestore(&port->port_lock, flags); ++ return; ++ } ++ ++ pr_debug("delayed start ttyGS%d\n", port->port_num); ++ gs_start_io(port); ++ if (gser->connect) ++ gser->connect(gser); ++ port->start_delayed = false; ++ spin_unlock_irqrestore(&port->port_lock, flags); ++} ++EXPORT_SYMBOL_GPL(gserial_resume); ++ + static int userial_init(void) + { + unsigned i; +diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h +index 9acaac1cb..223a4be05 100644 +--- a/drivers/usb/gadget/function/u_serial.h ++++ b/drivers/usb/gadget/function/u_serial.h +@@ -60,6 +60,8 @@ void gserial_free_line(unsigned char port_line); + /* connect/disconnect is handled by individual functions */ + int gserial_connect(struct gserial *, u8 port_num); + void gserial_disconnect(struct gserial *); ++void gserial_suspend(struct gserial *p); ++void gserial_resume(struct gserial *p); + + /* functions are bound to configurations by a config or gadget driver */ + int gser_bind_config(struct usb_configuration *c, u8 port_num); +diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c +index 769749ca5..a356b227e 100644 +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include "ehci.h" + +@@ -307,6 +308,9 @@ static int ehci_platform_suspend(struct device *dev) + if (pdata->power_suspend) + pdata->power_suspend(pdev); + ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) ++ enable_irq_wake(hcd->irq); ++ + return ret; + } + +@@ -318,6 +322,9 @@ static int ehci_platform_resume(struct device *dev) + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + struct device *companion_dev; + ++ if (device_may_wakeup(dev) || device_wakeup_path(dev)) ++ disable_irq_wake(hcd->irq); ++ + if (pdata->power_on) { + int err = pdata->power_on(pdev); + if (err < 0) +diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c +index 440d213e1..791908f8c 100644 +--- a/drivers/usb/renesas_usbhs/rcar2.c ++++ b/drivers/usb/renesas_usbhs/rcar2.c +@@ -34,7 +34,7 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + + if (priv->phy) { +- phy_put(priv->phy); ++ phy_put(&pdev->dev, priv->phy); + priv->phy = NULL; + } + +diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c +index 021749594..3eed3334a 100644 +--- a/drivers/usb/renesas_usbhs/rza2.c ++++ b/drivers/usb/renesas_usbhs/rza2.c +@@ -29,7 +29,7 @@ static int usbhs_rza2_hardware_exit(struct platform_device *pdev) + { + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + +- phy_put(priv->phy); ++ phy_put(&pdev->dev, priv->phy); + priv->phy = NULL; + + return 0; +diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig +index 895e2418d..3a1ee89be 100644 +--- a/drivers/usb/typec/Kconfig ++++ b/drivers/usb/typec/Kconfig +@@ -61,6 +61,15 @@ config TYPEC_TPS6598X + If you choose to build this driver as a dynamically linked module, the + module will be called tps6598x.ko. + ++config TYPEC_STUSB ++ tristate "STMicroelectronics STUSB Type-C controller driver" ++ depends on I2C ++ select USB_ROLE_SWITCH ++ help ++ The STMicroelectronics STUSB Type-C controller driver that works ++ with Type-C Port Controller Manager to provide USB Type-C ++ functionalities. ++ + source "drivers/usb/typec/mux/Kconfig" + + source "drivers/usb/typec/altmodes/Kconfig" +diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile +index 6696b7263..c9136020e 100644 +--- a/drivers/usb/typec/Makefile ++++ b/drivers/usb/typec/Makefile +@@ -5,4 +5,5 @@ obj-$(CONFIG_TYPEC) += altmodes/ + obj-$(CONFIG_TYPEC_TCPM) += tcpm/ + obj-$(CONFIG_TYPEC_UCSI) += ucsi/ + obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o ++obj-$(CONFIG_TYPEC_STUSB) += typec_stusb.o + obj-$(CONFIG_TYPEC) += mux/ +diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c +index a400b65cf..6391d0101 100644 +--- a/drivers/usb/typec/class.c ++++ b/drivers/usb/typec/class.c +@@ -1387,6 +1387,21 @@ void typec_set_pwr_opmode(struct typec_port *port, + } + EXPORT_SYMBOL_GPL(typec_set_pwr_opmode); + ++/** ++ * typec_find_power_opmode - Get the typec port power operation mode ++ * @name: port power operation mode string ++ * ++ * This routine is used to find the typec_pwr_opmodes by its string name. ++ * ++ * Returns typec_pwr_opmodes if success, otherwise negative error code. ++ */ ++int typec_find_port_power_opmode(const char *name) ++{ ++ return match_string(typec_pwr_opmodes, ++ ARRAY_SIZE(typec_pwr_opmodes), name); ++} ++EXPORT_SYMBOL_GPL(typec_find_port_power_opmode); ++ + /** + * typec_find_port_power_role - Get the typec port power capability + * @name: port power capability string +diff --git a/drivers/usb/typec/typec_stusb.c b/drivers/usb/typec/typec_stusb.c +new file mode 100644 +index 000000000..e760ba304 +--- /dev/null ++++ b/drivers/usb/typec/typec_stusb.c +@@ -0,0 +1,910 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * STMicroelectronics STUSB Type-C controller family driver ++ * ++ * Copyright (C) 2019, STMicroelectronics ++ * Author(s): Amelie Delaunay ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STUSB_ALERT_STATUS 0x0B /* RC */ ++#define STUSB_ALERT_STATUS_MASK_CTRL 0x0C /* RW */ ++#define STUSB_CC_CONNECTION_STATUS_TRANS 0x0D /* RC */ ++#define STUSB_CC_CONNECTION_STATUS 0x0E /* RO */ ++#define STUSB_MONITORING_STATUS_TRANS 0x0F /* RC */ ++#define STUSB_MONITORING_STATUS 0x10 /* RO */ ++#define STUSB_CC_OPERATION_STATUS 0x11 /* RO */ ++#define STUSB_HW_FAULT_STATUS_TRANS 0x12 /* RC */ ++#define STUSB_HW_FAULT_STATUS 0x13 /* RO */ ++#define STUSB_CC_CAPABILITY_CTRL 0x18 /* RW */ ++#define STUSB_CC_VCONN_SWITCH_CTRL 0x1E /* RW */ ++#define STUSB_VCONN_MONITORING_CTRL 0x20 /* RW */ ++#define STUSB_VBUS_MONITORING_RANGE_CTRL 0x22 /* RW */ ++#define STUSB_RESET_CTRL 0x23 /* RW */ ++#define STUSB_VBUS_DISCHARGE_TIME_CTRL 0x25 /* RW */ ++#define STUSB_VBUS_DISCHARGE_STATUS 0x26 /* RO */ ++#define STUSB_VBUS_ENABLE_STATUS 0x27 /* RO */ ++#define STUSB_CC_POWER_MODE_CTRL 0x28 /* RW */ ++#define STUSB_VBUS_MONITORING_CTRL 0x2E /* RW */ ++#define STUSB1600_REG_MAX 0x2F /* RO - Reserved */ ++ ++/* STUSB_ALERT_STATUS/STUSB_ALERT_STATUS_MASK_CTRL bitfields */ ++#define STUSB_HW_FAULT BIT(4) ++#define STUSB_MONITORING BIT(5) ++#define STUSB_CC_CONNECTION BIT(6) ++#define STUSB_ALL_ALERTS GENMASK(6, 4) ++ ++/* STUSB_CC_CONNECTION_STATUS_TRANS bitfields */ ++#define STUSB_CC_ATTACH_TRANS BIT(0) ++ ++/* STUSB_CC_CONNECTION_STATUS bitfields */ ++#define STUSB_CC_ATTACH BIT(0) ++#define STUSB_CC_VCONN_SUPPLY BIT(1) ++#define STUSB_CC_DATA_ROLE(s) (!!((s) & BIT(2))) ++#define STUSB_CC_POWER_ROLE(s) (!!((s) & BIT(3))) ++#define STUSB_CC_ATTACHED_MODE GENMASK(7, 5) ++ ++/* STUSB_MONITORING_STATUS_TRANS bitfields */ ++#define STUSB_VCONN_PRESENCE_TRANS BIT(0) ++#define STUSB_VBUS_PRESENCE_TRANS BIT(1) ++#define STUSB_VBUS_VSAFE0V_TRANS BIT(2) ++#define STUSB_VBUS_VALID_TRANS BIT(3) ++ ++/* STUSB_MONITORING_STATUS bitfields */ ++#define STUSB_VCONN_PRESENCE BIT(0) ++#define STUSB_VBUS_PRESENCE BIT(1) ++#define STUSB_VBUS_VSAFE0V BIT(2) ++#define STUSB_VBUS_VALID BIT(3) ++ ++/* STUSB_CC_OPERATION_STATUS bitfields */ ++#define STUSB_TYPEC_FSM_STATE GENMASK(4, 0) ++#define STUSB_SINK_POWER_STATE GENMASK(6, 5) ++#define STUSB_CC_ATTACHED BIT(7) ++ ++/* STUSB_HW_FAULT_STATUS_TRANS bitfields */ ++#define STUSB_VCONN_SW_OVP_FAULT_TRANS BIT(0) ++#define STUSB_VCONN_SW_OCP_FAULT_TRANS BIT(1) ++#define STUSB_VCONN_SW_RVP_FAULT_TRANS BIT(2) ++#define STUSB_VPU_VALID_TRANS BIT(4) ++#define STUSB_VPU_OVP_FAULT_TRANS BIT(5) ++#define STUSB_THERMAL_FAULT BIT(7) ++ ++/* STUSB_HW_FAULT_STATUS bitfields */ ++#define STUSB_VCONN_SW_OVP_FAULT_CC2 BIT(0) ++#define STUSB_VCONN_SW_OVP_FAULT_CC1 BIT(1) ++#define STUSB_VCONN_SW_OCP_FAULT_CC2 BIT(2) ++#define STUSB_VCONN_SW_OCP_FAULT_CC1 BIT(3) ++#define STUSB_VCONN_SW_RVP_FAULT_CC2 BIT(4) ++#define STUSB_VCONN_SW_RVP_FAULT_CC1 BIT(5) ++#define STUSB_VPU_VALID BIT(6) ++#define STUSB_VPU_OVP_FAULT BIT(7) ++ ++/* STUSB_CC_CAPABILITY_CTRL bitfields */ ++#define STUSB_CC_VCONN_SUPPLY_EN BIT(0) ++#define STUSB_CC_VCONN_DISCHARGE_EN BIT(4) ++#define STUSB_CC_CURRENT_ADVERTISED GENMASK(7, 6) ++ ++/* STUSB_VCONN_SWITCH_CTRL bitfields */ ++#define STUSB_CC_VCONN_SWITCH_ILIM GENMASK(3, 0) ++ ++/* STUSB_VCONN_MONITORING_CTRL bitfields */ ++#define STUSB_VCONN_UVLO_THRESHOLD BIT(6) ++#define STUSB_VCONN_MONITORING_EN BIT(7) ++ ++/* STUSB_VBUS_MONITORING_RANGE_CTRL bitfields */ ++#define STUSB_SHIFT_LOW_VBUS_LIMIT GENMASK(3, 0) ++#define STUSB_SHIFT_HIGH_VBUS_LIMIT GENMASK(7, 4) ++ ++/* STUSB_RESET_CTRL bitfields */ ++#define STUSB_SW_RESET_EN BIT(0) ++ ++/* STUSB_VBUS_DISCHARGE_TIME_CTRL bitfields */ ++#define STUSBXX02_VBUS_DISCHARGE_TIME_TO_PDO GENMASK(3, 0) ++#define STUSB_VBUS_DISCHARGE_TIME_TO_0V GENMASK(7, 4) ++ ++/* STUSB_VBUS_DISCHARGE_STATUS bitfields */ ++#define STUSB_VBUS_DISCHARGE_EN BIT(7) ++ ++/* STUSB_VBUS_ENABLE_STATUS bitfields */ ++#define STUSB_VBUS_SOURCE_EN BIT(0) ++#define STUSB_VBUS_SINK_EN BIT(1) ++ ++/* STUSB_CC_POWER_MODE_CTRL bitfields */ ++#define STUSB_CC_POWER_MODE GENMASK(2, 0) ++ ++/* STUSB_VBUS_MONITORING_CTRL bitfields */ ++#define STUSB_VDD_UVLO_DISABLE BIT(0) ++#define STUSB_VBUS_VSAFE0V_THRESHOLD GENMASK(2, 1) ++#define STUSB_VBUS_RANGE_DISABLE BIT(4) ++#define STUSB_VDD_OVLO_DISABLE BIT(6) ++ ++enum stusb_pwr_mode { ++ SOURCE_WITH_ACCESSORY, ++ SINK_WITH_ACCESSORY, ++ SINK_WITHOUT_ACCESSORY, ++ DUAL_WITH_ACCESSORY, ++ DUAL_WITH_ACCESSORY_AND_TRY_SRC, ++ DUAL_WITH_ACCESSORY_AND_TRY_SNK, ++}; ++ ++enum stusb_attached_mode { ++ NO_DEVICE_ATTACHED, ++ SINK_ATTACHED, ++ SOURCE_ATTACHED, ++ DEBUG_ACCESSORY_ATTACHED, ++ AUDIO_ACCESSORY_ATTACHED, ++}; ++ ++struct stusb { ++ struct device *dev; ++ struct regmap *regmap; ++ struct regulator *vdd_supply; ++ struct regulator *vsys_supply; ++ struct regulator *vconn_supply; ++ struct regulator *main_supply; ++ ++ struct typec_port *port; ++ struct typec_capability capability; ++ struct typec_partner *partner; ++ ++ enum typec_port_type port_type; ++ enum typec_pwr_opmode pwr_opmode; ++ bool vbus_on; ++ ++ struct usb_role_switch *role_sw; ++ struct work_struct wq_role_sw; ++}; ++ ++static bool stusb_reg_writeable(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case STUSB_ALERT_STATUS_MASK_CTRL: ++ case STUSB_CC_CAPABILITY_CTRL: ++ case STUSB_CC_VCONN_SWITCH_CTRL: ++ case STUSB_VCONN_MONITORING_CTRL: ++ case STUSB_VBUS_MONITORING_RANGE_CTRL: ++ case STUSB_RESET_CTRL: ++ case STUSB_VBUS_DISCHARGE_TIME_CTRL: ++ case STUSB_CC_POWER_MODE_CTRL: ++ case STUSB_VBUS_MONITORING_CTRL: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool stusb_reg_readable(struct device *dev, unsigned int reg) ++{ ++ if (reg <= 0x0A || ++ (reg >= 0x14 && reg <= 0x17) || ++ (reg >= 0x19 && reg <= 0x1D) || ++ (reg >= 0x29 && reg <= 0x2D) || ++ (reg == 0x1F || reg == 0x21 || reg == 0x24 || reg == 0x2F)) ++ return false; ++ else ++ return true; ++} ++ ++static bool stusb_reg_volatile(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case STUSB_ALERT_STATUS: ++ case STUSB_CC_CONNECTION_STATUS_TRANS: ++ case STUSB_CC_CONNECTION_STATUS: ++ case STUSB_MONITORING_STATUS_TRANS: ++ case STUSB_MONITORING_STATUS: ++ case STUSB_CC_OPERATION_STATUS: ++ case STUSB_HW_FAULT_STATUS_TRANS: ++ case STUSB_HW_FAULT_STATUS: ++ case STUSB_VBUS_DISCHARGE_STATUS: ++ case STUSB_VBUS_ENABLE_STATUS: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool stusb_reg_precious(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case STUSB_ALERT_STATUS: ++ case STUSB_CC_CONNECTION_STATUS_TRANS: ++ case STUSB_MONITORING_STATUS_TRANS: ++ case STUSB_HW_FAULT_STATUS_TRANS: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static const struct regmap_config stusb1600_regmap_config = { ++ .reg_bits = 8, ++ .reg_stride = 1, ++ .val_bits = 8, ++ .max_register = STUSB1600_REG_MAX, ++ .writeable_reg = stusb_reg_writeable, ++ .readable_reg = stusb_reg_readable, ++ .volatile_reg = stusb_reg_volatile, ++ .precious_reg = stusb_reg_precious, ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++static bool stusb_get_vconn(struct stusb *chip) ++{ ++ u32 val; ++ int ret; ++ ++ ret = regmap_read(chip->regmap, STUSB_CC_CAPABILITY_CTRL, &val); ++ if (ret) { ++ dev_err(chip->dev, "Unable to get Vconn status: %d\n", ret); ++ return false; ++ } ++ ++ return !!FIELD_GET(STUSB_CC_VCONN_SUPPLY_EN, val); ++} ++ ++static int stusb_set_vconn(struct stusb *chip, bool on) ++{ ++ int ret; ++ ++ /* Manage VCONN input supply */ ++ if (chip->vconn_supply) { ++ if (on) { ++ ret = regulator_enable(chip->vconn_supply); ++ if (ret) { ++ dev_err(chip->dev, ++ "failed to enable vconn supply: %d\n", ++ ret); ++ return ret; ++ } ++ } else { ++ regulator_disable(chip->vconn_supply); ++ } ++ } ++ ++ /* Manage VCONN monitoring and power path */ ++ ret = regmap_update_bits(chip->regmap, STUSB_VCONN_MONITORING_CTRL, ++ STUSB_VCONN_MONITORING_EN, ++ on ? STUSB_VCONN_MONITORING_EN : 0); ++ if (ret) ++ goto vconn_reg_disable; ++ ++ return 0; ++ ++vconn_reg_disable: ++ if (chip->vconn_supply && on) ++ regulator_disable(chip->vconn_supply); ++ ++ return ret; ++} ++ ++static enum typec_pwr_opmode stusb_get_pwr_opmode(struct stusb *chip) ++{ ++ u32 val; ++ int ret; ++ ++ ret = regmap_read(chip->regmap, STUSB_CC_CAPABILITY_CTRL, &val); ++ if (ret) { ++ dev_err(chip->dev, "Unable to get pwr opmode: %d\n", ret); ++ return TYPEC_PWR_MODE_USB; ++ } ++ ++ return FIELD_GET(STUSB_CC_CURRENT_ADVERTISED, val); ++} ++ ++static enum typec_accessory stusb_get_accessory(u32 status) ++{ ++ enum stusb_attached_mode mode; ++ ++ mode = FIELD_GET(STUSB_CC_ATTACHED_MODE, status); ++ ++ switch (mode) { ++ case DEBUG_ACCESSORY_ATTACHED: ++ return TYPEC_ACCESSORY_DEBUG; ++ case AUDIO_ACCESSORY_ATTACHED: ++ return TYPEC_ACCESSORY_AUDIO; ++ default: ++ return TYPEC_ACCESSORY_NONE; ++ } ++} ++ ++static enum typec_role stusb_get_vconn_role(u32 status) ++{ ++ if (FIELD_GET(STUSB_CC_VCONN_SUPPLY, status)) ++ return TYPEC_SOURCE; ++ else ++ return TYPEC_SINK; ++} ++ ++static void stusb_set_role_sw(struct work_struct *work) ++{ ++ struct stusb *chip = container_of(work, struct stusb, wq_role_sw); ++ enum usb_role usb_role = USB_ROLE_NONE; ++ u32 conn_status, vbus_status; ++ bool id, vbus; ++ int ret; ++ ++ /* Check ID and Vbus to update state */ ++ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, ++ &conn_status); ++ if (ret) ++ return; ++ ++ ret = regmap_read(chip->regmap, STUSB_VBUS_ENABLE_STATUS, ++ &vbus_status); ++ if (ret) ++ return; ++ ++ /* 0 = Device, 1 = Host */ ++ id = STUSB_CC_DATA_ROLE(conn_status); ++ ++ if (STUSB_CC_POWER_ROLE(conn_status)) /* Source */ ++ vbus = !!(vbus_status & STUSB_VBUS_SOURCE_EN); ++ else /* Sink */ ++ vbus = !!(vbus_status & STUSB_VBUS_SINK_EN); ++ ++ dev_dbg(chip->dev, "role=%s vbus=%sable\n", ++ id ? "Host" : "Device", vbus ? "en" : "dis"); ++ ++ /* ++ * !vbus = detached, so neither B-Session Valid nor A-Session Valid ++ * !vbus = USB_ROLE_NONE ++ * vbus = attached, so either B-Session Valid or A-Session Valid ++ * vbus && !id = B-Session Valid = USB_ROLE_DEVICE ++ * vbus && id = A-Session Valid = USB_ROLE_HOST ++ */ ++ if (vbus && id) /* Attached and A-Session Valid */ ++ usb_role = USB_ROLE_HOST; ++ if (vbus && !id) /* Attached and B-Session Valid */ ++ usb_role = USB_ROLE_DEVICE; ++ ++ usb_role_switch_set_role(chip->role_sw, usb_role); ++} ++ ++static int stusb_attach(struct stusb *chip, u32 status) ++{ ++ struct typec_partner_desc desc; ++ int ret; ++ ++ if ((STUSB_CC_POWER_ROLE(status) == TYPEC_SOURCE) && ++ chip->vdd_supply) { ++ ret = regulator_enable(chip->vdd_supply); ++ if (ret) { ++ dev_err(chip->dev, ++ "Failed to enable Vbus supply: %d\n", ret); ++ return ret; ++ } ++ chip->vbus_on = true; ++ } ++ ++ desc.usb_pd = false; ++ desc.accessory = stusb_get_accessory(status); ++ desc.identity = NULL; ++ ++ chip->partner = typec_register_partner(chip->port, &desc); ++ if (IS_ERR(chip->partner)) { ++ ret = PTR_ERR(chip->partner); ++ goto vbus_disable; ++ } ++ ++ typec_set_pwr_role(chip->port, STUSB_CC_POWER_ROLE(status)); ++ typec_set_pwr_opmode(chip->port, stusb_get_pwr_opmode(chip)); ++ typec_set_vconn_role(chip->port, stusb_get_vconn_role(status)); ++ typec_set_data_role(chip->port, STUSB_CC_DATA_ROLE(status)); ++ ++ if (chip->role_sw) ++ queue_work(system_power_efficient_wq, &chip->wq_role_sw); ++ ++ return 0; ++ ++vbus_disable: ++ if (chip->vbus_on) { ++ regulator_disable(chip->vdd_supply); ++ chip->vbus_on = false; ++ } ++ ++ return ret; ++} ++ ++static void stusb_detach(struct stusb *chip, u32 status) ++{ ++ typec_unregister_partner(chip->partner); ++ chip->partner = NULL; ++ ++ typec_set_pwr_role(chip->port, STUSB_CC_POWER_ROLE(status)); ++ typec_set_pwr_opmode(chip->port, TYPEC_PWR_MODE_USB); ++ typec_set_vconn_role(chip->port, stusb_get_vconn_role(status)); ++ typec_set_data_role(chip->port, STUSB_CC_DATA_ROLE(status)); ++ ++ if (chip->vbus_on) { ++ regulator_disable(chip->vdd_supply); ++ chip->vbus_on = false; ++ } ++ ++ if (chip->role_sw) ++ queue_work(system_power_efficient_wq, &chip->wq_role_sw); ++} ++ ++static irqreturn_t stusb_irq_handler(int irq, void *data) ++{ ++ struct stusb *chip = data; ++ u32 pending, trans, status; ++ int ret; ++ ++ ret = regmap_read(chip->regmap, STUSB_ALERT_STATUS, &pending); ++ if (ret) ++ return IRQ_NONE; ++ ++ if (pending & STUSB_CC_CONNECTION) { ++ ret = regmap_read(chip->regmap, ++ STUSB_CC_CONNECTION_STATUS_TRANS, &trans); ++ if (ret) ++ goto err; ++ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, ++ &status); ++ if (ret) ++ goto err; ++ ++ if (trans & STUSB_CC_ATTACH_TRANS) { ++ if (status & STUSB_CC_ATTACH) { ++ ret = stusb_attach(chip, status); ++ if (ret) ++ goto err; ++ } else { ++ stusb_detach(chip, status); ++ } ++ } ++ } ++err: ++ return IRQ_HANDLED; ++} ++ ++static int stusb_irq_init(struct stusb *chip, int irq) ++{ ++ u32 status; ++ int ret; ++ ++ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, &status); ++ if (ret) ++ return ret; ++ ++ if (status & STUSB_CC_ATTACH) { ++ ret = stusb_attach(chip, status); ++ if (ret) ++ dev_err(chip->dev, "attach failed: %d\n", ret); ++ } ++ ++ ret = devm_request_threaded_irq(chip->dev, irq, NULL, stusb_irq_handler, ++ IRQF_ONESHOT, dev_name(chip->dev), ++ chip); ++ if (ret) ++ goto partner_unregister; ++ ++ /* Unmask CC_CONNECTION events */ ++ ret = regmap_write_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, ++ STUSB_CC_CONNECTION, 0); ++ if (ret) ++ goto partner_unregister; ++ ++ return 0; ++ ++partner_unregister: ++ if (chip->partner) { ++ typec_unregister_partner(chip->partner); ++ chip->partner = NULL; ++ } ++ ++ return ret; ++} ++ ++static int stusb_init(struct stusb *chip) ++{ ++ u32 val; ++ int ret; ++ ++ /* Change the default Type-C power mode */ ++ if (chip->port_type == TYPEC_PORT_SRC) ++ ret = regmap_update_bits(chip->regmap, ++ STUSB_CC_POWER_MODE_CTRL, ++ STUSB_CC_POWER_MODE, ++ SOURCE_WITH_ACCESSORY); ++ else if (chip->port_type == TYPEC_PORT_SNK) ++ ret = regmap_update_bits(chip->regmap, ++ STUSB_CC_POWER_MODE_CTRL, ++ STUSB_CC_POWER_MODE, ++ SINK_WITH_ACCESSORY); ++ else /* (capability->type == TYPEC_PORT_DRP) */ ++ ret = regmap_update_bits(chip->regmap, ++ STUSB_CC_POWER_MODE_CTRL, ++ STUSB_CC_POWER_MODE, ++ DUAL_WITH_ACCESSORY); ++ if (ret) ++ return ret; ++ ++ if (chip->port_type == TYPEC_PORT_SNK) ++ goto skip_src; ++ ++ /* Change the default Type-C Source power operation mode capability */ ++ ret = regmap_update_bits(chip->regmap, STUSB_CC_CAPABILITY_CTRL, ++ STUSB_CC_CURRENT_ADVERTISED, ++ FIELD_PREP(STUSB_CC_CURRENT_ADVERTISED, ++ chip->pwr_opmode)); ++ if (ret) ++ return ret; ++ ++ /* Manage Type-C Source Vconn supply */ ++ if (stusb_get_vconn(chip)) { ++ ret = stusb_set_vconn(chip, true); ++ if (ret) ++ return ret; ++ } ++ ++skip_src: ++ /* Mask all events interrupts - to be unmasked with interrupt support */ ++ ret = regmap_update_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, ++ STUSB_ALL_ALERTS, STUSB_ALL_ALERTS); ++ if (ret) ++ return ret; ++ ++ /* Read status at least once to clear any stale interrupts */ ++ regmap_read(chip->regmap, STUSB_ALERT_STATUS, &val); ++ regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS_TRANS, &val); ++ regmap_read(chip->regmap, STUSB_MONITORING_STATUS_TRANS, &val); ++ regmap_read(chip->regmap, STUSB_HW_FAULT_STATUS_TRANS, &val); ++ ++ return 0; ++} ++ ++static int stusb_fw_get_caps(struct stusb *chip) ++{ ++ struct fwnode_handle *fwnode = device_get_named_child_node(chip->dev, ++ "connector"); ++ const char *cap_str; ++ int ret; ++ ++ if (!fwnode) ++ return -EINVAL; ++ ++ chip->capability.fwnode = fwnode; ++ ++ ret = fwnode_property_read_string(fwnode, "power-role", &cap_str); ++ if (!ret) { ++ chip->port_type = typec_find_port_power_role(cap_str); ++ if (chip->port_type < 0) ++ return -EINVAL; ++ ++ chip->capability.type = chip->port_type; ++ } ++ ++ if (chip->port_type == TYPEC_PORT_SNK) ++ goto sink; ++ ++ if (chip->port_type == TYPEC_PORT_DRP) ++ chip->capability.prefer_role = TYPEC_SINK; ++ ++ ret = fwnode_property_read_string(fwnode, "power-opmode", &cap_str); ++ if (!ret) { ++ chip->pwr_opmode = typec_find_port_power_opmode(cap_str); ++ ++ /* Power delivery not yet supported */ ++ if (chip->pwr_opmode < 0 || ++ chip->pwr_opmode == TYPEC_PWR_MODE_PD) { ++ dev_err(chip->dev, "bad power operation mode: %d\n", ++ chip->pwr_opmode); ++ return -EINVAL; ++ } ++ ++ } else { ++ chip->pwr_opmode = stusb_get_pwr_opmode(chip); ++ } ++ ++sink: ++ return 0; ++} ++ ++static int stusb_get_caps(struct stusb *chip, bool *try) ++{ ++ enum typec_port_type *type = &chip->capability.type; ++ enum typec_port_data *data = &chip->capability.data; ++ enum typec_accessory *accessory = chip->capability.accessory; ++ u32 val; ++ int ret; ++ ++ chip->capability.revision = USB_TYPEC_REV_1_2; ++ ++ ret = regmap_read(chip->regmap, STUSB_CC_POWER_MODE_CTRL, &val); ++ if (ret) ++ return ret; ++ ++ *try = false; ++ ++ switch (FIELD_GET(STUSB_CC_POWER_MODE, val)) { ++ case SOURCE_WITH_ACCESSORY: ++ *type = TYPEC_PORT_SRC; ++ *data = TYPEC_PORT_DFP; ++ *accessory++ = TYPEC_ACCESSORY_AUDIO; ++ *accessory++ = TYPEC_ACCESSORY_DEBUG; ++ break; ++ case SINK_WITH_ACCESSORY: ++ *type = TYPEC_PORT_SNK; ++ *data = TYPEC_PORT_UFP; ++ *accessory++ = TYPEC_ACCESSORY_AUDIO; ++ *accessory++ = TYPEC_ACCESSORY_DEBUG; ++ break; ++ case SINK_WITHOUT_ACCESSORY: ++ *type = TYPEC_PORT_SNK; ++ *data = TYPEC_PORT_UFP; ++ break; ++ case DUAL_WITH_ACCESSORY: ++ *type = TYPEC_PORT_DRP; ++ *data = TYPEC_PORT_DRD; ++ *accessory++ = TYPEC_ACCESSORY_AUDIO; ++ *accessory++ = TYPEC_ACCESSORY_DEBUG; ++ break; ++ case DUAL_WITH_ACCESSORY_AND_TRY_SRC: ++ case DUAL_WITH_ACCESSORY_AND_TRY_SNK: ++ *type = TYPEC_PORT_DRP; ++ *data = TYPEC_PORT_DRD; ++ *accessory++ = TYPEC_ACCESSORY_AUDIO; ++ *accessory++ = TYPEC_ACCESSORY_DEBUG; ++ *try = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ chip->port_type = *type; ++ ++ return stusb_fw_get_caps(chip); ++} ++ ++static const struct of_device_id stusb_of_match[] = { ++ { .compatible = "st,stusb1600", .data = &stusb1600_regmap_config}, ++ {}, ++}; ++ ++static int stusb_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct stusb *chip; ++ const struct of_device_id *match; ++ struct regmap_config *regmap_config; ++ bool try_role; ++ struct fwnode_handle *fwnode; ++ int ret; ++ ++ chip = devm_kzalloc(&client->dev, sizeof(struct stusb), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, chip); ++ ++ match = i2c_of_match_device(stusb_of_match, client); ++ regmap_config = (struct regmap_config *)match->data; ++ chip->regmap = devm_regmap_init_i2c(client, regmap_config); ++ if (IS_ERR(chip->regmap)) { ++ ret = PTR_ERR(chip->regmap); ++ dev_err(&client->dev, ++ "Failed to allocate register map:%d\n", ret); ++ return ret; ++ } ++ ++ chip->dev = &client->dev; ++ ++ chip->vsys_supply = devm_regulator_get_optional(chip->dev, "vsys"); ++ if (IS_ERR(chip->vsys_supply)) { ++ ret = PTR_ERR(chip->vsys_supply); ++ if (ret != -ENODEV) ++ return ret; ++ chip->vsys_supply = NULL; ++ } ++ ++ chip->vdd_supply = devm_regulator_get_optional(chip->dev, "vdd"); ++ if (IS_ERR(chip->vdd_supply)) { ++ ret = PTR_ERR(chip->vdd_supply); ++ if (ret != -ENODEV) ++ return ret; ++ chip->vdd_supply = NULL; ++ } ++ ++ chip->vconn_supply = devm_regulator_get_optional(chip->dev, "vconn"); ++ if (IS_ERR(chip->vconn_supply)) { ++ ret = PTR_ERR(chip->vconn_supply); ++ if (ret != -ENODEV) ++ return ret; ++ chip->vconn_supply = NULL; ++ } ++ ++ /* ++ * When both VDD and VSYS power supplies are present, the low power ++ * supply VSYS is selected when VSYS voltage is above 3.1 V. ++ * Otherwise VDD is selected. ++ */ ++ if (chip->vdd_supply && ++ (!chip->vsys_supply || ++ (regulator_get_voltage(chip->vsys_supply) <= 3100000))) ++ chip->main_supply = chip->vdd_supply; ++ else ++ chip->main_supply = chip->vsys_supply; ++ ++ if (chip->main_supply) { ++ ret = regulator_enable(chip->main_supply); ++ if (ret) { ++ dev_err(chip->dev, ++ "Failed to enable main supply: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ ret = stusb_get_caps(chip, &try_role); ++ if (ret) { ++ dev_err(chip->dev, "Failed to get port caps: %d\n", ret); ++ goto main_reg_disable; ++ } ++ ++ ret = stusb_init(chip); ++ if (ret) { ++ dev_err(chip->dev, "Failed to init port: %d\n", ret); ++ goto main_reg_disable; ++ } ++ ++ chip->port = typec_register_port(chip->dev, &chip->capability); ++ if (!chip->port) { ++ ret = -ENODEV; ++ goto all_reg_disable; ++ } ++ ++ /* ++ * Default power operation mode initialization: will be updated upon ++ * attach/detach interrupt ++ */ ++ typec_set_pwr_opmode(chip->port, chip->pwr_opmode); ++ ++ if (!client->irq) { ++ /* ++ * If Source or Dual power role, need to enable VDD supply ++ * providing Vbus if present. In case of interrupt support, ++ * VDD supply will be dynamically managed upon attach/detach ++ * interrupt. ++ */ ++ if ((chip->port_type != TYPEC_PORT_SNK) && chip->vdd_supply) { ++ ret = regulator_enable(chip->vdd_supply); ++ if (ret) { ++ dev_err(chip->dev, ++ "Failed to enable VDD supply: %d\n", ++ ret); ++ goto port_unregister; ++ } ++ chip->vbus_on = true; ++ } ++ ++ return 0; ++ } ++ ++ fwnode = device_get_named_child_node(chip->dev, "connector"); ++ chip->role_sw = fwnode_usb_role_switch_get(fwnode); ++ if (IS_ERR(chip->role_sw)) { ++ ret = PTR_ERR(chip->role_sw); ++ if (ret != -EPROBE_DEFER) ++ dev_err(chip->dev, ++ "Failed to get usb role switch: %d\n", ret); ++ goto port_unregister; ++ } ++ ++ if (chip->role_sw) ++ INIT_WORK(&chip->wq_role_sw, stusb_set_role_sw); ++ ++ ret = stusb_irq_init(chip, client->irq); ++ if (ret) ++ goto role_sw_put; ++ ++ return 0; ++ ++role_sw_put: ++ if (chip->role_sw) { ++ cancel_work_sync(&chip->wq_role_sw); ++ usb_role_switch_put(chip->role_sw); ++ } ++port_unregister: ++ typec_unregister_port(chip->port); ++all_reg_disable: ++ if (stusb_get_vconn(chip)) ++ stusb_set_vconn(chip, false); ++main_reg_disable: ++ if (chip->main_supply) ++ regulator_disable(chip->main_supply); ++ ++ return ret; ++} ++ ++static int stusb_remove(struct i2c_client *client) ++{ ++ struct stusb *chip = i2c_get_clientdata(client); ++ ++ if (chip->partner) { ++ typec_unregister_partner(chip->partner); ++ chip->partner = NULL; ++ } ++ ++ if (chip->vbus_on) ++ regulator_disable(chip->vdd_supply); ++ ++ if (chip->role_sw) { ++ cancel_work_sync(&chip->wq_role_sw); ++ usb_role_switch_put(chip->role_sw); ++ } ++ ++ typec_unregister_port(chip->port); ++ ++ if (stusb_get_vconn(chip)) ++ stusb_set_vconn(chip, false); ++ ++ if (chip->main_supply) ++ regulator_disable(chip->main_supply); ++ ++ return 0; ++} ++ ++static int __maybe_unused stusb_suspend(struct device *dev) ++{ ++ struct stusb *chip = dev_get_drvdata(dev); ++ ++ /* Mask interrupts */ ++ return regmap_update_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, ++ STUSB_ALL_ALERTS, STUSB_ALL_ALERTS); ++} ++ ++static int __maybe_unused stusb_resume(struct device *dev) ++{ ++ struct stusb *chip = dev_get_drvdata(dev); ++ u32 status; ++ int ret; ++ ++ ret = regcache_sync(chip->regmap); ++ if (ret) ++ return ret; ++ ++ /* Check if attach/detach occurred during low power */ ++ ret = regmap_read(chip->regmap, STUSB_CC_CONNECTION_STATUS, &status); ++ if (ret) ++ return ret; ++ ++ if (chip->partner && !(status & STUSB_CC_ATTACH)) ++ stusb_detach(chip, status); ++ ++ if (!chip->partner && (status & STUSB_CC_ATTACH)) { ++ ret = stusb_attach(chip, status); ++ if (ret) ++ dev_err(chip->dev, "attach failed: %d\n", ret); ++ } ++ ++ /* Unmask interrupts */ ++ return regmap_write_bits(chip->regmap, STUSB_ALERT_STATUS_MASK_CTRL, ++ STUSB_CC_CONNECTION, 0); ++} ++ ++static SIMPLE_DEV_PM_OPS(stusb_pm_ops, stusb_suspend, stusb_resume); ++ ++static struct i2c_driver stusb_driver = { ++ .driver = { ++ .name = "typec_stusb", ++ .pm = &stusb_pm_ops, ++ .of_match_table = stusb_of_match, ++ }, ++ .probe = stusb_probe, ++ .remove = stusb_remove, ++}; ++module_i2c_driver(stusb_driver); ++ ++MODULE_AUTHOR("Amelie Delaunay "); ++MODULE_DESCRIPTION("STMicroelectronics STUSB Type-C controller driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h +index 15032f145..99ec370a6 100644 +--- a/include/linux/phy/phy.h ++++ b/include/linux/phy/phy.h +@@ -233,7 +233,8 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, + const char *con_id); + struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index); +-void phy_put(struct phy *phy); ++void of_phy_put(struct phy *phy); ++void phy_put(struct device *dev, struct phy *phy); + void devm_phy_put(struct device *dev, struct phy *phy); + struct phy *of_phy_get(struct device_node *np, const char *con_id); + struct phy *of_phy_simple_xlate(struct device *dev, +@@ -418,7 +419,11 @@ static inline struct phy *devm_of_phy_get_by_index(struct device *dev, + return ERR_PTR(-ENOSYS); + } + +-static inline void phy_put(struct phy *phy) ++static inline void of_phy_put(struct phy *phy) ++{ ++} ++ ++static inline void phy_put(struct device *dev, struct phy *phy) + { + } + +diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h +index 7df4ecabc..2671776a1 100644 +--- a/include/linux/usb/typec.h ++++ b/include/linux/usb/typec.h +@@ -241,6 +241,7 @@ int typec_set_orientation(struct typec_port *port, + enum typec_orientation typec_get_orientation(struct typec_port *port); + int typec_set_mode(struct typec_port *port, int mode); + ++int typec_find_port_power_opmode(const char *name); + int typec_find_port_power_role(const char *name); + int typec_find_power_role(const char *name); + int typec_find_port_data_role(const char *name); +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch new file mode 100644 index 0000000..e02a3b6 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch @@ -0,0 +1,2670 @@ +From 479f8a903c863085c2bc680c71ae0f7fea166aa8 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:47:29 +0200 +Subject: [PATCH 17/23] ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM + +--- + drivers/pinctrl/pinctrl-stmfx.c | 36 +- + drivers/pinctrl/stm32/pinctrl-stm32.c | 250 +++++++--- + drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- + drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + + drivers/pwm/pwm-stm32.c | 116 +++-- + drivers/regulator/stm32-pwr.c | 85 +++- + drivers/regulator/stpmic1_regulator.c | 203 +++++++- + drivers/spi/spi-stm32-qspi.c | 127 ++++- + drivers/spi/spi-stm32.c | 511 +++++++++++++-------- + 9 files changed, 990 insertions(+), 356 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c +index ccdf0bb21..f7958eece 100644 +--- a/drivers/pinctrl/pinctrl-stmfx.c ++++ b/drivers/pinctrl/pinctrl-stmfx.c +@@ -277,7 +277,7 @@ static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + struct pinctrl_gpio_range *range; + enum pin_config_param param; + u32 arg; +- int dir, i, ret; ++ int i, ret; + + range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); + if (!range) { +@@ -285,10 +285,6 @@ static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + return -EINVAL; + } + +- dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin); +- if (dir < 0) +- return dir; +- + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); +@@ -505,6 +501,34 @@ static void stmfx_pinctrl_irq_bus_sync_unlock(struct irq_data *data) + mutex_unlock(&pctl->lock); + } + ++static int stmfx_gpio_irq_request_resources(struct irq_data *data) ++{ ++ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); ++ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); ++ int ret; ++ ++ ret = stmfx_gpio_direction_input(&pctl->gpio_chip, data->hwirq); ++ if (ret) ++ return ret; ++ ++ ret = gpiochip_lock_as_irq(&pctl->gpio_chip, data->hwirq); ++ if (ret) { ++ dev_err(pctl->dev, "Unable to lock gpio %lu as IRQ: %d\n", ++ data->hwirq, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void stmfx_gpio_irq_release_resources(struct irq_data *data) ++{ ++ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); ++ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); ++ ++ gpiochip_unlock_as_irq(&pctl->gpio_chip, data->hwirq); ++} ++ + static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl, + unsigned int offset) + { +@@ -664,6 +688,8 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) + pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type; + pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock; + pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock; ++ pctl->irq_chip.irq_request_resources = stmfx_gpio_irq_request_resources; ++ pctl->irq_chip.irq_release_resources = stmfx_gpio_irq_release_resources; + + ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip, + 0, handle_bad_irq, IRQ_TYPE_NONE); +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c +index 2d5e0435a..1d52cbeab 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32.c ++++ b/drivers/pinctrl/stm32/pinctrl-stm32.c +@@ -64,7 +64,7 @@ + #define gpio_range_to_bank(chip) \ + container_of(chip, struct stm32_gpio_bank, range) + +-#define HWSPINLOCK_TIMEOUT 5 /* msec */ ++#define HWSPNLCK_TIMEOUT 1000 /* usec */ + + static const char * const stm32_gpio_functions[] = { + "gpio", "af0", "af1", +@@ -73,6 +73,7 @@ static const char * const stm32_gpio_functions[] = { + "af8", "af9", "af10", + "af11", "af12", "af13", + "af14", "af15", "analog", ++ "reserved", + }; + + struct stm32_pinctrl_group { +@@ -84,6 +85,7 @@ struct stm32_pinctrl_group { + struct stm32_gpio_bank { + void __iomem *base; + struct clk *clk; ++ struct reset_control *rstc; + spinlock_t lock; + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range range; +@@ -92,6 +94,7 @@ struct stm32_gpio_bank { + u32 bank_nr; + u32 bank_ioport_nr; + u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; ++ u8 irq_type[STM32_GPIO_PINS_PER_BANK]; + }; + + struct stm32_pinctrl { +@@ -113,6 +116,7 @@ struct stm32_pinctrl { + u32 pkg; + u16 irqmux_map; + spinlock_t irqmux_lock; ++ u32 pin_base_shift; + }; + + static inline int stm32_gpio_pin(int gpio) +@@ -301,6 +305,51 @@ static const struct gpio_chip stm32_gpio_template = { + .direction_output = stm32_gpio_direction_output, + .to_irq = stm32_gpio_to_irq, + .get_direction = stm32_gpio_get_direction, ++ .set_config = gpiochip_generic_config, ++}; ++ ++static void stm32_gpio_irq_trigger(struct irq_data *d) ++{ ++ struct stm32_gpio_bank *bank = d->domain->host_data; ++ int level; ++ ++ /* If level interrupt type then retrig */ ++ level = stm32_gpio_get(&bank->gpio_chip, d->hwirq); ++ if ((level == 0 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_LOW) || ++ (level == 1 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_HIGH)) ++ irq_chip_retrigger_hierarchy(d); ++} ++ ++static void stm32_gpio_irq_eoi(struct irq_data *d) ++{ ++ irq_chip_eoi_parent(d); ++ stm32_gpio_irq_trigger(d); ++}; ++ ++static int stm32_gpio_set_type(struct irq_data *d, unsigned int type) ++{ ++ struct stm32_gpio_bank *bank = d->domain->host_data; ++ u32 parent_type; ++ ++ switch (type) { ++ case IRQ_TYPE_EDGE_RISING: ++ case IRQ_TYPE_EDGE_FALLING: ++ case IRQ_TYPE_EDGE_BOTH: ++ parent_type = type; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ parent_type = IRQ_TYPE_EDGE_RISING; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ parent_type = IRQ_TYPE_EDGE_FALLING; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ bank->irq_type[d->hwirq] = type; ++ ++ return irq_chip_set_type_parent(d, parent_type); + }; + + static int stm32_gpio_irq_request_resources(struct irq_data *irq_data) +@@ -330,13 +379,19 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data) + gpiochip_unlock_as_irq(&bank->gpio_chip, irq_data->hwirq); + } + ++static void stm32_gpio_irq_unmask(struct irq_data *d) ++{ ++ irq_chip_unmask_parent(d); ++ stm32_gpio_irq_trigger(d); ++} ++ + static struct irq_chip stm32_gpio_irq_chip = { + .name = "stm32gpio", +- .irq_eoi = irq_chip_eoi_parent, ++ .irq_eoi = stm32_gpio_irq_eoi, + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, +- .irq_unmask = irq_chip_unmask_parent, +- .irq_set_type = irq_chip_set_type_parent, ++ .irq_unmask = stm32_gpio_irq_unmask, ++ .irq_set_type = stm32_gpio_set_type, + .irq_set_wake = irq_chip_set_wake_parent, + .irq_request_resources = stm32_gpio_irq_request_resources, + .irq_release_resources = stm32_gpio_irq_release_resources, +@@ -369,12 +424,14 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, + * to avoid overriding. + */ + spin_lock_irqsave(&pctl->irqmux_lock, flags); +- if (pctl->hwlock) +- ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); + +- if (ret) { +- dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ if (pctl->hwlock) { ++ ret = hwspin_lock_timeout_in_atomic(pctl->hwlock, ++ HWSPNLCK_TIMEOUT); ++ if (ret) { ++ dev_err(pctl->dev, "Can't get hwspinlock\n"); ++ goto unlock; ++ } + } + + if (pctl->irqmux_map & BIT(irq_data->hwirq)) { +@@ -382,7 +439,7 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, + irq_data->hwirq); + ret = -EBUSY; + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + goto unlock; + } else { + pctl->irqmux_map |= BIT(irq_data->hwirq); +@@ -391,7 +448,7 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, + regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); + + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + + unlock: + spin_unlock_irqrestore(&pctl->irqmux_lock, flags); +@@ -458,7 +515,7 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) + static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, + u32 pin_num, u32 fnum) + { +- int i; ++ int i, k; + + for (i = 0; i < pctl->npins; i++) { + const struct stm32_desc_pin *pin = pctl->pins + i; +@@ -467,7 +524,10 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, + if (pin->pin.number != pin_num) + continue; + +- while (func && func->name) { ++ if (fnum == STM32_PIN_RSVD) ++ return true; ++ ++ for (k = 0; k < STM32_CONFIG_NUM; k++) { + if (func->num == fnum) + return true; + func++; +@@ -699,12 +759,13 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, + clk_enable(bank->clk); + spin_lock_irqsave(&bank->lock, flags); + +- if (pctl->hwlock) +- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); +- +- if (err) { +- dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ if (pctl->hwlock) { ++ err = hwspin_lock_timeout_in_atomic(pctl->hwlock, ++ HWSPNLCK_TIMEOUT); ++ if (err) { ++ dev_err(pctl->dev, "Can't get hwspinlock\n"); ++ goto unlock; ++ } + } + + val = readl_relaxed(bank->base + alt_offset); +@@ -718,7 +779,7 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, + writel_relaxed(val, bank->base + STM32_GPIO_MODER); + + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + + stm32_gpio_backup_mode(bank, pin, mode, alt); + +@@ -777,6 +838,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, + return -EINVAL; + } + ++ if (function == STM32_PIN_RSVD) { ++ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); ++ return 0; ++ } ++ + bank = gpiochip_get_data(range->gc); + pin = stm32_gpio_pin(g->pin); + +@@ -818,12 +884,13 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, + clk_enable(bank->clk); + spin_lock_irqsave(&bank->lock, flags); + +- if (pctl->hwlock) +- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); +- +- if (err) { +- dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ if (pctl->hwlock) { ++ err = hwspin_lock_timeout_in_atomic(pctl->hwlock, ++ HWSPNLCK_TIMEOUT); ++ if (err) { ++ dev_err(pctl->dev, "Can't get hwspinlock\n"); ++ goto unlock; ++ } + } + + val = readl_relaxed(bank->base + STM32_GPIO_TYPER); +@@ -832,7 +899,7 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, + writel_relaxed(val, bank->base + STM32_GPIO_TYPER); + + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + + stm32_gpio_backup_driving(bank, offset, drive); + +@@ -872,12 +939,13 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, + clk_enable(bank->clk); + spin_lock_irqsave(&bank->lock, flags); + +- if (pctl->hwlock) +- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); +- +- if (err) { +- dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ if (pctl->hwlock) { ++ err = hwspin_lock_timeout_in_atomic(pctl->hwlock, ++ HWSPNLCK_TIMEOUT); ++ if (err) { ++ dev_err(pctl->dev, "Can't get hwspinlock\n"); ++ goto unlock; ++ } + } + + val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); +@@ -886,7 +954,7 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, + writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR); + + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + + stm32_gpio_backup_speed(bank, offset, speed); + +@@ -926,12 +994,13 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, + clk_enable(bank->clk); + spin_lock_irqsave(&bank->lock, flags); + +- if (pctl->hwlock) +- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); +- +- if (err) { +- dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ if (pctl->hwlock) { ++ err = hwspin_lock_timeout_in_atomic(pctl->hwlock, ++ HWSPNLCK_TIMEOUT); ++ if (err) { ++ dev_err(pctl->dev, "Can't get hwspinlock\n"); ++ goto unlock; ++ } + } + + val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); +@@ -940,7 +1009,7 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, + writel_relaxed(val, bank->base + STM32_GPIO_PUPDR); + + if (pctl->hwlock) +- hwspin_unlock(pctl->hwlock); ++ hwspin_unlock_in_atomic(pctl->hwlock); + + stm32_gpio_backup_bias(bank, offset, bias); + +@@ -992,20 +1061,14 @@ static bool stm32_pconf_get(struct stm32_gpio_bank *bank, + } + + static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, +- unsigned int pin, enum pin_config_param param, +- enum pin_config_param arg) ++ struct pinctrl_gpio_range *range, ++ unsigned int pin, ++ enum pin_config_param param, ++ enum pin_config_param arg) + { +- struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); +- struct pinctrl_gpio_range *range; + struct stm32_gpio_bank *bank; + int offset, ret = 0; + +- range = pinctrl_find_gpio_range_from_pin(pctldev, pin); +- if (!range) { +- dev_err(pctl->dev, "No gpio range defined.\n"); +- return -EINVAL; +- } +- + bank = gpiochip_get_data(range->gc); + offset = stm32_gpio_pin(pin); + +@@ -1033,7 +1096,8 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, + ret = stm32_pmx_gpio_set_direction(pctldev, range, pin, false); + break; + default: +- ret = -EINVAL; ++ dev_dbg(pctldev->dev, "configuration %d not supported.\n", ++ param); + } + + return ret; +@@ -1055,12 +1119,19 @@ static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, + { + struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct stm32_pinctrl_group *g = &pctl->groups[group]; ++ struct pinctrl_gpio_range *range; + int i, ret; + ++ range = pinctrl_find_gpio_range_from_pin(pctldev, g->pin); ++ if (!range) { ++ dev_err(pctl->dev, "No gpio range defined.\n"); ++ return -EINVAL; ++ } ++ + for (i = 0; i < num_configs; i++) { +- ret = stm32_pconf_parse_conf(pctldev, g->pin, +- pinconf_to_config_param(configs[i]), +- pinconf_to_config_argument(configs[i])); ++ ret = stm32_pconf_parse_conf(pctldev, range, g->pin, ++ pinconf_to_config_param(configs[i]), ++ pinconf_to_config_argument(configs[i])); + if (ret < 0) + return ret; + +@@ -1070,10 +1141,36 @@ static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, + return 0; + } + ++static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *configs, unsigned int num_configs) ++{ ++ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ struct pinctrl_gpio_range *range; ++ int i, ret; ++ ++ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); ++ if (!range) { ++ dev_err(pctl->dev, "No gpio range defined.\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < num_configs; i++) { ++ ret = stm32_pconf_parse_conf(pctldev, range, pin, ++ pinconf_to_config_param(configs[i]), ++ pinconf_to_config_argument(configs[i])); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int pin) + { ++ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ const struct stm32_desc_pin *pin_desc; + struct pinctrl_gpio_range *range; + struct stm32_gpio_bank *bank; + int offset; +@@ -1123,7 +1220,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, + case 2: + drive = stm32_pconf_get_driving(bank, offset); + speed = stm32_pconf_get_speed(bank, offset); +- seq_printf(s, "%d - %s - %s - %s %s", alt, ++ pin_desc = pctl->pins + (pin - pctl->pin_base_shift); ++ seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, ++ pin_desc->functions[alt + 1].name, + drive ? "open drain" : "push pull", + biasing[bias], + speeds[speed], "speed"); +@@ -1140,6 +1239,7 @@ static const struct pinconf_ops stm32_pconf_ops = { + .pin_config_group_get = stm32_pconf_group_get, + .pin_config_group_set = stm32_pconf_group_set, + .pin_config_dbg_show = stm32_pconf_dbg_show, ++ .pin_config_set = stm32_pconf_set, + }; + + static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, +@@ -1151,13 +1251,11 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, + struct of_phandle_args args; + struct device *dev = pctl->dev; + struct resource res; +- struct reset_control *rstc; + int npins = STM32_GPIO_PINS_PER_BANK; + int bank_nr, err; + +- rstc = of_reset_control_get_exclusive(np, NULL); +- if (!IS_ERR(rstc)) +- reset_control_deassert(rstc); ++ if (!IS_ERR(bank->rstc)) ++ reset_control_deassert(bank->rstc); + + if (of_address_to_resource(np, 0, &res)) + return -ENODEV; +@@ -1166,12 +1264,6 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, + if (IS_ERR(bank->base)) + return PTR_ERR(bank->base); + +- bank->clk = of_clk_get_by_name(np, NULL); +- if (IS_ERR(bank->clk)) { +- dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk)); +- return PTR_ERR(bank->clk); +- } +- + err = clk_prepare(bank->clk); + if (err) { + dev_err(dev, "failed to prepare clk (%d)\n", err); +@@ -1335,7 +1427,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, + if (pctl->pkg && !(pctl->pkg & p->pkg)) + continue; + pins->pin = p->pin; +- pins->functions = p->functions; ++ memcpy((struct stm32_desc_pin *)pins->functions, p->functions, ++ STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); + pins++; + nb_pins_available++; + } +@@ -1444,6 +1537,7 @@ int stm32_pctl_probe(struct platform_device *pdev) + pctl->pctl_desc.pctlops = &stm32_pctrl_ops; + pctl->pctl_desc.pmxops = &stm32_pmx_ops; + pctl->dev = &pdev->dev; ++ pctl->pin_base_shift = pctl->match_data->pin_base_shift; + + pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, + pctl); +@@ -1466,6 +1560,28 @@ int stm32_pctl_probe(struct platform_device *pdev) + if (!pctl->banks) + return -ENOMEM; + ++ i = 0; ++ for_each_available_child_of_node(np, child) { ++ struct stm32_gpio_bank *bank = &pctl->banks[i]; ++ ++ if (of_property_read_bool(child, "gpio-controller")) { ++ bank->rstc = of_reset_control_get_exclusive(child, ++ NULL); ++ if (PTR_ERR(bank->rstc) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ bank->clk = of_clk_get_by_name(child, NULL); ++ if (IS_ERR(bank->clk)) { ++ if (PTR_ERR(bank->clk) != -EPROBE_DEFER) ++ dev_err(dev, ++ "failed to get clk (%ld)\n", ++ PTR_ERR(bank->clk)); ++ return PTR_ERR(bank->clk); ++ } ++ i++; ++ } ++ } ++ + for_each_available_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + ret = stm32_gpiolib_register_bank(pctl, child); +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h +index ec0d34c33..b11a223f3 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32.h ++++ b/drivers/pinctrl/stm32/pinctrl-stm32.h +@@ -17,6 +17,8 @@ + #define STM32_PIN_GPIO 0 + #define STM32_PIN_AF(x) ((x) + 1) + #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) ++#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) ++#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) + + /* package information */ + #define STM32MP_PKG_AA BIT(0) +@@ -24,6 +26,8 @@ + #define STM32MP_PKG_AC BIT(2) + #define STM32MP_PKG_AD BIT(3) + ++#define STM32MP157_Z_BASE_SHIFT 400 ++ + struct stm32_desc_function { + const char *name; + const unsigned char num; +@@ -31,26 +35,26 @@ struct stm32_desc_function { + + struct stm32_desc_pin { + struct pinctrl_pin_desc pin; +- const struct stm32_desc_function *functions; ++ const struct stm32_desc_function functions[STM32_CONFIG_NUM]; + const unsigned int pkg; + }; + + #define STM32_PIN(_pin, ...) \ + { \ + .pin = _pin, \ +- .functions = (struct stm32_desc_function[]){ \ +- __VA_ARGS__, { } }, \ ++ .functions = { \ ++ __VA_ARGS__}, \ + } + + #define STM32_PIN_PKG(_pin, _pkg, ...) \ + { \ + .pin = _pin, \ + .pkg = _pkg, \ +- .functions = (struct stm32_desc_function[]){ \ +- __VA_ARGS__, { } }, \ ++ .functions = { \ ++ __VA_ARGS__}, \ + } + #define STM32_FUNCTION(_num, _name) \ +- { \ ++ [_num] = { \ + .num = _num, \ + .name = _name, \ + } +@@ -58,6 +62,7 @@ struct stm32_desc_pin { + struct stm32_pinctrl_match_data { + const struct stm32_desc_pin *pins; + const unsigned int npins; ++ const unsigned int pin_base_shift; + }; + + struct stm32_gpio_bank; +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +index 2ccb99d64..86fe6d5ac 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c ++++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +@@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { + static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { + .pins = stm32mp157_z_pins, + .npins = ARRAY_SIZE(stm32mp157_z_pins), ++ .pin_base_shift = STM32MP157_Z_BASE_SHIFT, + }; + + static const struct of_device_id stm32mp157_pctrl_match[] = { +diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c +index 359b08596..d3be944f2 100644 +--- a/drivers/pwm/pwm-stm32.c ++++ b/drivers/pwm/pwm-stm32.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -19,6 +20,12 @@ + #define CCMR_CHANNEL_MASK 0xFF + #define MAX_BREAKINPUT 2 + ++struct stm32_breakinput { ++ u32 index; ++ u32 level; ++ u32 filter; ++}; ++ + struct stm32_pwm { + struct pwm_chip chip; + struct mutex lock; /* protect pwm config/enable */ +@@ -26,15 +33,11 @@ struct stm32_pwm { + struct regmap *regmap; + u32 max_arr; + bool have_complementary_output; ++ struct stm32_breakinput breakinputs[MAX_BREAKINPUT]; ++ unsigned int num_breakinputs; + u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */ + }; + +-struct stm32_breakinput { +- u32 index; +- u32 level; +- u32 filter; +-}; +- + static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip) + { + return container_of(chip, struct stm32_pwm, chip); +@@ -374,9 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, + else + regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); + +- regmap_update_bits(priv->regmap, TIM_BDTR, +- TIM_BDTR_MOE | TIM_BDTR_AOE, +- TIM_BDTR_MOE | TIM_BDTR_AOE); ++ regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE); + + return 0; + } +@@ -488,22 +489,19 @@ static const struct pwm_ops stm32pwm_ops = { + }; + + static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, +- int index, int level, int filter) ++ const struct stm32_breakinput *bi) + { +- u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E; +- int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT; +- u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF +- : TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F; +- u32 bdtr = bke; ++ u32 shift = TIM_BDTR_BKF_SHIFT(bi->index); ++ u32 bke = TIM_BDTR_BKE(bi->index); ++ u32 bkp = TIM_BDTR_BKP(bi->index); ++ u32 bkf = TIM_BDTR_BKF(bi->index); ++ u32 mask = bkf | bkp | bke; ++ u32 bdtr; + +- /* +- * The both bits could be set since only one will be wrote +- * due to mask value. +- */ +- if (level) +- bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P; ++ bdtr = (bi->filter & TIM_BDTR_BKF_MASK) << shift | bke; + +- bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift; ++ if (bi->level) ++ bdtr |= bkp; + + regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr); + +@@ -512,11 +510,25 @@ static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, + return (bdtr & bke) ? 0 : -EINVAL; + } + +-static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv, ++static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv) ++{ ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < priv->num_breakinputs; i++) { ++ ret = stm32_pwm_set_breakinput(priv, &priv->breakinputs[i]); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int stm32_pwm_probe_breakinputs(struct stm32_pwm *priv, + struct device_node *np) + { +- struct stm32_breakinput breakinput[MAX_BREAKINPUT]; +- int nb, ret, i, array_size; ++ int nb, ret, array_size; ++ unsigned int i; + + nb = of_property_count_elems_of_size(np, "st,breakinput", + sizeof(struct stm32_breakinput)); +@@ -531,20 +543,21 @@ static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv, + if (nb > MAX_BREAKINPUT) + return -EINVAL; + ++ priv->num_breakinputs = nb; + array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32); + ret = of_property_read_u32_array(np, "st,breakinput", +- (u32 *)breakinput, array_size); ++ (u32 *)priv->breakinputs, array_size); + if (ret) + return ret; + +- for (i = 0; i < nb && !ret; i++) { +- ret = stm32_pwm_set_breakinput(priv, +- breakinput[i].index, +- breakinput[i].level, +- breakinput[i].filter); ++ for (i = 0; i < priv->num_breakinputs; i++) { ++ if (priv->breakinputs[i].index > 1 || ++ priv->breakinputs[i].level > 1 || ++ priv->breakinputs[i].filter > 15) ++ return -EINVAL; + } + +- return ret; ++ return stm32_pwm_apply_breakinputs(priv); + } + + static void stm32_pwm_detect_complementary(struct stm32_pwm *priv) +@@ -614,7 +627,7 @@ static int stm32_pwm_probe(struct platform_device *pdev) + if (!priv->regmap || !priv->clk) + return -EINVAL; + +- ret = stm32_pwm_apply_breakinputs(priv, np); ++ ret = stm32_pwm_probe_breakinputs(priv, np); + if (ret) + return ret; + +@@ -647,6 +660,42 @@ static int stm32_pwm_remove(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused stm32_pwm_suspend(struct device *dev) ++{ ++ struct stm32_pwm *priv = dev_get_drvdata(dev); ++ unsigned int i; ++ u32 ccer, mask; ++ ++ /* Look for active channels */ ++ ccer = active_channels(priv); ++ ++ for (i = 0; i < priv->chip.npwm; i++) { ++ mask = TIM_CCER_CC1E << (i * 4); ++ if (ccer & mask) { ++ dev_err(dev, "PWM %u still in use by consumer %s\n", ++ i, priv->chip.pwms[i].label); ++ return -EBUSY; ++ } ++ } ++ ++ return pinctrl_pm_select_sleep_state(dev); ++} ++ ++static int __maybe_unused stm32_pwm_resume(struct device *dev) ++{ ++ struct stm32_pwm *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pinctrl_pm_select_default_state(dev); ++ if (ret) ++ return ret; ++ ++ /* restore breakinput registers that may have been lost in low power */ ++ return stm32_pwm_apply_breakinputs(priv); ++} ++ ++static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume); ++ + static const struct of_device_id stm32_pwm_of_match[] = { + { .compatible = "st,stm32-pwm", }, + { /* end node */ }, +@@ -659,6 +708,7 @@ static struct platform_driver stm32_pwm_driver = { + .driver = { + .name = "stm32-pwm", + .of_match_table = stm32_pwm_of_match, ++ .pm = &stm32_pwm_pm_ops, + }, + }; + module_platform_driver(stm32_pwm_driver); +diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c +index e0e627b01..373d83797 100644 +--- a/drivers/regulator/stm32-pwr.c ++++ b/drivers/regulator/stm32-pwr.c +@@ -3,12 +3,15 @@ + // Authors: Gabriel Fernandez + // Pascal Paillet . + ++#include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + +@@ -24,6 +27,11 @@ + #define REG_1_1_EN BIT(30) + #define REG_1_1_RDY BIT(31) + ++#define STM32_SMC_PWR 0x82001001 ++#define STM32_WRITE 0x1 ++#define STM32_SMC_REG_SET 0x2 ++#define STM32_SMC_REG_CLEAR 0x3 ++ + /* list of supported regulators */ + enum { + PWR_REG11, +@@ -39,10 +47,18 @@ static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = { + }; + + struct stm32_pwr_reg { ++ int tzen; + void __iomem *base; + u32 ready_mask; + }; + ++#define SMC(class, op, address, val)\ ++ ({\ ++ struct arm_smccc_res res;\ ++ arm_smccc_smc(class, op, address, val,\ ++ 0, 0, 0, 0, &res);\ ++ }) ++ + static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) + { + struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); +@@ -69,9 +85,15 @@ static int stm32_pwr_reg_enable(struct regulator_dev *rdev) + int ret; + u32 val; + +- val = readl_relaxed(priv->base + REG_PWR_CR3); +- val |= rdev->desc->enable_mask; +- writel_relaxed(val, priv->base + REG_PWR_CR3); ++ if (priv->tzen) { ++ SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, REG_PWR_CR3, ++ rdev->desc->enable_mask); ++ } else { ++ val = readl_relaxed(priv->base + REG_PWR_CR3); ++ val |= rdev->desc->enable_mask; ++ writel_relaxed(val, priv->base + REG_PWR_CR3); ++ } ++ + + /* use an arbitrary timeout of 20ms */ + ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val, +@@ -88,9 +110,14 @@ static int stm32_pwr_reg_disable(struct regulator_dev *rdev) + int ret; + u32 val; + +- val = readl_relaxed(priv->base + REG_PWR_CR3); +- val &= ~rdev->desc->enable_mask; +- writel_relaxed(val, priv->base + REG_PWR_CR3); ++ if (priv->tzen) { ++ SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, REG_PWR_CR3, ++ rdev->desc->enable_mask); ++ } else { ++ val = readl_relaxed(priv->base + REG_PWR_CR3); ++ val &= ~rdev->desc->enable_mask; ++ writel_relaxed(val, priv->base + REG_PWR_CR3); ++ } + + /* use an arbitrary timeout of 20ms */ + ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val, +@@ -121,12 +148,50 @@ static const struct regulator_ops stm32_pwr_reg_ops = { + .supply_name = _supply, \ + } \ + +-static const struct regulator_desc stm32_pwr_desc[] = { ++static struct regulator_desc stm32_pwr_desc[] = { + PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"), + PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"), + PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"), + }; + ++static int is_stm32_soc_secured(struct platform_device *pdev, int *val) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct regmap *syscon; ++ u32 reg, mask; ++ int tzc_val = 0; ++ int err; ++ ++ syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); ++ if (IS_ERR(syscon)) { ++ if (PTR_ERR(syscon) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "tzcr syscon required\n"); ++ return PTR_ERR(syscon); ++ } ++ ++ err = of_property_read_u32_index(np, "st,tzcr", 1, ®); ++ if (err) { ++ dev_err(&pdev->dev, "tzcr offset required !\n"); ++ return err; ++ } ++ ++ err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); ++ if (err) { ++ dev_err(&pdev->dev, "tzcr mask required !\n"); ++ return err; ++ } ++ ++ err = regmap_read(syscon, reg, &tzc_val); ++ if (err) { ++ dev_err(&pdev->dev, "failed to read tzcr status !\n"); ++ return err; ++ } ++ ++ *val = tzc_val & mask; ++ ++ return 0; ++} ++ + static int stm32_pwr_regulator_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -135,6 +200,11 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) + struct regulator_dev *rdev; + struct regulator_config config = { }; + int i, ret = 0; ++ int tzen = 0; ++ ++ ret = is_stm32_soc_secured(pdev, &tzen); ++ if (ret) ++ return ret; + + base = of_iomap(np, 0); + if (!base) { +@@ -149,6 +219,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) + GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ priv->tzen = tzen; + priv->base = base; + priv->ready_mask = ready_mask_table[i]; + config.driver_data = priv; +diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c +index f09061473..4537e3ab1 100644 +--- a/drivers/regulator/stpmic1_regulator.c ++++ b/drivers/regulator/stpmic1_regulator.c +@@ -2,7 +2,9 @@ + // Copyright (C) STMicroelectronics 2018 + // Author: Pascal Paillet for STMicroelectronics. + ++#include + #include ++#include + #include + #include + #include +@@ -30,10 +32,26 @@ struct stpmic1_regulator_cfg { + u8 icc_mask; + }; + ++/** ++ * struct boost_data - this structure is used as driver data for the usb boost ++ * @boost_rdev: device for boost regulator ++ * @vbus_otg_rdev: device for vbus_otg regulator ++ * @sw_out_rdev: device for sw_out regulator ++ * @occ_timeout: overcurrent detection timeout ++ */ ++struct boost_data { ++ struct regulator_dev *boost_rdev; ++ struct regulator_dev *vbus_otg_rdev; ++ struct regulator_dev *sw_out_rdev; ++ ktime_t occ_timeout; ++}; ++ + static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); + static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); + static int stpmic1_set_icc(struct regulator_dev *rdev); + static unsigned int stpmic1_map_mode(unsigned int mode); ++static int regulator_enable_boost(struct regulator_dev *rdev); ++static int regulator_disable_boost(struct regulator_dev *rdev); + + enum { + STPMIC1_BUCK1 = 0, +@@ -54,6 +72,8 @@ enum { + + /* Enable time worst case is 5000mV/(2250uV/uS) */ + #define PMIC_ENABLE_TIME_US 2200 ++/* Ramp delay worst case is (2250uV/uS) */ ++#define PMIC_RAMP_DELAY 2200 + + static const struct regulator_linear_range buck1_ranges[] = { + REGULATOR_LINEAR_RANGE(725000, 0, 4, 0), +@@ -179,8 +199,8 @@ static const struct regulator_ops stpmic1_vref_ddr_ops = { + + static const struct regulator_ops stpmic1_boost_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, +- .enable = regulator_enable_regmap, +- .disable = regulator_disable_regmap, ++ .enable = regulator_enable_boost, ++ .disable = regulator_disable_boost, + .set_over_current_protection = stpmic1_set_icc, + }; + +@@ -208,6 +228,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = { + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ ++ .ramp_delay = PMIC_RAMP_DELAY, \ + .supply_name = #base, \ + } + +@@ -227,6 +248,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = { + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ ++ .ramp_delay = PMIC_RAMP_DELAY, \ + .bypass_reg = LDO3_ACTIVE_CR, \ + .bypass_mask = LDO_BYPASS_MASK, \ + .bypass_val_on = LDO_BYPASS_MASK, \ +@@ -248,6 +270,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = { + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ ++ .ramp_delay = PMIC_RAMP_DELAY, \ + .supply_name = #base, \ + } + +@@ -267,6 +290,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = { + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ ++ .ramp_delay = PMIC_RAMP_DELAY, \ + .of_map_mode = stpmic1_map_mode, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ +@@ -511,6 +535,94 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) + return IRQ_HANDLED; + } + ++static int regulator_enable_boost(struct regulator_dev *rdev) ++{ ++ struct boost_data *usb_data = rdev_get_drvdata(rdev); ++ ++ usb_data->occ_timeout = ktime_add_us(ktime_get(), 100000); ++ ++ return regulator_enable_regmap(rdev); ++} ++ ++static int regulator_disable_boost(struct regulator_dev *rdev) ++{ ++ struct boost_data *usb_data = rdev_get_drvdata(rdev); ++ ++ usb_data->occ_timeout = 0; ++ ++ return regulator_disable_regmap(rdev); ++} ++ ++static void stpmic1_reset_boost(struct boost_data *usb_data) ++{ ++ int otg_on = 0; ++ int sw_out_on = 0; ++ ++ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "reset usb boost\n"); ++ ++ regulator_lock(usb_data->boost_rdev); ++ ++ /* the boost was actually disabled by the over-current protection */ ++ regulator_disable_regmap(usb_data->boost_rdev); ++ ++ if (usb_data->vbus_otg_rdev) ++ otg_on = regulator_is_enabled_regmap(usb_data->vbus_otg_rdev); ++ if (otg_on) { ++ regulator_lock(usb_data->vbus_otg_rdev); ++ regulator_disable_regmap(usb_data->vbus_otg_rdev); ++ } ++ ++ if (usb_data->sw_out_rdev) ++ sw_out_on = regulator_is_enabled_regmap(usb_data->sw_out_rdev); ++ if (sw_out_on) { ++ regulator_lock(usb_data->sw_out_rdev); ++ regulator_disable_regmap(usb_data->sw_out_rdev); ++ } ++ ++ regulator_enable_regmap(usb_data->boost_rdev); ++ ++ /* sleep at least 5ms */ ++ usleep_range(5000, 10000); ++ ++ if (otg_on) { ++ regulator_enable_regmap(usb_data->vbus_otg_rdev); ++ regulator_unlock(usb_data->vbus_otg_rdev); ++ } ++ ++ if (sw_out_on) { ++ regulator_enable_regmap(usb_data->sw_out_rdev); ++ regulator_unlock(usb_data->sw_out_rdev); ++ } ++ ++ regulator_unlock(usb_data->boost_rdev); ++} ++ ++static irqreturn_t stpmic1_boost_irq_handler(int irq, void *data) ++{ ++ struct boost_data *usb_data = (struct boost_data *)data; ++ ++ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "usb boost irq handler\n"); ++ ++ /* overcurrent detected on boost after timeout */ ++ if (usb_data->occ_timeout != 0 && ++ ktime_compare(ktime_get(), usb_data->occ_timeout) > 0) { ++ /* reset usb boost and usb power switches */ ++ stpmic1_reset_boost(usb_data); ++ return IRQ_HANDLED; ++ } ++ ++ regulator_lock(usb_data->boost_rdev); ++ ++ /* Send an overcurrent notification */ ++ regulator_notifier_call_chain(usb_data->boost_rdev, ++ REGULATOR_EVENT_OVER_CURRENT, ++ NULL); ++ ++ regulator_unlock(usb_data->boost_rdev); ++ ++ return IRQ_HANDLED; ++} ++ + #define MATCH(_name, _id) \ + [STPMIC1_##_id] = { \ + .name = #_name, \ +@@ -534,9 +646,10 @@ static struct of_regulator_match stpmic1_matches[] = { + MATCH(pwr_sw2, SW_OUT), + }; + +-static int stpmic1_regulator_register(struct platform_device *pdev, int id, +- struct of_regulator_match *match, +- const struct stpmic1_regulator_cfg *cfg) ++static struct regulator_dev * ++stpmic1_regulator_register(struct platform_device *pdev, int id, ++ struct of_regulator_match *match, ++ const struct stpmic1_regulator_cfg *cfg) + { + struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); + struct regulator_dev *rdev; +@@ -554,7 +667,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", + cfg->desc.name); +- return PTR_ERR(rdev); ++ return rdev; + } + + /* set mask reset */ +@@ -566,7 +679,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + cfg->mask_reset_mask); + if (ret) { + dev_err(&pdev->dev, "set mask reset failed\n"); +- return ret; ++ return ERR_PTR(ret); + } + } + +@@ -580,15 +693,60 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + pdev->name, rdev); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); +- return ret; ++ return ERR_PTR(ret); + } + } +- return 0; ++ ++ return rdev; ++} ++ ++static struct regulator_dev * ++stpmic1_boost_register(struct platform_device *pdev, int id, ++ struct of_regulator_match *match, ++ const struct stpmic1_regulator_cfg *cfg, ++ struct boost_data *usb_data) ++{ ++ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); ++ struct regulator_dev *rdev; ++ struct regulator_config config = {}; ++ int ret = 0; ++ int irq; ++ ++ config.dev = &pdev->dev; ++ config.init_data = match->init_data; ++ config.of_node = match->of_node; ++ config.regmap = pmic_dev->regmap; ++ config.driver_data = (void *)usb_data; ++ ++ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&pdev->dev, "failed to register %s regulator\n", ++ cfg->desc.name); ++ return rdev; ++ } ++ ++ /* setup an irq handler for over-current detection */ ++ irq = of_irq_get(config.of_node, 0); ++ if (irq > 0) { ++ ret = devm_request_threaded_irq(&pdev->dev, ++ irq, NULL, ++ stpmic1_boost_irq_handler, ++ IRQF_ONESHOT, pdev->name, ++ usb_data); ++ if (ret) { ++ dev_err(&pdev->dev, "Request IRQ failed\n"); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ return rdev; + } + + static int stpmic1_regulator_probe(struct platform_device *pdev) + { + int i, ret; ++ struct boost_data *usb_data; ++ struct regulator_dev *rdev; + + ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, + ARRAY_SIZE(stpmic1_matches)); +@@ -598,11 +756,30 @@ static int stpmic1_regulator_probe(struct platform_device *pdev) + return ret; + } + ++ usb_data = devm_kzalloc(&pdev->dev, sizeof(*usb_data), GFP_KERNEL); ++ if (!usb_data) ++ return -ENOMEM; ++ + for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { +- ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], +- &stpmic1_regulator_cfgs[i]); +- if (ret < 0) +- return ret; ++ if (i == STPMIC1_BOOST) { ++ rdev = ++ stpmic1_boost_register(pdev, i, &stpmic1_matches[i], ++ &stpmic1_regulator_cfgs[i], ++ usb_data); ++ ++ usb_data->boost_rdev = rdev; ++ } else { ++ rdev = ++ stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], ++ &stpmic1_regulator_cfgs[i]); ++ ++ if (i == STPMIC1_VBUS_OTG) ++ usb_data->vbus_otg_rdev = rdev; ++ else if (i == STPMIC1_SW_OUT) ++ usb_data->sw_out_rdev = rdev; ++ } ++ if (IS_ERR(rdev)) ++ return PTR_ERR(rdev); + } + + dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); +diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c +index 4e726929b..02f110b10 100644 +--- a/drivers/spi/spi-stm32-qspi.c ++++ b/drivers/spi/spi-stm32-qspi.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -87,6 +88,7 @@ + #define STM32_BUSY_TIMEOUT_US 100000 + #define STM32_ABT_TIMEOUT_US 100000 + #define STM32_COMP_TIMEOUT_MS 1000 ++#define STM32_AUTOSUSPEND_DELAY -1 + + struct stm32_qspi_flash { + struct stm32_qspi *qspi; +@@ -431,10 +433,17 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + int ret; + ++ ret = pm_runtime_get_sync(qspi->dev); ++ if (ret < 0) ++ return ret; ++ + mutex_lock(&qspi->lock); + ret = stm32_qspi_send(mem, op); + mutex_unlock(&qspi->lock); + ++ pm_runtime_mark_last_busy(qspi->dev); ++ pm_runtime_put_autosuspend(qspi->dev); ++ + return ret; + } + +@@ -444,6 +453,7 @@ static int stm32_qspi_setup(struct spi_device *spi) + struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); + struct stm32_qspi_flash *flash; + u32 presc; ++ int ret; + + if (ctrl->busy) + return -EBUSY; +@@ -451,6 +461,10 @@ static int stm32_qspi_setup(struct spi_device *spi) + if (!spi->max_speed_hz) + return -EINVAL; + ++ ret = pm_runtime_get_sync(qspi->dev); ++ if (ret < 0) ++ return ret; ++ + presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; + + flash = &qspi->flash[spi->chip_select]; +@@ -467,13 +481,17 @@ static int stm32_qspi_setup(struct spi_device *spi) + writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); + mutex_unlock(&qspi->lock); + ++ pm_runtime_mark_last_busy(qspi->dev); ++ pm_runtime_put_autosuspend(qspi->dev); ++ + return 0; + } + +-static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) ++static int stm32_qspi_dma_setup(struct stm32_qspi *qspi) + { + struct dma_slave_config dma_cfg; + struct device *dev = qspi->dev; ++ int ret = 0; + + memset(&dma_cfg, 0, sizeof(dma_cfg)); + +@@ -484,8 +502,13 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) + dma_cfg.src_maxburst = 4; + dma_cfg.dst_maxburst = 4; + +- qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); +- if (qspi->dma_chrx) { ++ qspi->dma_chrx = dma_request_chan(dev, "rx"); ++ if (IS_ERR(qspi->dma_chrx)) { ++ ret = PTR_ERR(qspi->dma_chrx); ++ qspi->dma_chrx = NULL; ++ if (ret == -EPROBE_DEFER) ++ goto out; ++ } else { + if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { + dev_err(dev, "dma rx config failed\n"); + dma_release_channel(qspi->dma_chrx); +@@ -493,8 +516,11 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) + } + } + +- qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); +- if (qspi->dma_chtx) { ++ qspi->dma_chtx = dma_request_chan(dev, "tx"); ++ if (IS_ERR(qspi->dma_chtx)) { ++ ret = PTR_ERR(qspi->dma_chtx); ++ qspi->dma_chtx = NULL; ++ } else { + if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { + dev_err(dev, "dma tx config failed\n"); + dma_release_channel(qspi->dma_chtx); +@@ -502,7 +528,13 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) + } + } + ++out: + init_completion(&qspi->dma_completion); ++ ++ if (ret != -EPROBE_DEFER) ++ ret = 0; ++ ++ return ret; + } + + static void stm32_qspi_dma_free(struct stm32_qspi *qspi) +@@ -524,9 +556,14 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { + static void stm32_qspi_release(struct stm32_qspi *qspi) + { + /* disable qspi */ ++ pm_runtime_get_sync(qspi->dev); + writel_relaxed(0, qspi->io_base + QSPI_CR); + stm32_qspi_dma_free(qspi); + mutex_destroy(&qspi->lock); ++ pm_runtime_put_noidle(qspi->dev); ++ pm_runtime_disable(qspi->dev); ++ pm_runtime_set_suspended(qspi->dev); ++ pm_runtime_dont_use_autosuspend(qspi->dev); + clk_disable_unprepare(qspi->clk); + } + +@@ -550,7 +587,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) + qspi->io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->io_base)) { + ret = PTR_ERR(qspi->io_base); +- goto err; ++ goto err_master_put; + } + + qspi->phys_base = res->start; +@@ -559,24 +596,26 @@ static int stm32_qspi_probe(struct platform_device *pdev) + qspi->mm_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->mm_base)) { + ret = PTR_ERR(qspi->mm_base); +- goto err; ++ goto err_master_put; + } + + qspi->mm_size = resource_size(res); + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) { + ret = -EINVAL; +- goto err; ++ goto err_master_put; + } + + irq = platform_get_irq(pdev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto err_master_put; ++ } + + ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, + dev_name(dev), qspi); + if (ret) { + dev_err(dev, "failed to request irq\n"); +- goto err; ++ goto err_master_put; + } + + init_completion(&qspi->data_completion); +@@ -584,23 +623,27 @@ static int stm32_qspi_probe(struct platform_device *pdev) + qspi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(qspi->clk)) { + ret = PTR_ERR(qspi->clk); +- goto err; ++ goto err_master_put; + } + + qspi->clk_rate = clk_get_rate(qspi->clk); + if (!qspi->clk_rate) { + ret = -EINVAL; +- goto err; ++ goto err_master_put; + } + + ret = clk_prepare_enable(qspi->clk); + if (ret) { + dev_err(dev, "can not enable the clock\n"); +- goto err; ++ goto err_master_put; + } + + rstc = devm_reset_control_get_exclusive(dev, NULL); +- if (!IS_ERR(rstc)) { ++ if (IS_ERR(rstc)) { ++ ret = PTR_ERR(rstc); ++ if (ret == -EPROBE_DEFER) ++ goto err_qspi_release; ++ } else { + reset_control_assert(rstc); + udelay(2); + reset_control_deassert(rstc); +@@ -608,7 +651,10 @@ static int stm32_qspi_probe(struct platform_device *pdev) + + qspi->dev = dev; + platform_set_drvdata(pdev, qspi); +- stm32_qspi_dma_setup(qspi); ++ ret = stm32_qspi_dma_setup(qspi); ++ if (ret) ++ goto err_qspi_release; ++ + mutex_init(&qspi->lock); + + ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD +@@ -619,12 +665,24 @@ static int stm32_qspi_probe(struct platform_device *pdev) + ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; + ctrl->dev.of_node = dev->of_node; + ++ pm_runtime_set_autosuspend_delay(dev, STM32_AUTOSUSPEND_DELAY); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_get_noresume(dev); ++ + ret = devm_spi_register_master(dev, ctrl); +- if (!ret) +- return 0; ++ if (ret) ++ goto err_qspi_release; ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; + +-err: ++err_qspi_release: + stm32_qspi_release(qspi); ++err_master_put: + spi_master_put(qspi->ctrl); + + return ret; +@@ -635,14 +693,28 @@ static int stm32_qspi_remove(struct platform_device *pdev) + struct stm32_qspi *qspi = platform_get_drvdata(pdev); + + stm32_qspi_release(qspi); ++ + return 0; + } + +-static int __maybe_unused stm32_qspi_suspend(struct device *dev) ++static int __maybe_unused stm32_qspi_runtime_suspend(struct device *dev) + { + struct stm32_qspi *qspi = dev_get_drvdata(dev); + + clk_disable_unprepare(qspi->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_qspi_runtime_resume(struct device *dev) ++{ ++ struct stm32_qspi *qspi = dev_get_drvdata(dev); ++ ++ return clk_prepare_enable(qspi->clk); ++} ++ ++static int __maybe_unused stm32_qspi_suspend(struct device *dev) ++{ + pinctrl_pm_select_sleep_state(dev); + + return 0; +@@ -651,17 +723,28 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) + static int __maybe_unused stm32_qspi_resume(struct device *dev) + { + struct stm32_qspi *qspi = dev_get_drvdata(dev); ++ int ret; + + pinctrl_pm_select_default_state(dev); +- clk_prepare_enable(qspi->clk); ++ ++ ret = pm_runtime_get_sync(qspi->dev); ++ if (ret < 0) ++ return ret; + + writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); + writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); + ++ pm_runtime_mark_last_busy(qspi->dev); ++ pm_runtime_put_autosuspend(qspi->dev); ++ + return 0; + } + +-static SIMPLE_DEV_PM_OPS(stm32_qspi_pm_ops, stm32_qspi_suspend, stm32_qspi_resume); ++static const struct dev_pm_ops stm32_qspi_pm_ops = { ++ SET_RUNTIME_PM_OPS(stm32_qspi_runtime_suspend, ++ stm32_qspi_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(stm32_qspi_suspend, stm32_qspi_resume) ++}; + + static const struct of_device_id stm32_qspi_match[] = { + {.compatible = "st,stm32f469-qspi"}, +diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c +index b222ce8d0..df98a6925 100644 +--- a/drivers/spi/spi-stm32.c ++++ b/drivers/spi/spi-stm32.c +@@ -5,6 +5,7 @@ + // Copyright (C) 2017, STMicroelectronics - All Rights Reserved + // Author(s): Amelie Delaunay for STMicroelectronics. + ++#include + #include + #include + #include +@@ -13,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,8 +33,8 @@ + #define STM32F4_SPI_CR1_CPHA BIT(0) + #define STM32F4_SPI_CR1_CPOL BIT(1) + #define STM32F4_SPI_CR1_MSTR BIT(2) +-#define STM32F4_SPI_CR1_BR_SHIFT 3 + #define STM32F4_SPI_CR1_BR GENMASK(5, 3) ++#define STM32F4_SPI_CR1_BR_SHIFT 3 + #define STM32F4_SPI_CR1_SPE BIT(6) + #define STM32F4_SPI_CR1_LSBFRST BIT(7) + #define STM32F4_SPI_CR1_SSI BIT(8) +@@ -94,27 +96,24 @@ + #define STM32H7_SPI_CR1_SSI BIT(12) + + /* STM32H7_SPI_CR2 bit fields */ +-#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 + #define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) ++#define STM32H7_SPI_CR2_TSER GENMASK(31, 16) ++#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0) ++#define STM32H7_SPI_TSER_MAX (GENMASK(31, 16) >> 16) + + /* STM32H7_SPI_CFG1 bit fields */ +-#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 + #define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0) +-#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5 + #define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5) + #define STM32H7_SPI_CFG1_RXDMAEN BIT(14) + #define STM32H7_SPI_CFG1_TXDMAEN BIT(15) +-#define STM32H7_SPI_CFG1_MBR_SHIFT 28 + #define STM32H7_SPI_CFG1_MBR GENMASK(30, 28) ++#define STM32H7_SPI_CFG1_MBR_SHIFT 28 + #define STM32H7_SPI_CFG1_MBR_MIN 0 + #define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) + + /* STM32H7_SPI_CFG2 bit fields */ +-#define STM32H7_SPI_CFG2_MIDI_SHIFT 4 + #define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4) +-#define STM32H7_SPI_CFG2_COMM_SHIFT 17 + #define STM32H7_SPI_CFG2_COMM GENMASK(18, 17) +-#define STM32H7_SPI_CFG2_SP_SHIFT 19 + #define STM32H7_SPI_CFG2_SP GENMASK(21, 19) + #define STM32H7_SPI_CFG2_MASTER BIT(22) + #define STM32H7_SPI_CFG2_LSBFRST BIT(23) +@@ -131,16 +130,18 @@ + #define STM32H7_SPI_IER_TXTFIE BIT(4) + #define STM32H7_SPI_IER_OVRIE BIT(6) + #define STM32H7_SPI_IER_MODFIE BIT(9) ++#define STM32H7_SPI_IER_TSERFIE BIT(10) + #define STM32H7_SPI_IER_ALL GENMASK(10, 0) + + /* STM32H7_SPI_SR bit fields */ + #define STM32H7_SPI_SR_RXP BIT(0) + #define STM32H7_SPI_SR_TXP BIT(1) + #define STM32H7_SPI_SR_EOT BIT(3) ++#define STM32H7_SPI_SR_TXTF BIT(4) + #define STM32H7_SPI_SR_OVR BIT(6) + #define STM32H7_SPI_SR_MODF BIT(9) ++#define STM32H7_SPI_SR_TSERF BIT(10) + #define STM32H7_SPI_SR_SUSP BIT(11) +-#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 + #define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) + #define STM32H7_SPI_SR_RXWNE BIT(15) + +@@ -167,8 +168,6 @@ + #define SPI_3WIRE_TX 3 + #define SPI_3WIRE_RX 4 + +-#define SPI_1HZ_NS 1000000000 +- + /* + * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers + * without fifo buffers. +@@ -249,7 +248,7 @@ struct stm32_spi_cfg { + int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type); + void (*set_data_idleness)(struct stm32_spi *spi, u32 length); + int (*set_number_of_data)(struct stm32_spi *spi, u32 length); +- void (*transfer_one_dma_start)(struct stm32_spi *spi); ++ int (*transfer_one_dma_start)(struct stm32_spi *spi); + void (*dma_rx_cb)(void *data); + void (*dma_tx_cb)(void *data); + int (*transfer_one_irq)(struct stm32_spi *spi); +@@ -268,7 +267,6 @@ struct stm32_spi_cfg { + * @base: virtual memory area + * @clk: hw kernel clock feeding the SPI clock generator + * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator +- * @rst: SPI controller reset line + * @lock: prevent I/O concurrent access + * @irq: SPI controller interrupt line + * @fifo_size: size of the embedded fifo in bytes +@@ -278,6 +276,7 @@ struct stm32_spi_cfg { + * @cur_fthlv: fifo threshold level (data frames in a single data packet) + * @cur_comm: SPI communication mode + * @cur_xferlen: current transfer length in bytes ++ * @cur_reload: current transfer remaining bytes to be loaded + * @cur_usedma: boolean to know if dma is used in current transfer + * @tx_buf: data to be written, or NULL + * @rx_buf: data to be read, or NULL +@@ -294,7 +293,6 @@ struct stm32_spi { + void __iomem *base; + struct clk *clk; + u32 clk_rate; +- struct reset_control *rst; + spinlock_t lock; /* prevent I/O concurrent access */ + int irq; + unsigned int fifo_size; +@@ -305,6 +303,7 @@ struct stm32_spi { + unsigned int cur_fthlv; + unsigned int cur_comm; + unsigned int cur_xferlen; ++ unsigned int cur_reload; + bool cur_usedma; + + const void *tx_buf; +@@ -313,7 +312,10 @@ struct stm32_spi { + int rx_len; + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; ++ struct completion dma_completion; + dma_addr_t phys_addr; ++ struct completion xfer_completion; ++ int xfer_status; + }; + + static const struct stm32_spi_regspec stm32f4_spi_regspec = { +@@ -417,9 +419,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) + stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); + + cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); +- max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >> +- STM32H7_SPI_CFG1_DSIZE_SHIFT; +- max_bpw += 1; ++ max_bpw = FIELD_GET(STM32H7_SPI_CFG1_DSIZE, cfg1) + 1; + + spin_unlock_irqrestore(&spi->lock, flags); + +@@ -442,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, + { + u32 div, mbrdiv; + +- div = DIV_ROUND_UP(spi->clk_rate, speed_hz); ++ /* Ensure spi->clk_rate is even */ ++ div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz); + + /* + * SPI framework set xfer->speed_hz to master->max_speed_hz if +@@ -469,19 +470,22 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, + * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level + * @spi: pointer to the spi controller data structure + */ +-static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) ++static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len) + { +- u32 fthlv, half_fifo; ++ u32 fthlv, half_fifo, packet; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (spi->fifo_size / 2); + ++ /* data_packet should not exceed transfer length */ ++ packet = (half_fifo > xfer_len) ? xfer_len : half_fifo; ++ + if (spi->cur_bpw <= 8) +- fthlv = half_fifo; ++ fthlv = packet; + else if (spi->cur_bpw <= 16) +- fthlv = half_fifo / 2; ++ fthlv = packet / 2; + else +- fthlv = half_fifo / 4; ++ fthlv = packet / 4; + + /* align packet size with data registers access */ + if (spi->cur_bpw > 8) +@@ -489,9 +493,29 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) + else + fthlv -= (fthlv % 4); /* multiple of 4 */ + ++ if (!fthlv) ++ fthlv = 1; ++ + return fthlv; + } + ++static void stm32h7_spi_transfer_extension(struct stm32_spi *spi) ++{ ++ if (spi->cur_reload > 0) { ++ u32 cr2 = readl_relaxed(spi->base + STM32H7_SPI_CR2); ++ u32 tsize = FIELD_GET(STM32H7_SPI_CR2_TSIZE, cr2); ++ u32 tser = STM32H7_SPI_TSER_MAX; ++ ++ tser -= (STM32H7_SPI_TSER_MAX % spi->cur_fthlv); ++ tser = min(spi->cur_reload, tser); ++ ++ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSER, tser) | ++ FIELD_PREP(STM32H7_SPI_CR2_TSIZE, tsize), ++ spi->base + STM32H7_SPI_CR2); ++ spi->cur_reload -= tser; ++ } ++} ++ + /** + * stm32f4_spi_write_tx - Write bytes to Transmit Data Register + * @spi: pointer to the spi controller data structure +@@ -592,25 +616,26 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) + * Write in rx_buf depends on remaining bytes to avoid to write beyond + * rx_buf end. + */ +-static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) ++static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi) + { + u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); +- u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> +- STM32H7_SPI_SR_RXPLVL_SHIFT; ++ u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); + + while ((spi->rx_len > 0) && + ((sr & STM32H7_SPI_SR_RXP) || +- (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { ++ ((sr & STM32H7_SPI_SR_EOT) && ++ ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = spi->cur_xferlen - spi->rx_len; + + if ((spi->rx_len >= sizeof(u32)) || +- (flush && (sr & STM32H7_SPI_SR_RXWNE))) { ++ (sr & STM32H7_SPI_SR_RXWNE)) { + u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); + + *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); + spi->rx_len -= sizeof(u32); + } else if ((spi->rx_len >= sizeof(u16)) || +- (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { ++ (!(sr & STM32H7_SPI_SR_RXWNE) && ++ (rxplvl >= 2 || spi->cur_bpw > 8))) { + u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); + + *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); +@@ -623,12 +648,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) + } + + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); +- rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> +- STM32H7_SPI_SR_RXPLVL_SHIFT; ++ rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); + } + +- dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, +- flush ? "(flush)" : "", spi->rx_len); ++ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", ++ __func__, spi->rx_len, sr); + } + + /** +@@ -696,12 +720,7 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) + * @spi: pointer to the spi controller data structure + * + * RX-Fifo is flushed when SPI controller is disabled. To prevent any data +- * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in +- * RX-Fifo. +- * Normally, if TSIZE has been configured, we should relax the hardware at the +- * reception of the EOT interrupt. But in case of error, EOT will not be +- * raised. So the subsystem unprepare_message call allows us to properly +- * complete the transfer from an hardware point of view. ++ * loss, use stm32_spi_read_rxfifo to read the remaining bytes in RX-Fifo. + */ + static void stm32h7_spi_disable(struct stm32_spi *spi) + { +@@ -736,7 +755,7 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) + } + + if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) +- stm32h7_spi_read_rxfifo(spi, true); ++ stm32h7_spi_read_rxfifo(spi); + + if (spi->cur_usedma && spi->dma_tx) + dmaengine_terminate_all(spi->dma_tx); +@@ -891,7 +910,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + { + struct spi_master *master = dev_id; + struct stm32_spi *spi = spi_master_get_devdata(master); +- u32 sr, ier, mask; ++ u32 sr, ier, mask, ifcr; + unsigned long flags; + bool end = false; + +@@ -899,77 +918,82 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); + ier = readl_relaxed(spi->base + STM32H7_SPI_IER); ++ ifcr = 0; + + mask = ier; +- /* EOTIE is triggered on EOT, SUSP and TXC events. */ ++ /* ++ * EOTIE enables irq from EOT, SUSP and TXC events. We need to set ++ * SUSP to acknowledge it later. TXC is automatically cleared ++ */ + mask |= STM32H7_SPI_SR_SUSP; + /* +- * When TXTF is set, DXPIE and TXPIE are cleared. So in case of +- * Full-Duplex, need to poll RXP event to know if there are remaining +- * data, before disabling SPI. ++ * DXPIE is set in Full-Duplex, one IT will be raised if TXP and RXP ++ * are set. So in case of Full-Duplex, need to poll TXP and RXP event. + */ +- if (spi->rx_buf && !spi->cur_usedma) +- mask |= STM32H7_SPI_SR_RXP; ++ if ((spi->cur_comm == SPI_FULL_DUPLEX) && (!spi->cur_usedma)) ++ mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP; + +- if (!(sr & mask)) { +- dev_dbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", +- sr, ier); ++ mask &= sr; ++ ++ if (!mask) { ++ dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", ++ sr, ier); + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_NONE; + } + +- if (sr & STM32H7_SPI_SR_SUSP) { +- dev_warn(spi->dev, "Communication suspended\n"); ++ if (mask & STM32H7_SPI_SR_TSERF) { ++ stm32h7_spi_transfer_extension(spi); ++ ifcr |= STM32H7_SPI_SR_TSERF; ++ } ++ ++ if (mask & STM32H7_SPI_SR_SUSP) { ++ dev_warn_once(spi->dev, ++ "System too slow is limiting data throughput\n"); ++ + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, false); +- /* +- * If communication is suspended while using DMA, it means +- * that something went wrong, so stop the current transfer +- */ +- if (spi->cur_usedma) +- end = true; ++ stm32h7_spi_read_rxfifo(spi); ++ ++ ifcr |= STM32H7_SPI_SR_SUSP; + } + +- if (sr & STM32H7_SPI_SR_MODF) { +- dev_warn(spi->dev, "Mode fault: transfer aborted\n"); ++ if (mask & STM32H7_SPI_SR_OVR) { ++ dev_err(spi->dev, "Overrun: RX data lost\n"); ++ spi->xfer_status = -EIO; + end = true; ++ ifcr |= STM32H7_SPI_SR_OVR; + } + +- if (sr & STM32H7_SPI_SR_OVR) { +- dev_warn(spi->dev, "Overrun: received value discarded\n"); +- if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, false); +- /* +- * If overrun is detected while using DMA, it means that +- * something went wrong, so stop the current transfer +- */ +- if (spi->cur_usedma) +- end = true; +- } ++ if (mask & STM32H7_SPI_SR_TXTF) ++ ifcr |= STM32H7_SPI_SR_TXTF; + +- if (sr & STM32H7_SPI_SR_EOT) { ++ if (mask & STM32H7_SPI_SR_EOT) { + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, true); ++ stm32h7_spi_read_rxfifo(spi); + end = true; ++ ifcr |= STM32H7_SPI_SR_EOT; + } + +- if (sr & STM32H7_SPI_SR_TXP) ++ if (mask & STM32H7_SPI_SR_TXP) + if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) + stm32h7_spi_write_txfifo(spi); + +- if (sr & STM32H7_SPI_SR_RXP) ++ if (mask & STM32H7_SPI_SR_RXP) + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, false); +- +- writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR); +- +- spin_unlock_irqrestore(&spi->lock, flags); ++ stm32h7_spi_read_rxfifo(spi); + + if (end) { +- spi_finalize_current_transfer(master); +- stm32h7_spi_disable(spi); ++ /* Disable interrupts and clear status flags */ ++ writel_relaxed(0, spi->base + STM32H7_SPI_IER); ++ writel_relaxed(STM32H7_SPI_IFCR_ALL, ++ spi->base + STM32H7_SPI_IFCR); ++ ++ complete(&spi->xfer_completion); ++ } else { ++ writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR); + } + ++ spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_HANDLED; + } + +@@ -1079,25 +1103,18 @@ static void stm32f4_spi_dma_rx_cb(void *data) + /** + * stm32h7_spi_dma_cb - dma callback + * +- * DMA callback is called when the transfer is complete or when an error +- * occurs. If the transfer is complete, EOT flag is raised. ++ * DMA callback is called when the transfer is complete. + */ + static void stm32h7_spi_dma_cb(void *data) + { + struct stm32_spi *spi = data; + unsigned long flags; +- u32 sr; + + spin_lock_irqsave(&spi->lock, flags); + +- sr = readl_relaxed(spi->base + STM32H7_SPI_SR); ++ complete(&spi->dma_completion); + + spin_unlock_irqrestore(&spi->lock, flags); +- +- if (!(sr & STM32H7_SPI_SR_EOT)) +- dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); +- +- /* Now wait for EOT, or SUSP or OVR in case of error */ + } + + /** +@@ -1190,9 +1207,6 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) + /** + * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using + * interrupts +- * +- * It must returns 0 if the transfer is finished or 1 if the transfer is still +- * in progress. + */ + static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) + { +@@ -1209,7 +1223,9 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) + + /* Enable the interrupts relative to the end of transfer */ + ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | +- STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; ++ STM32H7_SPI_IER_OVRIE; ++ /* Enable the interrupt relative to transfer extension */ ++ ier |= STM32H7_SPI_IER_TSERFIE; + + spin_lock_irqsave(&spi->lock, flags); + +@@ -1225,15 +1241,19 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) + + spin_unlock_irqrestore(&spi->lock, flags); + +- return 1; ++ return 0; + } + + /** + * stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start + * transfer using DMA + */ +-static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) ++static int stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&spi->lock, flags); ++ + /* In DMA mode end of transfer is handled by DMA TX or RX callback. */ + if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX || + spi->cur_comm == SPI_FULL_DUPLEX) { +@@ -1246,40 +1266,58 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) + } + + stm32_spi_enable(spi); ++ ++ spin_unlock_irqrestore(&spi->lock, flags); ++ ++ return 1; + } + + /** + * stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start + * transfer using DMA + */ +-static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) ++static int stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&spi->lock, flags); ++ + /* Enable the interrupts relative to the end of transfer */ + stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | + STM32H7_SPI_IER_TXTFIE | + STM32H7_SPI_IER_OVRIE | +- STM32H7_SPI_IER_MODFIE); ++ /* transfer extension */ ++ STM32H7_SPI_IER_TSERFIE); + + stm32_spi_enable(spi); + + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); ++ ++ spin_unlock_irqrestore(&spi->lock, flags); ++ ++ return 0; + } + + /** + * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA +- * +- * It must returns 0 if the transfer is finished or 1 if the transfer is still +- * in progress. + */ + static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, + struct spi_transfer *xfer) + { ++ dma_async_tx_callback rx_done = NULL, tx_done = NULL; + struct dma_slave_config tx_dma_conf, rx_dma_conf; + struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc; + unsigned long flags; + + spin_lock_irqsave(&spi->lock, flags); + ++ if (spi->rx_buf) ++ rx_done = spi->cfg->dma_rx_cb; ++ else if (spi->tx_buf) ++ tx_done = spi->cfg->dma_tx_cb; ++ ++ reinit_completion(&spi->dma_completion); ++ + rx_dma_desc = NULL; + if (spi->rx_buf && spi->dma_rx) { + stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); +@@ -1316,7 +1354,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, + goto dma_desc_error; + + if (rx_dma_desc) { +- rx_dma_desc->callback = spi->cfg->dma_rx_cb; ++ rx_dma_desc->callback = rx_done; + rx_dma_desc->callback_param = spi; + + if (dma_submit_error(dmaengine_submit(rx_dma_desc))) { +@@ -1330,7 +1368,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, + if (tx_dma_desc) { + if (spi->cur_comm == SPI_SIMPLEX_TX || + spi->cur_comm == SPI_3WIRE_TX) { +- tx_dma_desc->callback = spi->cfg->dma_tx_cb; ++ tx_dma_desc->callback = tx_done; + tx_dma_desc->callback_param = spi; + } + +@@ -1345,12 +1383,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, + stm32_spi_set_bits(spi, spi->cfg->regs->dma_tx_en.reg, + spi->cfg->regs->dma_tx_en.mask); + } +- +- spi->cfg->transfer_one_dma_start(spi); +- + spin_unlock_irqrestore(&spi->lock, flags); + +- return 1; ++ return spi->cfg->transfer_one_dma_start(spi); + + dma_submit_error: + if (spi->dma_rx) +@@ -1392,15 +1427,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) + bpw = spi->cur_bpw - 1; + + cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; +- cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & +- STM32H7_SPI_CFG1_DSIZE; ++ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_DSIZE, bpw); + +- spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi); ++ spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen); + fthlv = spi->cur_fthlv - 1; + + cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; +- cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & +- STM32H7_SPI_CFG1_FTHLV; ++ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_FTHLV, fthlv); + + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & +@@ -1418,8 +1451,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) + u32 clrb = 0, setb = 0; + + clrb |= spi->cfg->regs->br.mask; +- setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) & +- spi->cfg->regs->br.mask; ++ setb |= (mbrdiv << spi->cfg->regs->br.shift) & spi->cfg->regs->br.mask; + + writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & + ~clrb) | setb, +@@ -1504,8 +1536,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) + } + + cfg2_clrb |= STM32H7_SPI_CFG2_COMM; +- cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & +- STM32H7_SPI_CFG2_COMM; ++ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_COMM, mode); + + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & +@@ -1527,15 +1558,15 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) + + cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; + if ((len > 1) && (spi->cur_midi > 0)) { +- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); +- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), +- (u32)STM32H7_SPI_CFG2_MIDI >> +- STM32H7_SPI_CFG2_MIDI_SHIFT); ++ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed); ++ u32 midi = min_t(u32, ++ DIV_ROUND_UP(spi->cur_midi, sck_period_ns), ++ FIELD_GET(STM32H7_SPI_CFG2_MIDI, ++ STM32H7_SPI_CFG2_MIDI)); + + dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", + sck_period_ns, midi, midi * sck_period_ns); +- cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & +- STM32H7_SPI_CFG2_MIDI; ++ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_MIDI, midi); + } + + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & +@@ -1550,19 +1581,23 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) + */ + static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) + { +- u32 cr2_clrb = 0, cr2_setb = 0; +- +- if (nb_words <= (STM32H7_SPI_CR2_TSIZE >> +- STM32H7_SPI_CR2_TSIZE_SHIFT)) { +- cr2_clrb |= STM32H7_SPI_CR2_TSIZE; +- cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; +- writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & +- ~cr2_clrb) | cr2_setb, +- spi->base + STM32H7_SPI_CR2); ++ u32 tsize; ++ ++ if (nb_words <= STM32H7_SPI_TSIZE_MAX) { ++ tsize = nb_words; ++ spi->cur_reload = 0; + } else { +- return -EMSGSIZE; ++ tsize = STM32H7_SPI_TSIZE_MAX; ++ tsize -= (STM32H7_SPI_TSIZE_MAX % spi->cur_fthlv); ++ spi->cur_reload = nb_words - tsize; + } + ++ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, tsize), ++ spi->base + STM32H7_SPI_CR2); ++ ++ if (spi->cur_reload > 0) ++ stm32h7_spi_transfer_extension(spi); ++ + return 0; + } + +@@ -1578,39 +1613,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, + unsigned long flags; + unsigned int comm_type; + int nb_words, ret = 0; ++ int mbr; + + spin_lock_irqsave(&spi->lock, flags); + +- if (spi->cur_bpw != transfer->bits_per_word) { +- spi->cur_bpw = transfer->bits_per_word; +- spi->cfg->set_bpw(spi); +- } +- +- if (spi->cur_speed != transfer->speed_hz) { +- int mbr; ++ spi->cur_xferlen = transfer->len; + +- /* Update spi->cur_speed with real clock speed */ +- mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, +- spi->cfg->baud_rate_div_min, +- spi->cfg->baud_rate_div_max); +- if (mbr < 0) { +- ret = mbr; +- goto out; +- } ++ spi->cur_bpw = transfer->bits_per_word; ++ spi->cfg->set_bpw(spi); + +- transfer->speed_hz = spi->cur_speed; +- stm32_spi_set_mbr(spi, mbr); ++ /* Update spi->cur_speed with real clock speed */ ++ mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, ++ spi->cfg->baud_rate_div_min, ++ spi->cfg->baud_rate_div_max); ++ if (mbr < 0) { ++ ret = mbr; ++ goto out; + } + +- comm_type = stm32_spi_communication_type(spi_dev, transfer); +- if (spi->cur_comm != comm_type) { +- ret = spi->cfg->set_mode(spi, comm_type); ++ transfer->speed_hz = spi->cur_speed; ++ stm32_spi_set_mbr(spi, mbr); + +- if (ret < 0) +- goto out; ++ comm_type = stm32_spi_communication_type(spi_dev, transfer); ++ ret = spi->cfg->set_mode(spi, comm_type); ++ if (ret < 0) ++ goto out; + +- spi->cur_comm = comm_type; +- } ++ spi->cur_comm = comm_type; + + if (spi->cfg->set_data_idleness) + spi->cfg->set_data_idleness(spi, transfer->len); +@@ -1628,8 +1657,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, + goto out; + } + +- spi->cur_xferlen = transfer->len; +- + dev_dbg(spi->dev, "transfer communication mode set to %d\n", + spi->cur_comm); + dev_dbg(spi->dev, +@@ -1658,6 +1685,8 @@ static int stm32_spi_transfer_one(struct spi_master *master, + struct spi_transfer *transfer) + { + struct stm32_spi *spi = spi_master_get_devdata(master); ++ u32 xfer_time, midi_delay_ns; ++ unsigned long timeout; + int ret; + + spi->tx_buf = transfer->tx_buf; +@@ -1674,10 +1703,39 @@ static int stm32_spi_transfer_one(struct spi_master *master, + return ret; + } + ++ reinit_completion(&spi->xfer_completion); ++ spi->xfer_status = 0; ++ + if (spi->cur_usedma) +- return stm32_spi_transfer_one_dma(spi, transfer); ++ ret = stm32_spi_transfer_one_dma(spi, transfer); + else +- return spi->cfg->transfer_one_irq(spi); ++ ret = spi->cfg->transfer_one_irq(spi); ++ ++ if (ret) ++ return ret; ++ ++ /* Wait for transfer to complete */ ++ xfer_time = spi->cur_xferlen * 8 * MSEC_PER_SEC / spi->cur_speed; ++ midi_delay_ns = spi->cur_xferlen * 8 / spi->cur_bpw * spi->cur_midi; ++ xfer_time += DIV_ROUND_UP(midi_delay_ns, NSEC_PER_MSEC); ++ xfer_time = max(2 * xfer_time, 100U); ++ timeout = msecs_to_jiffies(xfer_time); ++ ++ timeout = wait_for_completion_timeout(&spi->xfer_completion, timeout); ++ if (timeout && spi->cur_usedma) ++ timeout = wait_for_completion_timeout(&spi->dma_completion, ++ timeout); ++ ++ if (!timeout) { ++ dev_err(spi->dev, "SPI transfer timeout (%u ms)\n", xfer_time); ++ spi->xfer_status = -ETIMEDOUT; ++ } ++ ++ spi->cfg->disable(spi); ++ ++ spi_finalize_current_transfer(master); ++ ++ return spi->xfer_status; + } + + /** +@@ -1810,7 +1868,8 @@ static int stm32_spi_probe(struct platform_device *pdev) + struct spi_master *master; + struct stm32_spi *spi; + struct resource *res; +- int i, ret; ++ struct reset_control *rst; ++ int i, ret, num_cs, cs_gpio; + + master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); + if (!master) { +@@ -1823,6 +1882,8 @@ static int stm32_spi_probe(struct platform_device *pdev) + spi->dev = &pdev->dev; + spi->master = master; + spin_lock_init(&spi->lock); ++ init_completion(&spi->xfer_completion); ++ init_completion(&spi->dma_completion); + + spi->cfg = (const struct stm32_spi_cfg *) + of_match_device(pdev->dev.driver->of_match_table, +@@ -1873,11 +1934,20 @@ static int stm32_spi_probe(struct platform_device *pdev) + goto err_clk_disable; + } + +- spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (!IS_ERR(spi->rst)) { +- reset_control_assert(spi->rst); ++ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (rst) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "reset get failed: %d\n", ++ ret); ++ ++ goto err_clk_disable; ++ } ++ ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(spi->rst); ++ reset_control_deassert(rst); + } + + if (spi->cfg->has_fifo) +@@ -1903,17 +1973,29 @@ static int stm32_spi_probe(struct platform_device *pdev) + master->transfer_one = stm32_spi_transfer_one; + master->unprepare_message = stm32_spi_unprepare_msg; + +- spi->dma_tx = dma_request_slave_channel(spi->dev, "tx"); +- if (!spi->dma_tx) +- dev_warn(&pdev->dev, "failed to request tx dma channel\n"); +- else +- master->dma_tx = spi->dma_tx; ++ spi->dma_tx = dma_request_chan(spi->dev, "tx"); ++ if (IS_ERR(spi->dma_tx)) { ++ ret = PTR_ERR(spi->dma_tx); ++ spi->dma_tx = NULL; ++ if (ret == -EPROBE_DEFER) ++ goto err_dma_release; ++ else if (ret != -ENODEV) ++ dev_warn(&pdev->dev, "failed to request tx dma: %d\n", ++ ret); ++ } ++ master->dma_tx = spi->dma_tx; + +- spi->dma_rx = dma_request_slave_channel(spi->dev, "rx"); +- if (!spi->dma_rx) +- dev_warn(&pdev->dev, "failed to request rx dma channel\n"); +- else +- master->dma_rx = spi->dma_rx; ++ spi->dma_rx = dma_request_chan(spi->dev, "rx"); ++ if (IS_ERR(spi->dma_rx)) { ++ ret = PTR_ERR(spi->dma_rx); ++ spi->dma_rx = NULL; ++ if (ret == -EPROBE_DEFER) ++ goto err_dma_release; ++ else if (ret != -ENODEV) ++ dev_warn(&pdev->dev, "failed to request rx dma: %d\n", ++ ret); ++ } ++ master->dma_rx = spi->dma_rx; + + if (spi->dma_tx || spi->dma_rx) + master->can_dma = stm32_spi_can_dma; +@@ -1921,36 +2003,33 @@ static int stm32_spi_probe(struct platform_device *pdev) + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- ret = devm_spi_register_master(&pdev->dev, master); +- if (ret) { +- dev_err(&pdev->dev, "spi master registration failed: %d\n", +- ret); +- goto err_dma_release; +- } +- +- if (!master->cs_gpios) { +- dev_err(&pdev->dev, "no CS gpios available\n"); +- ret = -EINVAL; +- goto err_dma_release; +- } ++ num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios"); + +- for (i = 0; i < master->num_chipselect; i++) { +- if (!gpio_is_valid(master->cs_gpios[i])) { +- dev_err(&pdev->dev, "%i is not a valid gpio\n", +- master->cs_gpios[i]); +- ret = -EINVAL; ++ for (i = 0; i < num_cs; i++) { ++ cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i); ++ if (cs_gpio == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; + goto err_dma_release; + } + +- ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], +- DRIVER_NAME); +- if (ret) { +- dev_err(&pdev->dev, "can't get CS gpio %i\n", +- master->cs_gpios[i]); +- goto err_dma_release; ++ if (gpio_is_valid(cs_gpio)) { ++ ret = devm_gpio_request(&pdev->dev, cs_gpio, ++ DRIVER_NAME); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get CS gpio %i\n", ++ cs_gpio); ++ goto err_dma_release; ++ } + } + } + ++ ret = spi_register_master(master); ++ if (ret) { ++ dev_err(&pdev->dev, "spi master registration failed: %d\n", ++ ret); ++ goto err_dma_release; ++ } ++ + dev_info(&pdev->dev, "driver initialized\n"); + + return 0; +@@ -1975,6 +2054,9 @@ static int stm32_spi_remove(struct platform_device *pdev) + struct spi_master *master = platform_get_drvdata(pdev); + struct stm32_spi *spi = spi_master_get_devdata(master); + ++ pm_runtime_get_sync(&pdev->dev); ++ ++ spi_unregister_master(master); + spi->cfg->disable(spi); + + if (master->dma_tx) +@@ -1984,7 +2066,12 @@ static int stm32_spi_remove(struct platform_device *pdev) + + clk_disable_unprepare(spi->clk); + ++ pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); ++ ++ pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; + } +@@ -1997,13 +2084,18 @@ static int stm32_spi_runtime_suspend(struct device *dev) + + clk_disable_unprepare(spi->clk); + +- return 0; ++ return pinctrl_pm_select_sleep_state(dev); + } + + static int stm32_spi_runtime_resume(struct device *dev) + { + struct spi_master *master = dev_get_drvdata(dev); + struct stm32_spi *spi = spi_master_get_devdata(master); ++ int ret; ++ ++ ret = pinctrl_pm_select_default_state(dev); ++ if (ret) ++ return ret; + + return clk_prepare_enable(spi->clk); + } +@@ -2033,10 +2125,23 @@ static int stm32_spi_resume(struct device *dev) + return ret; + + ret = spi_master_resume(master); +- if (ret) ++ if (ret) { + clk_disable_unprepare(spi->clk); ++ return ret; ++ } + +- return ret; ++ ret = pm_runtime_get_sync(dev); ++ if (ret) { ++ dev_err(dev, "Unable to power device:%d\n", ret); ++ return ret; ++ } ++ ++ spi->cfg->config(spi); ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; + } + #endif + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch new file mode 100644 index 0000000..a74bad6 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch @@ -0,0 +1,679 @@ +From 9ce7cf9f5ce6b3fe1370be07d989eabaf0afb25a Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:47:45 +0200 +Subject: [PATCH 18/23] ARM-stm32mp1-r1-SOUND + +--- + sound/soc/codecs/Kconfig | 2 +- + sound/soc/codecs/cs42l51.c | 17 ++++-- + sound/soc/codecs/wm8994.c | 80 +++++++++++++++++++++++-- + sound/soc/stm/stm32_i2s.c | 75 +++++++++++++++++------- + sound/soc/stm/stm32_sai.c | 26 ++++++--- + sound/soc/stm/stm32_sai_sub.c | 21 ++++--- + sound/soc/stm/stm32_spdifrx.c | 107 +++++++++++++++++++++------------- + 7 files changed, 241 insertions(+), 87 deletions(-) + +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 229cc89f8..e5d231a63 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -1395,7 +1395,7 @@ config SND_SOC_WM8993 + tristate + + config SND_SOC_WM8994 +- tristate ++ tristate "Wolfson Microelectronics WM8994 codec" + + config SND_SOC_WM8995 + tristate +diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c +index 55408c8fc..01a4d93e1 100644 +--- a/sound/soc/codecs/cs42l51.c ++++ b/sound/soc/codecs/cs42l51.c +@@ -174,6 +174,7 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, CS42L51_POWER_CTL1, + CS42L51_POWER_CTL1_PDN, 0); ++ msleep(20); + break; + } + +@@ -214,12 +215,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { + SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture", + CS42L51_POWER_CTL1, 2, 1, + cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), +- SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback", +- CS42L51_POWER_CTL1, 5, 1, +- cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), +- SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback", +- CS42L51_POWER_CTL1, 6, 1, +- cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), ++ SND_SOC_DAPM_DAC_E("Left DAC", NULL, CS42L51_POWER_CTL1, 5, 1, ++ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), ++ SND_SOC_DAPM_DAC_E("Right DAC", NULL, CS42L51_POWER_CTL1, 6, 1, ++ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), + + /* analog/mic */ + SND_SOC_DAPM_INPUT("AIN1L"), +@@ -255,6 +254,12 @@ static const struct snd_soc_dapm_route cs42l51_routes[] = { + {"HPL", NULL, "Left DAC"}, + {"HPR", NULL, "Right DAC"}, + ++ {"Right DAC", NULL, "DAC Mux"}, ++ {"Left DAC", NULL, "DAC Mux"}, ++ ++ {"DAC Mux", "Direct PCM", "Playback"}, ++ {"DAC Mux", "DSP PCM", "Playback"}, ++ + {"Left ADC", NULL, "Left PGA"}, + {"Right ADC", NULL, "Right PGA"}, + +diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c +index d5fb7f5dd..a166ab1f3 100644 +--- a/sound/soc/codecs/wm8994.c ++++ b/sound/soc/codecs/wm8994.c +@@ -7,6 +7,7 @@ + * Author: Mark Brown + */ + ++#include + #include + #include + #include +@@ -840,6 +841,42 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, + return 0; + } + ++static int mclk_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); ++ struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(comp); ++ struct wm8994 *control = wm8994->wm8994; ++ struct wm8994_pdata *pdata = &control->pdata; ++ struct clk *mclk = pdata->mclk1; ++ int ret, mclk_id = 0; ++ ++ if (!strncmp(w->name, "MCLK2", 5)) { ++ mclk_id = 1; ++ mclk = pdata->mclk2; ++ } ++ ++ switch (event) { ++ case SND_SOC_DAPM_PRE_PMU: ++ dev_dbg(comp->dev, "Enable master clock %s\n", ++ mclk_id ? "MCLK2" : "MCLK1"); ++ ++ ret = clk_prepare_enable(mclk); ++ if (ret < 0) { ++ dev_err(comp->dev, "Failed to enable clock: %d\n", ret); ++ return ret; ++ } ++ break; ++ case SND_SOC_DAPM_POST_PMD: ++ dev_dbg(comp->dev, "Disable master clock %s\n", ++ mclk_id ? "MCLK2" : "MCLK1"); ++ clk_disable_unprepare(mclk); ++ break; ++ } ++ ++ return 0; ++} ++ + static void vmid_reference(struct snd_soc_component *component) + { + struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); +@@ -1157,7 +1194,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, + else + adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA; + +- + val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_2); + if ((val & WM8994_AIF2DACL_SRC) && + (val & WM8994_AIF2DACR_SRC)) +@@ -1776,6 +1812,16 @@ static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = { + SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux), + }; + ++static const struct snd_soc_dapm_widget wm8994_mclk1_dapm_widgets[] = { ++SND_SOC_DAPM_SUPPLY("MCLK1", SND_SOC_NOPM, 0, 0, mclk_event, ++ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), ++}; ++ ++static const struct snd_soc_dapm_widget wm8994_mclk2_dapm_widgets[] = { ++SND_SOC_DAPM_SUPPLY("MCLK2", SND_SOC_NOPM, 0, 0, mclk_event, ++ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), ++}; ++ + static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0), + SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux), +@@ -2000,10 +2046,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { + }; + + static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { +- { "AIF1DACDAT", NULL, "AIF2DACDAT" }, +- { "AIF2DACDAT", NULL, "AIF1DACDAT" }, +- { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, +- { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, ++// { "AIF1DACDAT", NULL, "AIF2DACDAT" }, ++// { "AIF2DACDAT", NULL, "AIF1DACDAT" }, ++// { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, ++// { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, + { "MICBIAS1", NULL, "CLK_SYS" }, + { "MICBIAS1", NULL, "MICBIAS Supply" }, + { "MICBIAS2", NULL, "CLK_SYS" }, +@@ -2377,11 +2423,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, + { + struct snd_soc_component *component = dai->component; + struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); ++ struct wm8994 *control = wm8994->wm8994; ++ struct wm8994_pdata *pdata = &control->pdata; + int i; + ++ /* ++ * Simple card provides unconditionnaly clock_id = 0. ++ * Workaround to select master clock for aif1/2 ++ */ + switch (dai->id) { + case 1: ++ if (pdata->mclk1) ++ clk_id = WM8994_SYSCLK_MCLK1; ++ else if (pdata->mclk2) ++ clk_id = WM8994_SYSCLK_MCLK2; ++ break; + case 2: ++ if (pdata->mclk2) ++ clk_id = WM8994_SYSCLK_MCLK2; ++ else if (pdata->mclk1) ++ clk_id = WM8994_SYSCLK_MCLK1; + break; + + default: +@@ -3991,6 +4052,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) + { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct wm8994 *control = dev_get_drvdata(component->dev->parent); ++ struct wm8994_pdata *pdata = &control->pdata; + struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); + unsigned int reg; + int ret, i; +@@ -4274,6 +4336,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) + ARRAY_SIZE(wm8994_snd_controls)); + snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, + ARRAY_SIZE(wm8994_specific_dapm_widgets)); ++ if (pdata->mclk1) ++ snd_soc_dapm_new_controls(dapm, wm8994_mclk1_dapm_widgets, ++ ARRAY_SIZE(wm8994_mclk1_dapm_widgets)); ++ ++ if (pdata->mclk2) ++ snd_soc_dapm_new_controls(dapm, wm8994_mclk2_dapm_widgets, ++ ARRAY_SIZE(wm8994_mclk2_dapm_widgets)); ++ + if (control->revision < 4) { + snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, + ARRAY_SIZE(wm8994_lateclk_revd_widgets)); +diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c +index 3e7226a53..7c4d63c33 100644 +--- a/sound/soc/stm/stm32_i2s.c ++++ b/sound/soc/stm/stm32_i2s.c +@@ -831,25 +831,33 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, + /* Get clocks */ + i2s->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(i2s->pclk)) { +- dev_err(&pdev->dev, "Could not get pclk\n"); ++ if (PTR_ERR(i2s->pclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get pclk: %ld\n", ++ PTR_ERR(i2s->pclk)); + return PTR_ERR(i2s->pclk); + } + + i2s->i2sclk = devm_clk_get(&pdev->dev, "i2sclk"); + if (IS_ERR(i2s->i2sclk)) { +- dev_err(&pdev->dev, "Could not get i2sclk\n"); ++ if (PTR_ERR(i2s->i2sclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get i2sclk: %ld\n", ++ PTR_ERR(i2s->i2sclk)); + return PTR_ERR(i2s->i2sclk); + } + + i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); + if (IS_ERR(i2s->x8kclk)) { +- dev_err(&pdev->dev, "missing x8k parent clock\n"); ++ if (PTR_ERR(i2s->x8kclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get x8k parent clock: %ld\n", ++ PTR_ERR(i2s->x8kclk)); + return PTR_ERR(i2s->x8kclk); + } + + i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); + if (IS_ERR(i2s->x11kclk)) { +- dev_err(&pdev->dev, "missing x11k parent clock\n"); ++ if (PTR_ERR(i2s->x11kclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get x11k parent clock: %ld\n", ++ PTR_ERR(i2s->x11kclk)); + return PTR_ERR(i2s->x11kclk); + } + +@@ -866,12 +874,24 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, + } + + /* Reset */ +- rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (!IS_ERR(rst)) { +- reset_control_assert(rst); +- udelay(2); +- reset_control_deassert(rst); ++ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ if (PTR_ERR(rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Reset controller error %ld\n", ++ PTR_ERR(rst)); ++ return PTR_ERR(rst); + } ++ reset_control_assert(rst); ++ udelay(2); ++ reset_control_deassert(rst); ++ ++ return 0; ++} ++ ++static int stm32_i2s_remove(struct platform_device *pdev) ++{ ++ snd_dmaengine_pcm_unregister(&pdev->dev); ++ snd_soc_unregister_component(&pdev->dev); + + return 0; + } +@@ -903,48 +923,62 @@ static int stm32_i2s_probe(struct platform_device *pdev) + i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", + i2s->base, i2s->regmap_conf); + if (IS_ERR(i2s->regmap)) { +- dev_err(&pdev->dev, "regmap init failed\n"); ++ if (PTR_ERR(i2s->regmap) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Regmap init error %ld\n", ++ PTR_ERR(i2s->regmap)); + return PTR_ERR(i2s->regmap); + } + +- ret = devm_snd_soc_register_component(&pdev->dev, &stm32_i2s_component, +- i2s->dai_drv, 1); +- if (ret) ++ ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); + return ret; ++ } + +- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, +- &stm32_i2s_pcm_config, 0); +- if (ret) ++ ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component, ++ i2s->dai_drv, 1); ++ if (ret) { ++ snd_dmaengine_pcm_unregister(&pdev->dev); + return ret; ++ } + + /* Set SPI/I2S in i2s mode */ + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); + if (ret) +- return ret; ++ goto error; + + ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, &val); + if (ret) +- return ret; ++ goto error; + + if (val == I2S_IPIDR_NUMBER) { + ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, &val); + if (ret) +- return ret; ++ goto error; + + if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) { + dev_err(&pdev->dev, + "Device does not support i2s mode\n"); +- return -EPERM; ++ ret = -EPERM; ++ goto error; + } + + ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, &val); ++ if (ret) ++ goto error; + + dev_dbg(&pdev->dev, "I2S version: %lu.%lu registered\n", + FIELD_GET(I2S_VERR_MAJ_MASK, val), + FIELD_GET(I2S_VERR_MIN_MASK, val)); + } + ++ return ret; ++ ++error: ++ stm32_i2s_remove(pdev); ++ + return ret; + } + +@@ -981,6 +1015,7 @@ static struct platform_driver stm32_i2s_driver = { + .pm = &stm32_i2s_pm_ops, + }, + .probe = stm32_i2s_probe, ++ .remove = stm32_i2s_remove, + }; + + module_platform_driver(stm32_i2s_driver); +diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c +index ef4273361..820ae27e7 100644 +--- a/sound/soc/stm/stm32_sai.c ++++ b/sound/soc/stm/stm32_sai.c +@@ -174,20 +174,26 @@ static int stm32_sai_probe(struct platform_device *pdev) + if (!STM_SAI_IS_F4(sai)) { + sai->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(sai->pclk)) { +- dev_err(&pdev->dev, "missing bus clock pclk\n"); ++ if (PTR_ERR(sai->pclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "missing bus clock pclk: %ld\n", ++ PTR_ERR(sai->pclk)); + return PTR_ERR(sai->pclk); + } + } + + sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); + if (IS_ERR(sai->clk_x8k)) { +- dev_err(&pdev->dev, "missing x8k parent clock\n"); ++ if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "missing x8k parent clock: %ld\n", ++ PTR_ERR(sai->clk_x8k)); + return PTR_ERR(sai->clk_x8k); + } + + sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); + if (IS_ERR(sai->clk_x11k)) { +- dev_err(&pdev->dev, "missing x11k parent clock\n"); ++ if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "missing x11k parent clock: %ld\n", ++ PTR_ERR(sai->clk_x11k)); + return PTR_ERR(sai->clk_x11k); + } + +@@ -197,12 +203,16 @@ static int stm32_sai_probe(struct platform_device *pdev) + return sai->irq; + + /* reset */ +- rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (!IS_ERR(rst)) { +- reset_control_assert(rst); +- udelay(2); +- reset_control_deassert(rst); ++ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ if (PTR_ERR(rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Reset controller error %ld\n", ++ PTR_ERR(rst)); ++ return PTR_ERR(rst); + } ++ reset_control_assert(rst); ++ udelay(2); ++ reset_control_deassert(rst); + + /* Enable peripheral clock to allow register access */ + ret = clk_prepare_enable(sai->pclk); +diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c +index 10eb4b8e8..be25715b4 100644 +--- a/sound/soc/stm/stm32_sai_sub.c ++++ b/sound/soc/stm/stm32_sai_sub.c +@@ -1380,7 +1380,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, + sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, + sai->regmap_config); + if (IS_ERR(sai->regmap)) { +- dev_err(&pdev->dev, "Failed to initialize MMIO\n"); ++ if (PTR_ERR(sai->regmap) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Regmap init error %ld\n", ++ PTR_ERR(sai->regmap)); + return PTR_ERR(sai->regmap); + } + +@@ -1471,7 +1473,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, + of_node_put(args.np); + sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); + if (IS_ERR(sai->sai_ck)) { +- dev_err(&pdev->dev, "Missing kernel clock sai_ck\n"); ++ if (PTR_ERR(sai->sai_ck) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Missing kernel clock sai_ck: %ld\n", ++ PTR_ERR(sai->sai_ck)); + return PTR_ERR(sai->sai_ck); + } + +@@ -1543,21 +1547,22 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) + return ret; + } + ++ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) ++ conf = &stm32_sai_pcm_config_spdif; ++ + ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); + if (ret) { +- dev_err(&pdev->dev, "Could not register pcm dma\n"); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); + return ret; + } + + ret = snd_soc_register_component(&pdev->dev, &stm32_component, + &sai->cpu_dai_drv, 1); + if (ret) +- return ret; ++ snd_dmaengine_pcm_unregister(&pdev->dev); + +- if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) +- conf = &stm32_sai_pcm_config_spdif; +- +- return 0; ++ return ret; + } + + static int stm32_sai_sub_remove(struct platform_device *pdev) +diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c +index e53fb4bd6..1bfa3b2ba 100644 +--- a/sound/soc/stm/stm32_spdifrx.c ++++ b/sound/soc/stm/stm32_spdifrx.c +@@ -353,6 +353,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; + cr_mask = cr; + ++ cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); ++ cr_mask |= SPDIFRX_CR_NBTR_MASK; + cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); + cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; + ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, +@@ -404,7 +406,9 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, + + spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); + if (IS_ERR(spdifrx->ctrl_chan)) { +- dev_err(dev, "dma_request_slave_channel failed\n"); ++ if (PTR_ERR(spdifrx->ctrl_chan) != -EPROBE_DEFER) ++ dev_err(dev, "dma_request_slave_channel error %ld\n", ++ PTR_ERR(spdifrx->ctrl_chan)); + return PTR_ERR(spdifrx->ctrl_chan); + } + +@@ -665,7 +669,7 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) + struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; + struct platform_device *pdev = spdifrx->pdev; + unsigned int cr, mask, sr, imr; +- unsigned int flags; ++ unsigned int flags, sync_state; + int err = 0, err_xrun = 0; + + regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); +@@ -725,11 +729,23 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) + } + + if (err) { +- /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ ++ regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); ++ sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && ++ SPDIFRX_SPDIFEN_SYNC; ++ ++ /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_SPDIFEN_MASK, cr); + ++ /* If SPDIFRX was in STATE_SYNC, retry synchro */ ++ if (sync_state) { ++ cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); ++ regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, ++ SPDIFRX_CR_SPDIFEN_MASK, cr); ++ return IRQ_HANDLED; ++ } ++ + spin_lock(&spdifrx->irq_lock); + if (spdifrx->substream) + snd_pcm_stop(spdifrx->substream, +@@ -915,7 +931,9 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, + + spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); + if (IS_ERR(spdifrx->kclk)) { +- dev_err(&pdev->dev, "Could not get kclk\n"); ++ if (PTR_ERR(spdifrx->kclk) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Could not get kclk: %ld\n", ++ PTR_ERR(spdifrx->kclk)); + return PTR_ERR(spdifrx->kclk); + } + +@@ -926,6 +944,22 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, + return 0; + } + ++static int stm32_spdifrx_remove(struct platform_device *pdev) ++{ ++ struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); ++ ++ if (spdifrx->ctrl_chan) ++ dma_release_channel(spdifrx->ctrl_chan); ++ ++ if (spdifrx->dmab) ++ snd_dma_free_pages(spdifrx->dmab); ++ ++ snd_dmaengine_pcm_unregister(&pdev->dev); ++ snd_soc_unregister_component(&pdev->dev); ++ ++ return 0; ++} ++ + static int stm32_spdifrx_probe(struct platform_device *pdev) + { + struct stm32_spdifrx_data *spdifrx; +@@ -953,7 +987,9 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) + spdifrx->base, + spdifrx->regmap_conf); + if (IS_ERR(spdifrx->regmap)) { +- dev_err(&pdev->dev, "Regmap init failed\n"); ++ if (PTR_ERR(spdifrx->regmap) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Regmap init error %ld\n", ++ PTR_ERR(spdifrx->regmap)); + return PTR_ERR(spdifrx->regmap); + } + +@@ -964,37 +1000,46 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) + return ret; + } + +- rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (!IS_ERR(rst)) { +- reset_control_assert(rst); +- udelay(2); +- reset_control_deassert(rst); ++ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ if (PTR_ERR(rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Reset controller error %ld\n", ++ PTR_ERR(rst)); ++ return PTR_ERR(rst); + } ++ reset_control_assert(rst); ++ udelay(2); ++ reset_control_deassert(rst); + +- ret = devm_snd_soc_register_component(&pdev->dev, +- &stm32_spdifrx_component, +- stm32_spdifrx_dai, +- ARRAY_SIZE(stm32_spdifrx_dai)); +- if (ret) ++ pcm_config = &stm32_spdifrx_pcm_config; ++ ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); ++ return ret; ++ } ++ ++ ret = snd_soc_register_component(&pdev->dev, ++ &stm32_spdifrx_component, ++ stm32_spdifrx_dai, ++ ARRAY_SIZE(stm32_spdifrx_dai)); ++ if (ret) { ++ snd_dmaengine_pcm_unregister(&pdev->dev); + return ret; ++ } + + ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); + if (ret) + goto error; + +- pcm_config = &stm32_spdifrx_pcm_config; +- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); +- if (ret) { +- dev_err(&pdev->dev, "PCM DMA register returned %d\n", ret); +- goto error; +- } +- + ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); + if (ret) + goto error; + + if (idr == SPDIFRX_IPIDR_NUMBER) { + ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); ++ if (ret) ++ goto error; + + dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", + FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), +@@ -1004,27 +1049,11 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) + return ret; + + error: +- if (!IS_ERR(spdifrx->ctrl_chan)) +- dma_release_channel(spdifrx->ctrl_chan); +- if (spdifrx->dmab) +- snd_dma_free_pages(spdifrx->dmab); ++ stm32_spdifrx_remove(pdev); + + return ret; + } + +-static int stm32_spdifrx_remove(struct platform_device *pdev) +-{ +- struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); +- +- if (spdifrx->ctrl_chan) +- dma_release_channel(spdifrx->ctrl_chan); +- +- if (spdifrx->dmab) +- snd_dma_free_pages(spdifrx->dmab); +- +- return 0; +-} +- + MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); + + #ifdef CONFIG_PM_SLEEP +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch new file mode 100644 index 0000000..a12e2fd --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch @@ -0,0 +1,213 @@ +From 21d34047c11667042371bf23d89f168be4eb607d Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:48:07 +0200 +Subject: [PATCH 19/23] ARM-stm32mp1-r1-MISC + +--- + CONTRIBUTING.md | 30 ++++++++++++++++++++++++ + drivers/block/loop.c | 49 ++++++++++++++++++++++++++++----------- + include/linux/pm_wakeup.h | 10 ++++++++ + tools/perf/util/srcline.c | 16 ++++++++++++- + 4 files changed, 91 insertions(+), 14 deletions(-) + create mode 100644 CONTRIBUTING.md + +diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md +new file mode 100644 +index 000000000..3d1bacd78 +--- /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. +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index ef6e25185..6831ab725 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -427,11 +427,12 @@ static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos, + * information. + */ + struct file *file = lo->lo_backing_file; ++ struct request_queue *q = lo->lo_queue; + int ret; + + mode |= FALLOC_FL_KEEP_SIZE; + +- if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) { ++ if (!blk_queue_discard(q)) { + ret = -EOPNOTSUPP; + goto out; + } +@@ -461,7 +462,7 @@ static void lo_complete_rq(struct request *rq) + if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || + req_op(rq) != REQ_OP_READ) { + if (cmd->ret < 0) +- ret = BLK_STS_IOERR; ++ ret = errno_to_blk_status(cmd->ret); + goto end_io; + } + +@@ -863,28 +864,47 @@ static void loop_config_discard(struct loop_device *lo) + struct inode *inode = file->f_mapping->host; + struct request_queue *q = lo->lo_queue; + ++ /* ++ * If the backing device is a block device, mirror its zeroing ++ * capability. Set the discard sectors to the block device's zeroing ++ * capabilities because loop discards result in blkdev_issue_zeroout(), ++ * not blkdev_issue_discard(). This maintains consistent behavior with ++ * file-backed loop devices: discarded regions read back as zero. ++ */ ++ if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) { ++ struct request_queue *backingq; ++ ++ backingq = bdev_get_queue(inode->i_bdev); ++ blk_queue_max_discard_sectors(q, ++ backingq->limits.max_write_zeroes_sectors); ++ ++ blk_queue_max_write_zeroes_sectors(q, ++ backingq->limits.max_write_zeroes_sectors); ++ + /* + * We use punch hole to reclaim the free space used by the + * image a.k.a. discard. However we do not support discard if + * encryption is enabled, because it may give an attacker + * useful information. + */ +- if ((!file->f_op->fallocate) || +- lo->lo_encrypt_key_size) { ++ } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) { + q->limits.discard_granularity = 0; + q->limits.discard_alignment = 0; + blk_queue_max_discard_sectors(q, 0); + blk_queue_max_write_zeroes_sectors(q, 0); +- blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); +- return; +- } + +- q->limits.discard_granularity = inode->i_sb->s_blocksize; +- q->limits.discard_alignment = 0; ++ } else { ++ q->limits.discard_granularity = inode->i_sb->s_blocksize; ++ q->limits.discard_alignment = 0; ++ ++ blk_queue_max_discard_sectors(q, UINT_MAX >> 9); ++ blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9); ++ } + +- blk_queue_max_discard_sectors(q, UINT_MAX >> 9); +- blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9); +- blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); ++ if (q->limits.max_write_zeroes_sectors) ++ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); ++ else ++ blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); + } + + static void loop_unprepare_queue(struct loop_device *lo) +@@ -1950,7 +1970,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd) + failed: + /* complete non-aio request */ + if (!cmd->use_aio || ret) { +- cmd->ret = ret ? -EIO : 0; ++ if (ret == -EOPNOTSUPP) ++ cmd->ret = ret; ++ else ++ cmd->ret = ret ? -EIO : 0; + blk_mq_complete_request(rq); + } + } +diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h +index 661efa029..faee74f36 100644 +--- a/include/linux/pm_wakeup.h ++++ b/include/linux/pm_wakeup.h +@@ -79,6 +79,11 @@ static inline bool device_may_wakeup(struct device *dev) + return dev->power.can_wakeup && !!dev->power.wakeup; + } + ++static inline bool device_wakeup_path(struct device *dev) ++{ ++ return !!dev->power.wakeup_path; ++} ++ + static inline void device_set_wakeup_path(struct device *dev) + { + dev->power.wakeup_path = true; +@@ -165,6 +170,11 @@ static inline bool device_may_wakeup(struct device *dev) + return dev->power.can_wakeup && dev->power.should_wakeup; + } + ++static inline bool device_wakeup_path(struct device *dev) ++{ ++ return false; ++} ++ + static inline void device_set_wakeup_path(struct device *dev) {} + + static inline void __pm_stay_awake(struct wakeup_source *ws) {} +diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c +index 6ccf6f6d0..5b7d6c16d 100644 +--- a/tools/perf/util/srcline.c ++++ b/tools/perf/util/srcline.c +@@ -193,16 +193,30 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data) + bfd_vma pc, vma; + bfd_size_type size; + struct a2l_data *a2l = data; ++ flagword flags; + + if (a2l->found) + return; + +- if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) ++#ifdef bfd_get_section_flags ++ flags = bfd_get_section_flags(abfd, section); ++#else ++ flags = bfd_section_flags(section); ++#endif ++ if ((flags & SEC_ALLOC) == 0) + return; + + pc = a2l->addr; ++#ifdef bfd_get_section_vma + vma = bfd_get_section_vma(abfd, section); ++#else ++ vma = bfd_section_vma(section); ++#endif ++#ifdef bfd_get_section_size + size = bfd_get_section_size(section); ++#else ++ size = bfd_section_size(section); ++#endif + + if (pc < vma || pc >= vma + size) + return; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch new file mode 100644 index 0000000..d47d1da --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch @@ -0,0 +1,12460 @@ +From 52b77d7689df6579e251a92b3911b13b3124d363 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:49:54 +0200 +Subject: [PATCH 20/23] ARM-stm32mp1-r1-DEVICETREE + +--- + .../devicetree/bindings/arm/stm32/stm32.yaml | 5 +- + .../bindings/clock/st,stm32mp1-rcc.txt | 5 +- + .../bindings/connector/usb-connector.txt | 2 + + .../bindings/cpufreq/stm32-cpufreq.txt | 61 + + .../display/panel/orisetech,otm8009a.txt | 23 - + .../display/panel/orisetech,otm8009a.yaml | 53 + + .../display/panel/raydium,rm68200.txt | 25 - + .../display/panel/raydium,rm68200.yaml | 52 + + .../devicetree/bindings/dma/stm32-dma.txt | 36 +- + .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- + .../devicetree/bindings/dma/stm32-mdma.txt | 66 +- + .../devicetree/bindings/hwlock/hwlock.txt | 27 +- + .../bindings/hwlock/st,stm32-hwspinlock.txt | 6 +- + .../devicetree/bindings/i2c/i2c-stm32.txt | 12 +- + .../iio/adc/sigma-delta-modulator.txt | 3 + + .../bindings/iio/adc/st,stm32-adc.txt | 2 + + .../iio/timer/stm32-timer-trigger.txt | 9 + + .../interrupt-controller/st,stm32-exti.txt | 30 +- + .../devicetree/bindings/mailbox/arm-smc.yaml | 96 ++ + .../bindings/mailbox/stm32-ipcc.txt | 4 +- + .../bindings/media/video-interfaces.txt | 2 + + .../bindings/mfd/st,stm32mp1-pwr.txt | 57 + + .../devicetree/bindings/mmc/mmci.txt | 2 + + .../bindings/perf/stm32-ddr-pmu.txt | 18 + + .../bindings/phy/phy-stm32-usbphyc.txt | 59 +- + .../bindings/pinctrl/st,stm32-pinctrl.yaml | 8 + + .../devicetree/bindings/pwm/pwm-stm32.txt | 8 +- + .../bindings/remoteproc/rproc-srm.txt | 58 + + .../bindings/remoteproc/stm32-rproc.txt | 13 + + .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- + .../bindings/serial/st,stm32-usart.txt | 46 +- + .../bindings/soc/stm32/stm32_hdp.txt | 39 + + .../devicetree/bindings/usb/dwc2.txt | 8 + + .../devicetree/bindings/usb/generic-ehci.yaml | 5 + + .../bindings/usb/st,typec-stusb.txt | 48 + + arch/arm/boot/dts/Makefile | 19 +- + arch/arm/boot/dts/stm32mp15-no-scmi.dtsi | 157 ++ + arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 1411 +++++++++++++++++ + .../dts/{stm32mp157c.dtsi => stm32mp151.dtsi} | 941 ++++++++--- + arch/arm/boot/dts/stm32mp153.dtsi | 54 + + .../boot/dts/stm32mp157-m4-srm-pinctrl.dtsi | 524 ++++++ + arch/arm/boot/dts/stm32mp157-m4-srm.dtsi | 442 ++++++ + arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 925 ----------- + arch/arm/boot/dts/stm32mp157.dtsi | 32 + + arch/arm/boot/dts/stm32mp157a-avenger96.dts | 17 +- + arch/arm/boot/dts/stm32mp157a-dk1.dts | 431 +---- + arch/arm/boot/dts/stm32mp157a-ed1.dts | 52 + + arch/arm/boot/dts/stm32mp157a-ev1.dts | 86 + + .../boot/dts/stm32mp157c-dk2-a7-examples.dts | 46 + + .../boot/dts/stm32mp157c-dk2-m4-examples.dts | 129 ++ + arch/arm/boot/dts/stm32mp157c-dk2.dts | 126 +- + arch/arm/boot/dts/stm32mp157c-ed1.dts | 317 +--- + .../boot/dts/stm32mp157c-ev1-a7-examples.dts | 53 + + .../boot/dts/stm32mp157c-ev1-m4-examples.dts | 146 ++ + arch/arm/boot/dts/stm32mp157c-ev1.dts | 293 +--- + arch/arm/boot/dts/stm32mp157d-dk1.dts | 44 + + arch/arm/boot/dts/stm32mp157d-ed1.dts | 52 + + arch/arm/boot/dts/stm32mp157d-ev1.dts | 86 + + .../boot/dts/stm32mp157f-dk2-a7-examples.dts | 46 + + .../boot/dts/stm32mp157f-dk2-m4-examples.dts | 129 ++ + arch/arm/boot/dts/stm32mp157f-dk2.dts | 185 +++ + arch/arm/boot/dts/stm32mp157f-ed1.dts | 56 + + .../boot/dts/stm32mp157f-ev1-a7-examples.dts | 53 + + .../boot/dts/stm32mp157f-ev1-m4-examples.dts | 146 ++ + arch/arm/boot/dts/stm32mp157f-ev1.dts | 86 + + arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi | 90 -- + arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi | 62 - + arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi | 78 - + arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi | 62 - + arch/arm/boot/dts/stm32mp15xa.dtsi | 13 + + arch/arm/boot/dts/stm32mp15xc.dtsi | 20 + + arch/arm/boot/dts/stm32mp15xd.dtsi | 42 + + arch/arm/boot/dts/stm32mp15xf.dtsi | 20 + + arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 768 +++++++++ + arch/arm/boot/dts/stm32mp15xx-edx.dtsi | 408 +++++ + arch/arm/boot/dts/stm32mp15xx-evx.dtsi | 680 ++++++++ + arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi | 85 + + arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi | 57 + + arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi | 73 + + arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi | 57 + + include/dt-bindings/clock/stm32mp1-clks.h | 33 + + include/dt-bindings/mfd/stm32f4-rcc.h | 1 - + include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + + include/dt-bindings/reset/stm32mp1-resets.h | 13 + + include/dt-bindings/rtc/rtc-stm32.h | 13 + + include/dt-bindings/soc/stm32-hdp.h | 108 ++ + 86 files changed, 8088 insertions(+), 2583 deletions(-) + create mode 100644 Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt + delete mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt + create mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml + delete mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt + create mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml + create mode 100644 Documentation/devicetree/bindings/mailbox/arm-smc.yaml + create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt + create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt + create mode 100644 Documentation/devicetree/bindings/remoteproc/rproc-srm.txt + create mode 100644 Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt + create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stusb.txt + create mode 100644 arch/arm/boot/dts/stm32mp15-no-scmi.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi + rename arch/arm/boot/dts/{stm32mp157c.dtsi => stm32mp151.dtsi} (59%) + create mode 100644 arch/arm/boot/dts/stm32mp153.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp157-m4-srm.dtsi + delete mode 100644 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp157.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp157a-ed1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157a-ev1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157d-dk1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157d-ed1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157d-ev1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-dk2.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-ed1.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts + create mode 100644 arch/arm/boot/dts/stm32mp157f-ev1.dts + delete mode 100644 arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi + delete mode 100644 arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi + delete mode 100644 arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi + delete mode 100644 arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xa.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xc.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xd.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xf.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xx-dkx.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xx-edx.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xx-evx.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi + create mode 100644 arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi + create mode 100644 include/dt-bindings/rtc/rtc-stm32.h + create mode 100644 include/dt-bindings/soc/stm32-hdp.h + +diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml +index 4d194f1eb..c9d74357b 100644 +--- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml ++++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml +@@ -27,5 +27,8 @@ properties: + - items: + - enum: + - arrow,stm32mp157a-avenger96 # Avenger96 +- - const: st,stm32mp157 ++ - enum: ++ - st,stm32mp157 ++ - st,stm32mp153 ++ - st,stm32mp151 + ... +diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt +index fb9495ea5..1f1ec3446 100644 +--- a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt ++++ b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt +@@ -12,7 +12,7 @@ binding usage. + + + Required properties: +-- compatible: "st,stm32mp1-rcc", "syscon" ++- compatible: "st,stm32mp1-rcc-secure", "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, +@@ -23,7 +23,8 @@ Required properties: + + Example: + rcc: rcc@50000000 { +- compatible = "st,stm32mp1-rcc", "syscon"; ++ compatible = "st,stm32mp1-rcc-secure", "st,stm32mp1-rcc", ++ "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt +index d35798718..5c0bb0395 100644 +--- a/Documentation/devicetree/bindings/connector/usb-connector.txt ++++ b/Documentation/devicetree/bindings/connector/usb-connector.txt +@@ -34,6 +34,8 @@ Optional properties for usb-b-connector: + Optional properties for usb-c-connector: + - power-role: should be one of "source", "sink" or "dual"(DRP) if typec + connector has power support. ++- power-opmode: should be one of "default", "1.5A", "3.0A" or ++ "usb_power_delivery" if typec connector has power support. + - try-power-role: preferred power role if "dual"(DRP) can support Try.SNK + or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. + - data-role: should be one of "host", "device", "dual"(DRD) if typec +diff --git a/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt +new file mode 100644 +index 000000000..1292eb261 +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt +@@ -0,0 +1,61 @@ ++STM32 CPUFreq and OPP bindings ++============================== ++ ++STM32 CPUFreq driver needs to read chip information from the SoC to list ++available OPPs. Then it depends on cpufreq-dt bindings. ++ ++Required properties: ++-------------------- ++- clocks: Phandle to the cpu clock "cpu". ++- clocks-name: Should contain "cpu". ++- nvmem-cells: Phandle to nvmem cell that contains "part_number". ++- nvmem-cell-names: Must be "part_number". ++- operating-points-v2: Phandle to operating points table. See ../power/opp.txt ++ for more details. ++ ++Optional properties: ++-------------------- ++See cpufreq-dt.txt for optional properties. ++ ++Examples: ++--------- ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "arm,cortex-a7"; ++ device_type = "cpu"; ++ reg = <0>; ++ 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>; ++ 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>; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt +deleted file mode 100644 +index 203b03eef..000000000 +--- a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt ++++ /dev/null +@@ -1,23 +0,0 @@ +-Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode) +- +-The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using +-a MIPI-DSI video interface. Its backlight is managed through the DSI link. +- +-Required properties: +- - compatible: "orisetech,otm8009a" +- - reg: the virtual channel number of a DSI peripheral +- +-Optional properties: +- - reset-gpios: a GPIO spec for the reset pin (active low). +- - power-supply: phandle of the regulator that provides the supply voltage. +- +-Example: +-&dsi { +- ... +- panel@0 { +- compatible = "orisetech,otm8009a"; +- reg = <0>; +- reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; +- power-supply = <&v1v8>; +- }; +-}; +diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml +new file mode 100644 +index 000000000..6eda24035 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml +@@ -0,0 +1,53 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/orisetech,otm8009a.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Orise Tech OTM8009A 3.97" 480x800 panel ++ ++maintainers: ++ - Yannick Fertre ++ ++description: ++ The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using ++ a MIPI-DSI video interface. Its backlight is managed through the DSI link. ++ ++properties: ++ compatible: ++ const: orisetech,otm8009a ++ ++ power-supply: true ++ reset-gpios: true ++ backlight: true ++ port: true ++ reg: true ++ ++required: ++ - compatible ++ - reg ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ display1: display { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ panel { ++ compatible = "orisetech,otm8009a"; ++ reg = <0>; ++ reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; ++ power-supply = <&v1v8>; ++ ++ port { ++ panel_in_dsi: endpoint { ++ remote-endpoint = <&controller_out_dsi>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt +deleted file mode 100644 +index cbb79ef3b..000000000 +--- a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt ++++ /dev/null +@@ -1,25 +0,0 @@ +-Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel +- +-The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD +-panel connected using a MIPI-DSI video interface. +- +-Required properties: +- - compatible: "raydium,rm68200" +- - reg: the virtual channel number of a DSI peripheral +- +-Optional properties: +- - reset-gpios: a GPIO spec for the reset pin (active low). +- - power-supply: phandle of the regulator that provides the supply voltage. +- - backlight: phandle of the backlight device attached to the panel. +- +-Example: +-&dsi { +- ... +- panel@0 { +- compatible = "raydium,rm68200"; +- reg = <0>; +- reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; +- power-supply = <&v1v8>; +- backlight = <&pwm_backlight>; +- }; +-}; +diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml +new file mode 100644 +index 000000000..2bbd4a0cb +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml +@@ -0,0 +1,52 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/raydium,rm68200.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raydium RM68200 5.5" 720x1280 panel ++ ++maintainers: ++ - Yannick Fertre ++ ++description: ++ The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD ++ panel connected using a MIPI-DSI video interface. ++ ++properties: ++ compatible: ++ const: raydium,rm68200 ++ ++ power-supply: true ++ reset-gpios: true ++ backlight: true ++ port: true ++ reg: true ++ ++required: ++ - compatible ++ - reg ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ display0: display { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ panel { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ power-supply = <&v1v8>; ++ port { ++ panel_in_dsi: endpoint { ++ remote-endpoint = <&controller_out_dsi>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt +index c5f519097..11ee1e9f8 100644 +--- a/Documentation/devicetree/bindings/dma/stm32-dma.txt ++++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt +@@ -17,6 +17,12 @@ Optional properties: + - resets: Reference to a reset controller asserting the DMA controller + - st,mem2mem: boolean; if defined, it indicates that the controller supports + memory-to-memory transfer ++- dmas: A list of eight dma specifiers, one for each entry in dma-names. ++ Refer to stm32-mdma.txt for more details. ++- dma-names: should contain "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6" and ++ "ch7" and represents each STM32 DMA channel connected to a STM32 MDMA one. ++- memory-region : phandle to a node describing memory to be used for ++ M2M intermediate transfer between DMA and MDMA. + + Example: + +@@ -36,6 +42,16 @@ Example: + st,mem2mem; + resets = <&rcc 150>; + dma-requests = <8>; ++ dmas = <&mdma1 8 0x10 0x1200000a 0x40026408 0x00000020 1>, ++ <&mdma1 9 0x10 0x1200000a 0x40026408 0x00000800 1>, ++ <&mdma1 10 0x10 0x1200000a 0x40026408 0x00200000 1>, ++ <&mdma1 11 0x10 0x1200000a 0x40026408 0x08000000 1>, ++ <&mdma1 12 0x10 0x1200000a 0x4002640C 0x00000020 1>, ++ <&mdma1 13 0x10 0x1200000a 0x4002640C 0x00000800 1>, ++ <&mdma1 14 0x10 0x1200000a 0x4002640C 0x00200000 1>, ++ <&mdma1 15 0x10 0x1200000a 0x4002640C 0x08000000 1>; ++ dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; ++ memory-region = <&sram_dmapool>; + }; + + * DMA client +@@ -62,13 +78,25 @@ channel: a phandle to the DMA controller plus the following four integer cells: + 0x1: medium + 0x2: high + 0x3: very high +-4. A 32bit bitfield value specifying DMA features which are device dependent: ++4. A bitfield value specifying DMA features which are device dependent: + -bit 0-1: DMA FIFO threshold selection + 0x0: 1/4 full FIFO + 0x1: 1/2 full FIFO + 0x2: 3/4 full FIFO + 0x3: full FIFO +- ++ -bit 2: DMA direct mode ++ 0: FIFO mode: with threshold level selectable with bit 0-1 ++ 1: Direct mode: each DMA request immediately initiates a transfer ++ from/to the memory. ++ -bit 30-29: indicated SRAM Buffer size in (2^order)*PAGE_SIZE. ++ Order is given by those 2 bits starting at 0. ++ Valid only whether Intermediate M2M transfer is set. ++ For cyclic, whether Intermediate M2M transfer is chosen, any value can ++ be set: SRAM buffer size will rely on period size and not on this DT ++ value. ++ -bit 31: Intermediate M2M transfer from/to DDR to/from SRAM throughout MDMA ++ 0: MDMA not used to generate an intermediate M2M transfer ++ 1: MDMA used to generate an intermediate M2M transfer. + + Example: + +@@ -77,7 +105,7 @@ Example: + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&clk_pclk2>; +- dmas = <&dma2 2 4 0x10400 0x3>, +- <&dma2 7 5 0x10200 0x3>; ++ dmas = <&dma2 2 4 0x10400 0x1>, ++ <&dma2 7 5 0x10200 0x1>; + dma-names = "rx", "tx"; + }; +diff --git a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt +index 1b893b235..8e092d29b 100644 +--- a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt ++++ b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt +@@ -4,9 +4,6 @@ Required properties: + - compatible: "st,stm32h7-dmamux" + - reg: Memory map for accessing module + - #dma-cells: Should be set to <3>. +- First parameter is request line number. +- Second is DMA channel configuration +- Third is Fifo threshold + For more details about the three cells, please see + stm32-dma.txt documentation binding file + - dma-masters: Phandle pointing to the DMA controllers. +@@ -53,7 +50,7 @@ dma2: dma@40020400 { + <68>, + <69>, + <70>; +- clocks = <&timer_clk>; ++ clocks = <&clk_hclk>; + #dma-cells = <4>; + st,mem2mem; + resets = <&rcc 150>; +diff --git a/Documentation/devicetree/bindings/dma/stm32-mdma.txt b/Documentation/devicetree/bindings/dma/stm32-mdma.txt +index d18772d6b..077c819a5 100644 +--- a/Documentation/devicetree/bindings/dma/stm32-mdma.txt ++++ b/Documentation/devicetree/bindings/dma/stm32-mdma.txt +@@ -10,7 +10,7 @@ Required properties: + - interrupts: Should contain the MDMA interrupt. + - clocks: Should contain the input clock of the DMA instance. + - resets: Reference to a reset controller asserting the DMA controller. +-- #dma-cells : Must be <5>. See DMA client paragraph for more details. ++- #dma-cells : Must be <6>. See DMA client paragraph for more details. + + Optional properties: + - dma-channels: Number of DMA channels supported by the controller. +@@ -26,7 +26,7 @@ Example: + interrupts = <122>; + clocks = <&timer_clk>; + resets = <&rcc 992>; +- #dma-cells = <5>; ++ #dma-cells = <6>; + dma-channels = <16>; + dma-requests = <32>; + st,ahb-addr-masks = <0x20000000>, <0x00000000>; +@@ -35,60 +35,64 @@ Example: + * DMA client + + DMA clients connected to the STM32 MDMA controller must use the format +-described in the dma.txt file, using a five-cell specifier for each channel: +-a phandle to the MDMA controller plus the following five integer cells: ++described in the dma.txt file, using a six-cell specifier for each channel: ++a phandle to the MDMA controller plus the following six integer cells: + + 1. The request line number + 2. The priority level +- 0x00: Low +- 0x01: Medium +- 0x10: High +- 0x11: Very high ++ 0x0: Low ++ 0x1: Medium ++ 0x2: High ++ 0x3: Very high + 3. A 32bit mask specifying the DMA channel configuration + -bit 0-1: Source increment mode +- 0x00: Source address pointer is fixed +- 0x10: Source address pointer is incremented after each data transfer +- 0x11: Source address pointer is decremented after each data transfer ++ 0x0: Source address pointer is fixed ++ 0x2: Source address pointer is incremented after each data transfer ++ 0x3: Source address pointer is decremented after each data transfer + -bit 2-3: Destination increment mode +- 0x00: Destination address pointer is fixed +- 0x10: Destination address pointer is incremented after each data ++ 0x0: Destination address pointer is fixed ++ 0x2: Destination address pointer is incremented after each data + transfer +- 0x11: Destination address pointer is decremented after each data ++ 0x3: Destination address pointer is decremented after each data + transfer + -bit 8-9: Source increment offset size +- 0x00: byte (8bit) +- 0x01: half-word (16bit) +- 0x10: word (32bit) +- 0x11: double-word (64bit) ++ 0x0: byte (8bit) ++ 0x1: half-word (16bit) ++ 0x2: word (32bit) ++ 0x3: double-word (64bit) + -bit 10-11: Destination increment offset size +- 0x00: byte (8bit) +- 0x01: half-word (16bit) +- 0x10: word (32bit) +- 0x11: double-word (64bit) ++ 0x0: byte (8bit) ++ 0x1: half-word (16bit) ++ 0x2: word (32bit) ++ 0x3: double-word (64bit) + -bit 25-18: The number of bytes to be transferred in a single transfer + (min = 1 byte, max = 128 bytes) + -bit 29:28: Trigger Mode +- 0x00: Each MDMA request triggers a buffer transfer (max 128 bytes) +- 0x01: Each MDMA request triggers a block transfer (max 64K bytes) +- 0x10: Each MDMA request triggers a repeated block transfer +- 0x11: Each MDMA request triggers a linked list transfer ++ 0x0: Each MDMA request triggers a buffer transfer (max 128 bytes) ++ 0x1: Each MDMA request triggers a block transfer (max 64K bytes) ++ 0x2: Each MDMA request triggers a repeated block transfer ++ 0x3: Each MDMA request triggers a linked list transfer + 4. A 32bit value specifying the register to be used to acknowledge the request + if no HW ack signal is used by the MDMA client + 5. A 32bit mask specifying the value to be written to acknowledge the request + if no HW ack signal is used by the MDMA client ++6. A bitfield value specifying if the MDMA client wants to generate M2M ++ transfer with HW trigger (1) or not (0). This bitfield should be only ++ enabled for M2M transfer triggered by STM32 DMA client. The memory devices ++ involved in this kind of transfer are SRAM and DDR. + + Example: + + i2c4: i2c@5c002000 { + compatible = "st,stm32f7-i2c"; + reg = <0x5c002000 0x400>; +- interrupts = <95>, +- <96>; +- clocks = <&timer_clk>; ++ interrupts = , ++ ; ++ clocks = <&clk_hsi>; + #address-cells = <1>; + #size-cells = <0>; +- dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>, +- <&mdma1 37 0x0 0x40002 0x0 0x0>; ++ dmas = <&mdma1 36 0x0 0x40008 0x0 0x0 0>, ++ <&mdma1 37 0x0 0x40002 0x0 0x0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; +diff --git a/Documentation/devicetree/bindings/hwlock/hwlock.txt b/Documentation/devicetree/bindings/hwlock/hwlock.txt +index 085d1f5c9..e98088a40 100644 +--- a/Documentation/devicetree/bindings/hwlock/hwlock.txt ++++ b/Documentation/devicetree/bindings/hwlock/hwlock.txt +@@ -13,7 +13,7 @@ hwlock providers: + + Required properties: + - #hwlock-cells: Specifies the number of cells needed to represent a +- specific lock. ++ specific lock. Shall be 1 or 2 (see hwlocks below). + + hwlock users: + ============= +@@ -27,6 +27,11 @@ Required properties: + #hwlock-cells. The list can have just a single hwlock + or multiple hwlocks, with each hwlock represented by + a phandle and a corresponding args specifier. ++ If #hwlock-cells is 1, all of the locks are exclusive ++ (cannot be used by several users). ++ If #hwlock-cells is 2, the value of the second cell ++ defines whether the lock is for exclusive usage (0) or ++ shared (1) i.e. can be used by several users. + + Optional properties: + - hwlock-names: List of hwlock name strings defined in the same order +@@ -46,14 +51,22 @@ of length 1. + ... + }; + +-2. Example of a node using multiple specific hwlocks: ++2. Example of nodes using multiple and shared specific hwlocks: + +-The following example has a node requesting two hwlocks, a hwlock within +-the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another +-hwlock within the hwlock device node 'hwlock2' with #hwlock-cells value of 2. ++The following example has a nodeA requesting two hwlocks: ++- an exclusive one (#hwlock-cells = 1) within the hwlock device node 'hwlock1' ++- a shared one (#hwlock-cells = 2, second cell = 1) within the hwlock device ++ node 'hwlock2'. ++The shared lock is also be used by nodeB. + +- node { ++ nodeA { + ... +- hwlocks = <&hwlock1 2>, <&hwlock2 0 3>; ++ hwlocks = <&hwlock1 2>, <&hwlock2 0 1>; + ... + }; ++ ++ nodeB { ++ ... ++ hwlocks = <&hwlock2 0 1>; ++ ... ++ }; +\ No newline at end of file +diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt +index adf4f000e..60a37163b 100644 +--- a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt ++++ b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt +@@ -4,8 +4,8 @@ STM32 Hardware Spinlock Device Binding + Required properties : + - compatible : should be "st,stm32-hwspinlock". + - reg : the register address of hwspinlock. +-- #hwlock-cells : hwlock users only use the hwlock id to represent a specific +- hwlock, so the number of cells should be <1> here. ++- #hwlock-cells : should be <2> so the hwlock users use the hwlock id to ++ represent a specific hwlock and define its shared / exclusive attribute. + - clock-names : Must contain "hsem". + - clocks : Must contain a phandle entry for the clock in clock-names, see the + common clock bindings. +@@ -16,7 +16,7 @@ Please look at the generic hwlock binding for usage information for consumers, + Example of hwlock provider: + hwspinlock@4c000000 { + compatible = "st,stm32-hwspinlock"; +- #hwlock-cells = <1>; ++ #hwlock-cells = <2>; + reg = <0x4c000000 0x400>; + clocks = <&rcc HSEM>; + clock-names = "hsem"; +diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt +index ce3df2fff..62ccd03fa 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt +@@ -4,13 +4,15 @@ Required properties: + - compatible: Must be one of the following + - "st,stm32f4-i2c" + - "st,stm32f7-i2c" ++ - "st,stm32mp15-i2c" + - 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. + - 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>; + +@@ -34,6 +36,10 @@ Optional properties: + 2nd cell: register offset within SYSCFG + 3rd cell: register bitmask for FMP bit + For STM32F7, STM32H7 and STM32MP1 only. ++- st,smbus-alert: enable the SMBus Alert feature ++- st,smbus-host-notify: enable the SMBus Host-Notify feature ++- wakeup-source: Enable the possibility to use the I2C as a wakeup-source ++ For STM32H7 and STM32MP1 only. + + Example: + +@@ -60,6 +66,8 @@ Example: + resets = <&rcc STM32F7_APB1_RESET(I2C1)>; + clocks = <&rcc 1 CLK_I2C1>; + pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; +- pinctrl-names = "default"; ++ 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>; + }; +diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt +index 59b92cd32..fa70fda13 100644 +--- a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt ++++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt +@@ -5,6 +5,9 @@ Required properties: + as a generic SD modulator if modulator not specified in compatible list. + - #io-channel-cells = <0>: See the IIO bindings section "IIO consumers". + ++Optional properties: ++- vref-supply: Phandle to the vref input analog reference voltage. ++ + Example node: + + ads1202: adc { +diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +index 4c0da8c74..8de933146 100644 +--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt ++++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +@@ -53,6 +53,8 @@ Optional properties: + analog input switches on stm32mp1. + - st,syscfg: Phandle to system configuration controller. It can be used to + control the analog circuitry on stm32mp1. ++- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog ++ circuitry. + + Contents of a stm32 adc child node: + ----------------------------------- +diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt +index b8e8c769d..4713ff1f5 100644 +--- a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt ++++ b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt +@@ -9,6 +9,12 @@ Required parameters: + "st,stm32h7-timer-trigger" + - reg: Identify trigger hardware block. + ++Optional properties: ++- pinctrl-names: Set to "default". An additional "sleep" state can be ++ defined to set pins in sleep state when in low power. ++- pinctrl-n: Phandle(s) pointing to pin configuration node for PWM, ++ respectively for "default" and "sleep" states. ++ + Example: + timers@40010000 { + #address-cells = <1>; +@@ -21,5 +27,8 @@ Example: + timer@0 { + compatible = "st,stm32-timer-trigger"; + reg = <0>; ++ pinctrl-0 = <&tim1_pins>; ++ pinctrl-1 = <&tim1_sleep_pins>; ++ pinctrl-names = "default", "sleep"; + }; + }; +diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +index cd01b2292..abcf816d6 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt ++++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +@@ -18,7 +18,19 @@ Optional properties: + + - hwlocks: reference to a phandle of a hardware spinlock provider node. + +-Example: ++Exti could have several parent interrupt controllers. In this case child nodes ++are used to describe those "extra" parent controllers. Properties to use are: ++ ++- interrupt-controller: Indentifies the node as an interrupt controller ++- #interrupt-cells: Specifies the number of cells to encode an interrupt ++ specifier, shall be 2 ++- interrupt-parent: Phandle to the interrupt parent node. ++- st,irq-number: Interrupt number mapped on the parent. ++ ++See example 2. ++ ++ ++Example 1: + + exti: interrupt-controller@40013c00 { + compatible = "st,stm32-exti"; +@@ -27,3 +39,19 @@ exti: interrupt-controller@40013c00 { + reg = <0x40013C00 0x400>; + interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>; + }; ++ ++Example 2: ++ ++exti: interrupt-controller@5000d000 { ++ compatible = "st,stm32mp1-exti", "syscon"; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x5000d000 0x400>; ++ ++ exti_pwr: exti-pwr { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&pwr>; ++ st,irq-number = <6>; ++ }; ++}; +diff --git a/Documentation/devicetree/bindings/mailbox/arm-smc.yaml b/Documentation/devicetree/bindings/mailbox/arm-smc.yaml +new file mode 100644 +index 000000000..c165946a6 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mailbox/arm-smc.yaml +@@ -0,0 +1,96 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mailbox/arm-smc.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ARM SMC Mailbox Interface ++ ++maintainers: ++ - Peng Fan ++ ++description: | ++ This mailbox uses the ARM smc (secure monitor call) or hvc (hypervisor ++ call) instruction to trigger a mailbox-connected activity in firmware, ++ executing on the very same core as the caller. The value of r0/w0/x0 ++ the firmware returns after the smc call is delivered as a received ++ message to the mailbox framework, so synchronous communication can be ++ established. The exact meaning of the action the mailbox triggers as ++ well as the return value is defined by their users and is not subject ++ to this binding. ++ ++ One example use case of this mailbox is the SCMI interface, which uses ++ shared memory to transfer commands and parameters, and a mailbox to ++ trigger a function call. This allows SoCs without a separate management ++ processor (or when such a processor is not available or used) to use ++ this standardized interface anyway. ++ ++ This binding describes no hardware, but establishes a firmware interface. ++ Upon receiving an SMC using the described SMC function identifier, the ++ firmware is expected to trigger some mailbox connected functionality. ++ The communication follows the ARM SMC calling convention. ++ Firmware expects an SMC function identifier in r0 or w0. The supported ++ identifier is listed in the the arm,func-id property as described below. ++ The firmware can return one value in the first SMC result register, ++ it is expected to be an error value, which shall be propagated to the ++ mailbox client. ++ ++ Any core which supports the SMC or HVC instruction can be used, as long ++ as a firmware component running in EL3 or EL2 is handling these calls. ++ ++properties: ++ compatible: ++ oneOf: ++ - description: ++ For implementations using ARM SMC instruction. ++ const: arm,smc-mbox ++ ++ - description: ++ For implementations using ARM HVC instruction. ++ const: arm,hvc-mbox ++ ++ "#mbox-cells": ++ const: 0 ++ ++ arm,func-id: ++ description: | ++ An single 32-bit value specifying the function ID used by the mailbox. ++ The function ID follows the ARM SMC calling convention standard. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ ++required: ++ - compatible ++ - "#mbox-cells" ++ - arm,func-id ++ ++examples: ++ - | ++ sram@93f000 { ++ compatible = "mmio-sram"; ++ reg = <0x0 0x93f000 0x0 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x93f000 0x1000>; ++ ++ cpu_scp_lpri: scp-shmem@0 { ++ compatible = "arm,scmi-shmem"; ++ reg = <0x0 0x200>; ++ }; ++ }; ++ ++ smc_tx_mbox: tx_mbox { ++ #mbox-cells = <0>; ++ compatible = "arm,smc-mbox"; ++ arm,func-id = <0xc20000fe>; ++ }; ++ ++ firmware { ++ scmi { ++ compatible = "arm,scmi"; ++ mboxes = <&smc_tx_mbox>; ++ mbox-names = "tx"; ++ shmem = <&cpu_scp_lpri>; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt +index 1d2b7fee7..139c06a94 100644 +--- a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt ++++ b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt +@@ -14,9 +14,9 @@ Required properties: + property. Must contain the following entries: + - "rx" + - "tx" +- - "wakeup" + - interrupts: Interrupt specifiers for "rx channel occupied", "tx channel +- free" and "system wakeup". ++ free". If "wakeup-source" is set the rx interrupt is the ++ one used to wake up the system. + - #mbox-cells: Number of cells required for the mailbox specifier. Must be 1. + The data contained in the mbox specifier of the "mboxes" + property in the client node is the mailbox channel index. +diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt +index f884ada0b..aff685a25 100644 +--- a/Documentation/devicetree/bindings/media/video-interfaces.txt ++++ b/Documentation/devicetree/bindings/media/video-interfaces.txt +@@ -149,6 +149,8 @@ Optional endpoint properties + as 0 (normal). This property is valid for serial busses only. + - strobe: Whether the clock signal is used as clock (0) or strobe (1). Used + with CCP2, for instance. ++- pclk-max-frequency: maximum pixel clock frequency admissible by video ++ host interface. + + Example + ------- +diff --git a/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt +new file mode 100644 +index 000000000..eb622387b +--- /dev/null ++++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt +@@ -0,0 +1,57 @@ ++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> ++- wakeup-gpios: contains a list of GPIO spec describing each wake-up pin. ++ ++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>; ++ ++ wakeup-gpios = <&gpioa 0 0>, <&gpioa 2 0>, ++ <&gpioc 13 0>, <&gpioi 8 0>, ++ <&gpioi 11 0>, <&gpioc 1 0>; ++ ++ 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>; ++ wakeup-source; ++ }; ++}; ++ +diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt +index 6d3c626e0..4ec921e4b 100644 +--- a/Documentation/devicetree/bindings/mmc/mmci.txt ++++ b/Documentation/devicetree/bindings/mmc/mmci.txt +@@ -28,6 +28,8 @@ specific for ux500 variant: + - st,sig-pin-fbclk : feedback clock signal pin used. + + specific for sdmmc variant: ++- reg : a second base register may be defined if a delay ++ block is present and used for tuning. + - st,sig-dir : signal direction polarity used for cmd, dat0 dat123. + - st,neg-edge : data & command phase relation, generated on + sd clock falling edge. +diff --git a/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt +new file mode 100644 +index 000000000..7533b8964 +--- /dev/null ++++ b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt +@@ -0,0 +1,18 @@ ++* STM32 DDR Performance Monitor (DDRPERFM) ++ ++Required properties: ++- compatible: must be "st,stm32-ddr-pmu". ++- reg: physical address and length of the registers set. ++- clocks: list of phandles and specifiers to all input clocks listed in ++ clock-names property. ++- clock-names: "bus" corresponds to the DDRPERFM bus clock and "ddr" to ++ the DDR frequency. ++ ++Example: ++ ddrperfm: perf@5a007000 { ++ compatible = "st,stm32-ddr-pmu"; ++ reg = <0x5a007000 0x400>; ++ clocks = <&rcc DDRPERFM>, <&scmi0_clk CK_SCMI0_PLL2_R>; ++ clock-names = "bus", "ddr"; ++ }; ++ +diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt +index 725ae71ae..156229b2e 100644 +--- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt ++++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt +@@ -23,8 +23,11 @@ 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 + - #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 +37,82 @@ 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>; + #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/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +index 400df2da0..4e24a8e86 100644 +--- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +@@ -144,9 +144,13 @@ patternProperties: + * ... + * 16 : Alternate Function 15 + * 17 : Analog ++ * 18 : Reserved + To simplify the usage, macro is available to generate "pinmux" field. + This macro is available here: + - include/dt-bindings/pinctrl/stm32-pinfunc.h ++ Setting the pinmux's function to the Reserved (RSVD) value is used to inform ++ the driver that it shall not apply the mux setting. This can be used to ++ reserve some pins, for example to a co-processor not running Linux. + Some examples of using macro: + /* GPIO A9 set as alernate function 2 */ + ... { +@@ -160,6 +164,10 @@ patternProperties: + ... { + pinmux = ; + }; ++ /* GPIO A9 reserved for co-processor */ ++ ... { ++ pinmux = ; ++ }; + + bias-disable: + type: boolean +diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt +index a8690bfa5..f1620c1fe 100644 +--- a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt ++++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt +@@ -5,8 +5,9 @@ See ../mfd/stm32-timers.txt for details about the parent node. + + Required parameters: + - compatible: Must be "st,stm32-pwm". +-- pinctrl-names: Set to "default". +-- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. ++- pinctrl-names: Set to "default". An additional "sleep" state can be ++ defined to set pins in sleep state when in low power. ++- pinctrl-n: List of phandles pointing to pin configuration nodes for PWM module. + For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt + - #pwm-cells: Should be set to 3. This PWM chip uses the default 3 cells + bindings defined in pwm.txt. +@@ -32,7 +33,8 @@ Example: + compatible = "st,stm32-pwm"; + #pwm-cells = <3>; + pinctrl-0 = <&pwm1_pins>; +- pinctrl-names = "default"; ++ pinctrl-1 = <&pwm1_sleep_pins>; ++ pinctrl-names = "default", "sleep"; + st,breakinput = <0 1 5>; + }; + }; +diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt +new file mode 100644 +index 000000000..baa6e8e13 +--- /dev/null ++++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt +@@ -0,0 +1,58 @@ ++Remoteproc System Resource Manager ++---------------------------------- ++ ++The remoteproc SRM (System Resource Manager) handles resources allocated ++to remote processors. ++This makes it possible for remote proc to reserve and initialize system ++resources for a peripheral assigned to a coprocessor. ++ ++The devices are grouped in a core node ++ ++Core ++==== ++Required properties: ++- compatible: should be "rproc-srm-core" ++ ++Dev ++=== ++Required properties: ++- compatible: should be "rproc-srm-dev" ++ ++Optional properties: ++- reg: register base address and length ++- clocks: clocks required by the coprocessor ++- clock-names: see clock-bindings.txt ++- pinctrl-0: pins configurations required by the coprocessor ++ The SRM reserves the pins for the coprocessor, which prevents the local ++ processor to use them. ++- pinctrl-names: must be "default". ++- x-supply: power supplies required by the coprocessor ++- interrupts: external interrupts configurations required by the coprocessor. ++ This is optional since the configuration is done by the coprocessor. ++ When defined, the SRM (over)writes the configuration which allows the ++ interrupt controller to check for configuration conflicts. ++- interrupt-parent: see interrupts.txt ++- interrupt-names: see interrupts.txt ++ ++Example: ++ system_resources { ++ compatible = "rproc-srm-core"; ++ ++ mmc0: sdhci@09060000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x09060000 0x100>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pinctrl_mmc0>; ++ clock-names = "mmc", "icn"; ++ clocks = <&clk_s_c0_flexgen CLK_MMC_0>, ++ <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; ++ vdda-supply = <&vdda>; ++ }; ++ ++ button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <5 1>; ++ interrupt-names = "gpio_key"; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt +index 5fa915a4b..1188d22bd 100644 +--- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt ++++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt +@@ -21,6 +21,9 @@ Required properties: + + Optional properties: + - interrupts: Should contain the watchdog interrupt ++- wakeup-source: Flag indicating whether remoteproc can wake up the system by ++ the watchdog interrupt. Only meaningful if the "interrupts" ++ property is defined. + - mboxes: This property is required only if the rpmsg/virtio functionality + is used. List of phandle and mailbox channel specifiers: + - a channel (a) used to communicate through virtqueues with the +@@ -48,6 +51,16 @@ Optional properties: + 1st cell: phandle to syscon block + 2nd cell: register offset containing the deep sleep setting + 3rd cell: register bitmask for the deep sleep bit ++- st,syscfg-rsc-tbl: Reference to the system configuration controlling the ++ resource table address loaded by the bootloader ++ 1st cell: phandle to syscon block ++ 2nd cell: register offset containing the resource table address ++ 3rd cell: register bitmask for the resource table address ++- st,syscfg-copro-state: Reference to the system configuration which returns the ++ coprocessor state. ++ 1st cell: phandle to syscon block ++ 2nd cell: register offset containing the coprocessor state ++ 3rd cell: register bitmask for the coprocessor state + - st,auto-boot: If defined, when remoteproc is probed, it loads the default + firmware and starts the remote processor. + +diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt +index 130ca5b98..bab0df81a 100644 +--- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt ++++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt +@@ -21,9 +21,14 @@ Required properties: + domain (RTC registers) write protection. + It is required on stm32(f4/f7/h7). + +-Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): ++Optional properties: ++* to override default rtc_ck parent clock on stm32(f4/f7/h7): + - assigned-clocks: reference to the rtc_ck clock entry. + - assigned-clock-parents: phandle of the new parent clock of rtc_ck. ++* to select and enable RTC Low Speed Clock Output on stm32mp1: ++- st,lsco: defines the RTC output on which RTC Low-Speed Clock is Output. The ++ valid output values are defined in . ++- pinctrl state named "default" may be defined to reserve pin for RTC output. + + Example: + +@@ -58,4 +63,7 @@ Example: + clock-names = "pclk", "rtc_ck"; + interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, + <&exti 19 1>; ++ st,lsco = ; ++ pinctrl-0 = <&rtc_out2_rmp_pins_a>; ++ pinctrl-names = "default"; + }; +diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +index 8620f7fcb..8b032ac3b 100644 +--- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt ++++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +@@ -1,7 +1,7 @@ + * STMicroelectronics STM32 USART + + Required properties: +-- compatible: can be either: ++- compatible: Can be either: + - "st,stm32-uart", + - "st,stm32f7-uart", + - "st,stm32h7-uart". +@@ -9,22 +9,43 @@ Required properties: + - reg: The address and length of the peripheral registers space + - interrupts: + - The interrupt line for the USART instance, +- - An optional wake-up interrupt. + - clocks: The input clock of the USART instance + + Optional properties: + - resets: Must contain the phandle to the reset controller. +-- pinctrl: The reference on the pins configuration +-- st,hw-flow-ctrl: bool flag to enable hardware flow control. ++- 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. ++- pinctrl-n: Phandle(s) pointing to pin configuration nodes. ++ For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt ++- uart-has-rtscts: See description in serial.txt binding. + - 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 ++ 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, if optional wake-up interrupt is used, should be: +- - "event": the name for the interrupt line of the USART instance +- - "wakeup" the name for the optional wake-up interrupt ++- wakeup-source: Bool flag to indicate this device has wakeup capabilities + ++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 { +@@ -32,8 +53,11 @@ usart4: serial@40004c00 { + reg = <0x40004c00 0x400>; + interrupts = <52>; + clocks = <&clk_pclk1>; +- pinctrl-names = "default"; ++ pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&pinctrl_usart4>; ++ pinctrl-1 = <&pinctrl_usart4_sleep>; ++ pinctrl-2 = <&pinctrl_usart4_idle>; ++ pinctrl-3 = <&pinctrl_usart4>; + }; + + usart2: serial@40004400 { +diff --git a/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt +new file mode 100644 +index 000000000..e2bd82f49 +--- /dev/null ++++ b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt +@@ -0,0 +1,39 @@ ++STM32 - STM32MP1- HDP Pin configuration for STM32MP1 ++======================================================= ++ ++The Hardware Debug Port (HDP) allows the observation of internal signals. By using multiplexers, ++up to 16 signals for each of 8-bit output can be observed. ++ ++Required Properties: ++ ++ - compatible: Must be "st,stm32mp1-hdp" ++ - muxing-hdp: Indicates for each HDP pins selected which HDP output among the 16 available signals you want ++ ++For each HDP pins you can select one of 16 signals which will be described in file : include/dt-bindings/soc/stm32-hdp.h ++ ++Example ++------- ++ ++In common dtsi file: ++ ++hdp: hdp@5002a000 { ++ compatible = "st,stm32mp1-hdp"; ++ reg = <0x5002a000 0x400>; ++ clocks = <&rcc HDP>; ++ clock-names = "hdp"; ++}; ++ ++In board-specific file: ++ ++In this example I've selected HDP0, HDP6 and HDP7, and for HDP0 the output signal is HDP0_GPOVAL_0, ++for HDP6 is HDP6_GPOVAL_6, and for HDP7 is HDP7_GPOVAL_7. ++ ++&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>; ++ ++ muxing-hdp = <(STM32_HDP(0, HDP0_GPOVAL_0) | ++ STM32_HDP(6, HDP6_GPOVAL_6) | ++ STM32_HDP(7, HDP7_GPOVAL_7))>; ++}; +diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt +index aafff3a69..1a65303d0 100644 +--- a/Documentation/devicetree/bindings/usb/dwc2.txt ++++ b/Documentation/devicetree/bindings/usb/dwc2.txt +@@ -23,6 +23,9 @@ Required properties: + configured in HS mode; + - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs + configured in HS mode; ++ - "st,stm32mp1-fsotg": The DWC2 USB controller instance in STM32MP1 SoCs, ++ configured in FS mode (using dedicated FS transceiver). ++ - "st,stm32mp1-hsotg": The DWC2 USB controller instance in STM32MP1 SoCs; + - reg : Should contain 1 register range (address and length) + - interrupts : Should contain 1 interrupt + - clocks: clock provider specifier +@@ -46,6 +49,11 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties + on for remote wakeup during suspend. + - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when + we detect a wakeup. This is due to a hardware errata. ++- usb33d-supply: external VBUS and ID sensing comparators supply, in order to ++ perform OTG operation, used on STM32MP1 SoCs. ++- usb-role-switch: use USB Role Switch to support dynamic dual role switch. ++ Refer to usb/generic.txt ++- wakeup-source: bool flag to indicate this device has wakeup capabilities + + Deprecated properties: + - g-use-dma: gadget DMA mode is automatically detected +diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml +index 1ca64c851..b71c15dc8 100644 +--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml ++++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml +@@ -69,6 +69,11 @@ properties: + phy-names: + const: usb + ++ wakeup-source: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Indicate this device has wakeup capabilities. ++ + required: + - compatible + - reg +diff --git a/Documentation/devicetree/bindings/usb/st,typec-stusb.txt b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt +new file mode 100644 +index 000000000..415e14e14 +--- /dev/null ++++ b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt +@@ -0,0 +1,48 @@ ++STMicroelectronics STUSB Type-C Controller family ++ ++Required properties: ++ - compatible: should be "st,stusb1600". ++ - reg: I2C slave address of the device. ++ ++Optional properties: ++ - vdd-supply: main power supply [4.1V;22V]. ++ - vsys-supply: low power supply [3.0V;5.5V]. ++ - vconn-supply: power supply [2.7;5.5V] used to supply VConn on CC pin in ++ source or dual power role. ++ - interrupts: interrupt specifier triggered by ALERT# signal. ++ Please refer to ../interrupt-controller/interrupt.txt ++ - pinctrl state named "default" may be defined to configure pin for #ALERT ++ signal ++ ++USB-C connector attached to STUSB Type-C port controller can be described in ++an optional connector sub-node. Refer to ../connector/usb-connector.txt. ++In case role switch can be used, an optional port sub-node can be added. Refer ++to ../graph.txt. ++ ++Example : ++ ++ typec: stusb1600@28 { ++ compatible = "st,stusb1600"; ++ reg = <0x28>; ++ vdd-supply = <&vbus_drd>; ++ vsys-supply = <&vdd_usb>; ++ interrupts = <11 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-parent = <&gpioi>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&stusb1600_pins_a>; ++ ++ usb_con: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C"; ++ power-role = "dual"; ++ power-opmode = "1.5A"; ++ data-role = "dual"; ++ ++ port { ++ con_usbotg_hs_ep: endpoint { ++ remote-endpoint = <&usbotg_hs_ep>; ++ }; ++ }; ++ }; ++ }; ++ +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index b21b3a646..3f1859094 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -989,9 +989,26 @@ dtb-$(CONFIG_ARCH_STM32) += \ + stm32h743i-disco.dtb \ + stm32mp157a-avenger96.dtb \ + stm32mp157a-dk1.dtb \ ++ stm32mp157d-dk1.dtb \ + stm32mp157c-dk2.dtb \ ++ stm32mp157f-dk2.dtb \ ++ stm32mp157c-dk2-a7-examples.dtb \ ++ stm32mp157c-dk2-m4-examples.dtb \ ++ stm32mp157f-dk2-a7-examples.dtb \ ++ stm32mp157f-dk2-m4-examples.dtb \ ++ stm32mp157a-ed1.dtb \ + stm32mp157c-ed1.dtb \ +- stm32mp157c-ev1.dtb ++ stm32mp157d-ed1.dtb \ ++ stm32mp157f-ed1.dtb \ ++ stm32mp157a-ev1.dtb \ ++ stm32mp157c-ev1.dtb \ ++ stm32mp157d-ev1.dtb \ ++ stm32mp157f-ev1.dtb \ ++ stm32mp157c-ev1-a7-examples.dtb \ ++ stm32mp157c-ev1-m4-examples.dtb \ ++ stm32mp157f-ev1-a7-examples.dtb \ ++ stm32mp157f-ev1-m4-examples.dtb ++ + dtb-$(CONFIG_MACH_SUN4I) += \ + sun4i-a10-a1000.dtb \ + sun4i-a10-ba10-tvbox.dtb \ +diff --git a/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi +new file mode 100644 +index 000000000..3bb96ab8a +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2020 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++/ { ++ ++ clocks { ++ clk_hse: clk-hse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_hsi: clk-hsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <64000000>; ++ }; ++ ++ clk_lse: clk-lse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32768>; ++ }; ++ ++ clk_lsi: clk-lsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32000>; ++ }; ++ ++ clk_csi: clk-csi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <4000000>; ++ }; ++ }; ++ ++ cpus { ++ cpu0: cpu@0 { ++ clocks = <&rcc CK_MPU>; ++ }; ++ ++ cpu1: cpu@1 { ++ clocks = <&rcc CK_MPU>; ++ }; ++ }; ++ ++ soc { ++ m_can1: can@4400e000 { ++ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ }; ++ ++ m_can2: can@4400f000 { ++ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ }; ++ ++ cryp1: cryp@54001000 { ++ clocks = <&rcc CRYP1>; ++ resets = <&rcc CRYP1_R>; ++ }; ++ }; ++ ++ mlahb { ++ m4_rproc: m4@10000000 { ++ resets = <&rcc MCU_R>; ++ ++ m4_system_resources { ++ m4_cec: cec@40016000 { ++ clocks = <&rcc CEC_K>, <&rcc CK_LSE>; ++ }; ++ ++ m4_m_can1: can@4400e000 { ++ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ }; ++ ++ m4_m_can2: can@4400f000 { ++ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ }; ++ }; ++ }; ++ }; ++ ++ firmware { ++ /delete-node/ scmi-0; ++ /delete-node/ scmi-1; ++ }; ++ /delete-node/ sram@2ffff000; ++ /delete-node/ mailbox-0; ++ /delete-node/ mailbox-1; ++}; ++ ++&cec { ++ clocks = <&rcc CEC_K>, <&clk_lse>; ++}; ++ ++&ddrperfm { ++ clocks = <&rcc DDRPERFM>, <&rcc PLL2_R>; ++}; ++ ++&dsi { ++ clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>; ++}; ++ ++&gpioz { ++ clocks = <&rcc GPIOZ>; ++}; ++ ++&hash1 { ++ clocks = <&rcc HASH1>; ++ resets = <&rcc HASH1_R>; ++}; ++ ++&i2c4 { ++ clocks = <&rcc I2C4_K>; ++ resets = <&rcc I2C4_R>; ++}; ++ ++&i2c6 { ++ clocks = <&rcc I2C6_K>; ++ resets = <&rcc I2C6_R>; ++}; ++ ++&iwdg2 { ++ clocks = <&rcc IWDG2>, <&rcc CK_LSI>; ++}; ++ ++&mdma1 { ++ clocks = <&rcc MDMA>; ++ resets = <&rcc MDMA_R>; ++}; ++ ++&rcc { ++ compatible = "st,stm32mp1-rcc", "syscon"; ++ clocks = <&clk_hse>, <&clk_hsi>, <&clk_csi>, <&clk_lse>, <&clk_lsi>; ++}; ++ ++&rng1 { ++ clocks = <&rcc RNG1_K>; ++ resets = <&rcc RNG1_R>; ++}; ++ ++&rtc { ++ clocks = <&rcc RTCAPB>, <&rcc RTC>; ++}; ++ ++&spi6 { ++ clocks = <&rcc SPI6_K>; ++ resets = <&rcc SPI6_R>; ++}; ++ ++&usart1 { ++ clocks = <&rcc USART1_K>; ++ resets = <&rcc USART1_R>; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +new file mode 100644 +index 000000000..38c792694 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +@@ -0,0 +1,1411 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++#include ++ ++&pinctrl { ++ 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_cc_pins_a: adc12-usb-cc-pins-0 { ++ pins { ++ pinmux = , /* ADC12 in18 */ ++ ; /* ADC12 in19 */ ++ }; ++ }; ++ ++ cec_pins_a: cec-0 { ++ pins { ++ pinmux = ; ++ bias-disable; ++ drive-open-drain; ++ 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 = <0>; ++ }; ++ }; ++ ++ 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_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 */ ++ , /* 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 */ ++ }; ++ }; ++ ++ 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 */ ++ }; ++ }; ++ ++ 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 */ ++ }; ++ }; ++ ++ 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 */ ++ }; ++ }; ++ ++ i2c1_pins_b: i2c1-2 { ++ pins { ++ pinmux = , /* I2C1_SCL */ ++ ; /* I2C1_SDA */ ++ bias-disable; ++ drive-open-drain; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ i2c1_pins_sleep_b: i2c1-3 { ++ 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 */ ++ }; ++ }; ++ ++ i2c2_pins_b1: i2c2-2 { ++ pins { ++ pinmux = ; /* I2C2_SDA */ ++ bias-disable; ++ drive-open-drain; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ i2c2_pins_sleep_b1: i2c2-3 { ++ pins { ++ pinmux = ; /* 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 = <1>; ++ 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_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 */ ++ }; ++ }; ++ ++ 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 */ ++ }; ++ }; ++ ++ 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; ++ }; ++ }; ++ ++ sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { ++ pins { ++ pinmux = , /* SDMMC1_D0 */ ++ , /* SDMMC1_D1 */ ++ , /* SDMMC1_D2 */ ++ , /* SDMMC1_D3 */ ++ , /* SDMMC1_CK */ ++ ; /* SDMMC1_CMD */ ++ }; ++ }; ++ ++ 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 = , /* 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; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 { ++ pins { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ , /* SDMMC2_CK */ ++ ; /* SDMMC2_CMD */ ++ }; ++ }; ++ ++ 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 */ ++ , /* SDMMC2_D5 */ ++ , /* SDMMC2_D6 */ ++ ; /* SDMMC2_D7 */ ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdmmc2_d47_sleep_pins_a: sdmmc2-d47-sleep-0 { ++ pins { ++ 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; ++ bias-pull-up; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC3_CK */ ++ slew-rate = <2>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ }; ++ ++ 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; ++ 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; ++ }; ++ }; ++ ++ sdmmc3_b4_sleep_pins_a: sdmmc3-b4-sleep-0 { ++ pins { ++ pinmux = , /* SDMMC3_D0 */ ++ , /* SDMMC3_D1 */ ++ , /* SDMMC3_D2 */ ++ , /* SDMMC3_D3 */ ++ , /* SDMMC3_CK */ ++ ; /* SDMMC3_CMD */ ++ }; ++ }; ++ ++ spdifrx_pins_a: spdifrx-0 { ++ pins { ++ pinmux = ; /* SPDIF_IN1 */ ++ bias-disable; ++ }; ++ }; ++ ++ spdifrx_sleep_pins_a: spdifrx-1 { ++ pins { ++ pinmux = ; /* SPDIF_IN1 */ ++ }; ++ }; ++ ++ spi4_pins_a: spi4-0 { ++ pins1 { ++ pinmux = , /* SPI4_SCK */ ++ ; /* SPI4_MOSI */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ ++ pins2 { ++ pinmux = ; /* SPI4_MISO */ ++ bias-disable; ++ }; ++ }; ++ ++ spi4_sleep_pins_a: spi4-sleep-0 { ++ pins { ++ pinmux = , /* SPI4_SCK */ ++ , /* SPI4_MISO */ ++ ; /* SPI4_MOSI */ ++ }; ++ }; ++ ++ spi5_pins_a: spi5-0 { ++ pins1 { ++ pinmux = , /* SPI5_SCK */ ++ ; /* SPI5_MOSI */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ ++ pins2 { ++ pinmux = ; /* SPI5_MISO */ ++ bias-disable; ++ }; ++ }; ++ ++ spi5_sleep_pins_a: spi5-sleep-0 { ++ pins { ++ pinmux = , /* SPI5_SCK */ ++ , /* SPI5_MISO */ ++ ; /* SPI5_MOSI */ ++ }; ++ }; ++ ++ stusb1600_pins_a: stusb1600-0 { ++ pins { ++ pinmux = ; ++ bias-pull-up; ++ }; ++ }; ++ ++ 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; ++ }; ++ }; ++ ++ uart4_sleep_pins_a: uart4-sleep-0 { ++ pins { ++ pinmux = , /* UART4_TX */ ++ ; /* UART4_RX */ ++ }; ++ }; ++ ++ uart4_pins_b: uart4-1 { ++ pins1 { ++ pinmux = ; /* UART4_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = ; /* UART4_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ uart7_pins_a: uart7-0 { ++ pins1 { ++ pinmux = ; /* UART4_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = , /* UART4_RX */ ++ , /* UART4_CTS */ ++ ; /* UART4_RTS */ ++ bias-disable; ++ }; ++ }; ++ ++ uart7_pins_b: uart7-1 { ++ pins1 { ++ pinmux = ; /* USART7_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = ; /* USART7_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ uart7_idle_pins_b: uart7-idle-1 { ++ pins1 { ++ pinmux = ; /* USART7_TX */ ++ }; ++ pins2 { ++ pinmux = ; /* USART7_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ uart7_sleep_pins_b: uart7-sleep-1 { ++ pins { ++ pinmux = , /* USART7_TX */ ++ ; /* USART7_RX */ ++ }; ++ }; ++ ++ usart2_pins_a: usart2-0 { ++ pins1 { ++ pinmux = , /* USART2_TX */ ++ ; /* USART2_RTS */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <3>; ++ }; ++ 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; ++ }; ++ }; ++ ++ usart2_sleep_pins_a: usart2-sleep-0 { ++ pins { ++ 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; ++ 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; ++ }; ++ }; ++ ++ usart3_sleep_pins_a: usart3-sleep-0 { ++ pins { ++ pinmux = , /* USART3_TX */ ++ , /* USART3_RTS */ ++ , /* USART3_CTS_NSS */ ++ ; /* USART3_RX */ ++ }; ++ }; ++ ++ usart3_pins_b: usart3-1 { ++ pins1 { ++ pinmux = , /* USART3_TX */ ++ ; /* USART3_RTS */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ 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 { ++ i2c2_pins_b2: i2c2-0 { ++ pins { ++ pinmux = ; /* I2C2_SCL */ ++ bias-disable; ++ drive-open-drain; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ i2c2_pins_sleep_b2: i2c2-1 { ++ pins { ++ pinmux = ; /* I2C2_SCL */ ++ }; ++ }; ++ ++ i2c4_pins_a: i2c4-0 { ++ pins { ++ pinmux = , /* I2C4_SCL */ ++ ; /* I2C4_SDA */ ++ bias-disable; ++ drive-open-drain; ++ 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/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi +similarity index 59% +rename from arch/arm/boot/dts/stm32mp157c.dtsi +rename to arch/arm/boot/dts/stm32mp151.dtsi +index f98e0370c..c516e2ed0 100644 +--- a/arch/arm/boot/dts/stm32mp157c.dtsi ++++ b/arch/arm/boot/dts/stm32mp151.dtsi +@@ -5,7 +5,10 @@ + */ + #include + #include ++#include + #include ++#include ++ + + / { + #address-cells = <1>; +@@ -19,20 +22,101 @@ + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; ++ clocks = <&scmi0_clk CK_SCMI0_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ nvmem-cells = <&part_number_otp>; ++ nvmem-cell-names = "part_number"; ++ #cooling-cells = <2>; + }; ++ }; + +- cpu1: cpu@1 { +- compatible = "arm,cortex-a7"; +- device_type = "cpu"; +- reg = <1>; ++ cpu0_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupts = ; ++ interrupt-affinity = <&cpu0>; ++ interrupt-parent = <&intc>; ++ }; ++ ++ scmi_sram: sram@2ffff000 { ++ compatible = "mmio-sram"; ++ reg = <0x2ffff000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x2ffff000 0x1000>; ++ ++ scmi0_shm: scmi_shm@0 { ++ reg = <0 0x80>; ++ }; ++ ++ scmi1_shm: scmi_shm@200 { ++ reg = <0x200 0x80>; ++ }; ++ }; ++ ++ scmi0_mbox: mailbox-0 { ++ #mbox-cells = <0>; ++ compatible = "arm,smc-mbox"; ++ arm,func-id = <0x82002000>; ++ }; ++ ++ scmi1_mbox: mailbox-1 { ++ #mbox-cells = <0>; ++ compatible = "arm,smc-mbox"; ++ arm,func-id = <0x82002001>; ++ }; ++ ++ firmware { ++ scmi0: scmi-0 { ++ compatible = "arm,scmi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mboxes = <&scmi0_mbox 0>; ++ mbox-names = "txrx"; ++ shmem = <&scmi0_shm>; ++ ++ scmi0_clk: protocol@14 { ++ reg = <0x14>; ++ #clock-cells = <1>; ++ }; ++ scmi0_reset: protocol@16 { ++ reg = <0x16>; ++ #reset-cells = <1>; ++ }; ++ }; ++ ++ scmi1: scmi-1 { ++ compatible = "arm,scmi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ mboxes = <&scmi1_mbox 0>; ++ mbox-names = "txrx"; ++ shmem = <&scmi1_shm>; ++ ++ scmi1_clk: protocol@14 { ++ reg = <0x14>; ++ #clock-cells = <1>; ++ }; ++ }; ++ ++ optee: optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ status = "disabled"; + }; + }; + + psci { +- compatible = "arm,psci"; ++ compatible = "arm,psci-1.0"; + method = "smc"; +- cpu_off = <0x84000002>; +- cpu_on = <0x84000003>; + }; + + intc: interrupt-controller@a0021000 { +@@ -50,38 +134,7 @@ + , + ; + interrupt-parent = <&intc>; +- }; +- +- clocks { +- clk_hse: clk-hse { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <24000000>; +- }; +- +- clk_hsi: clk-hsi { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <64000000>; +- }; +- +- clk_lse: clk-lse { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <32768>; +- }; +- +- clk_lsi: clk-lsi { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <32000>; +- }; +- +- clk_csi: clk-csi { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <4000000>; +- }; ++ always-on; + }; + + thermal-zones { +@@ -91,12 +144,6 @@ + thermal-sensors = <&dts>; + + trips { +- cpu_alert1: cpu-alert1 { +- temperature = <85000>; +- hysteresis = <0>; +- type = "passive"; +- }; +- + cpu-crit { + temperature = <120000>; + hysteresis = <0>; +@@ -115,6 +162,33 @@ + status = "disabled"; + }; + ++ pm_domain { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32mp157c-pd"; ++ ++ pd_core_ret: core-ret-power-domain@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ #power-domain-cells = <0>; ++ label = "CORE-RETENTION"; ++ ++ pd_core: core-power-domain@2 { ++ reg = <2>; ++ #power-domain-cells = <0>; ++ label = "CORE"; ++ }; ++ }; ++ }; ++ ++ reboot { ++ compatible = "syscon-reboot"; ++ regmap = <&rcc>; ++ offset = <0x404>; ++ mask = <0x1>; ++ }; ++ + soc { + compatible = "simple-bus"; + #address-cells = <1>; +@@ -122,6 +196,14 @@ + interrupt-parent = <&intc>; + ranges; + ++ sram: sram@10000000 { ++ compatible = "mmio-sram"; ++ reg = <0x10000000 0x60000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x10000000 0x60000>; ++ }; ++ + timers2: timer@40000000 { + #address-cells = <1>; + #size-cells = <0>; +@@ -129,11 +211,11 @@ + reg = <0x40000000 0x400>; + clocks = <&rcc TIM2_K>; + clock-names = "int"; +- dmas = <&dmamux1 18 0x400 0x1>, +- <&dmamux1 19 0x400 0x1>, +- <&dmamux1 20 0x400 0x1>, +- <&dmamux1 21 0x400 0x1>, +- <&dmamux1 22 0x400 0x1>; ++ dmas = <&dmamux1 18 0x400 0x80000001>, ++ <&dmamux1 19 0x400 0x80000001>, ++ <&dmamux1 20 0x400 0x80000001>, ++ <&dmamux1 21 0x400 0x80000001>, ++ <&dmamux1 22 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up"; + status = "disabled"; + +@@ -148,6 +230,11 @@ + reg = <1>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + timers3: timer@40001000 { +@@ -157,12 +244,12 @@ + reg = <0x40001000 0x400>; + clocks = <&rcc TIM3_K>; + clock-names = "int"; +- dmas = <&dmamux1 23 0x400 0x1>, +- <&dmamux1 24 0x400 0x1>, +- <&dmamux1 25 0x400 0x1>, +- <&dmamux1 26 0x400 0x1>, +- <&dmamux1 27 0x400 0x1>, +- <&dmamux1 28 0x400 0x1>; ++ dmas = <&dmamux1 23 0x400 0x80000001>, ++ <&dmamux1 24 0x400 0x80000001>, ++ <&dmamux1 25 0x400 0x80000001>, ++ <&dmamux1 26 0x400 0x80000001>, ++ <&dmamux1 27 0x400 0x80000001>, ++ <&dmamux1 28 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; + status = "disabled"; + +@@ -177,6 +264,11 @@ + reg = <2>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + timers4: timer@40002000 { +@@ -186,10 +278,10 @@ + reg = <0x40002000 0x400>; + clocks = <&rcc TIM4_K>; + clock-names = "int"; +- dmas = <&dmamux1 29 0x400 0x1>, +- <&dmamux1 30 0x400 0x1>, +- <&dmamux1 31 0x400 0x1>, +- <&dmamux1 32 0x400 0x1>; ++ dmas = <&dmamux1 29 0x400 0x80000001>, ++ <&dmamux1 30 0x400 0x80000001>, ++ <&dmamux1 31 0x400 0x80000001>, ++ <&dmamux1 32 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4"; + status = "disabled"; + +@@ -204,6 +296,11 @@ + reg = <3>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + timers5: timer@40003000 { +@@ -213,12 +310,12 @@ + reg = <0x40003000 0x400>; + clocks = <&rcc TIM5_K>; + clock-names = "int"; +- dmas = <&dmamux1 55 0x400 0x1>, +- <&dmamux1 56 0x400 0x1>, +- <&dmamux1 57 0x400 0x1>, +- <&dmamux1 58 0x400 0x1>, +- <&dmamux1 59 0x400 0x1>, +- <&dmamux1 60 0x400 0x1>; ++ dmas = <&dmamux1 55 0x400 0x80000001>, ++ <&dmamux1 56 0x400 0x80000001>, ++ <&dmamux1 57 0x400 0x80000001>, ++ <&dmamux1 58 0x400 0x80000001>, ++ <&dmamux1 59 0x400 0x80000001>, ++ <&dmamux1 60 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; + status = "disabled"; + +@@ -233,6 +330,11 @@ + reg = <4>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + timers6: timer@40004000 { +@@ -242,7 +344,7 @@ + reg = <0x40004000 0x400>; + clocks = <&rcc TIM6_K>; + clock-names = "int"; +- dmas = <&dmamux1 69 0x400 0x1>; ++ dmas = <&dmamux1 69 0x400 0x80000001>; + dma-names = "up"; + status = "disabled"; + +@@ -260,7 +362,7 @@ + reg = <0x40005000 0x400>; + clocks = <&rcc TIM7_K>; + clock-names = "int"; +- dmas = <&dmamux1 70 0x400 0x1>; ++ dmas = <&dmamux1 70 0x400 0x80000001>; + dma-names = "up"; + status = "disabled"; + +@@ -372,9 +474,10 @@ + 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"; + }; + +@@ -397,9 +500,10 @@ + 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"; + }; + +@@ -430,84 +534,132 @@ + usart2: serial@4000e000 { + compatible = "st,stm32h7-uart"; + reg = <0x4000e000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc USART2_K>; ++ resets = <&rcc USART2_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 43 0x400 0x5>, ++ <&dmamux1 44 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + usart3: serial@4000f000 { + compatible = "st,stm32h7-uart"; + reg = <0x4000f000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc USART3_K>; ++ resets = <&rcc USART3_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 45 0x400 0x5>, ++ <&dmamux1 46 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart4: serial@40010000 { + compatible = "st,stm32h7-uart"; + reg = <0x40010000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc UART4_K>; ++ resets = <&rcc UART4_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 63 0x400 0x5>, ++ <&dmamux1 64 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart5: serial@40011000 { + compatible = "st,stm32h7-uart"; + reg = <0x40011000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc UART5_K>; ++ resets = <&rcc UART5_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 65 0x400 0x5>, ++ <&dmamux1 66 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + i2c1: i2c@40012000 { +- compatible = "st,stm32f7-i2c"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x40012000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; ++ interrupts-extended = <&exti 21 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc I2C1_K>; + resets = <&rcc I2C1_R>; + #address-cells = <1>; + #size-cells = <0>; ++ dmas = <&dmamux1 33 0x400 0x80000001>, ++ <&dmamux1 34 0x400 0x80000001>; ++ dma-names = "rx", "tx"; ++ power-domains = <&pd_core>; ++ st,syscfg-fmp = <&syscfg 0x4 0x1>; ++ wakeup-source; + status = "disabled"; + }; + + i2c2: i2c@40013000 { +- compatible = "st,stm32f7-i2c"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x40013000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; ++ interrupts-extended = <&exti 22 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc I2C2_K>; + resets = <&rcc I2C2_R>; + #address-cells = <1>; + #size-cells = <0>; ++ dmas = <&dmamux1 35 0x400 0x80000001>, ++ <&dmamux1 36 0x400 0x80000001>; ++ dma-names = "rx", "tx"; ++ power-domains = <&pd_core>; ++ st,syscfg-fmp = <&syscfg 0x4 0x2>; ++ wakeup-source; + status = "disabled"; + }; + + i2c3: i2c@40014000 { +- compatible = "st,stm32f7-i2c"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x40014000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; ++ interrupts-extended = <&exti 23 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc I2C3_K>; + resets = <&rcc I2C3_R>; + #address-cells = <1>; + #size-cells = <0>; ++ dmas = <&dmamux1 73 0x400 0x80000001>, ++ <&dmamux1 74 0x400 0x80000001>; ++ dma-names = "rx", "tx"; ++ power-domains = <&pd_core>; ++ st,syscfg-fmp = <&syscfg 0x4 0x4>; ++ wakeup-source; + status = "disabled"; + }; + + i2c5: i2c@40015000 { +- compatible = "st,stm32f7-i2c"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x40015000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; ++ interrupts-extended = <&exti 25 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc I2C5_K>; + resets = <&rcc I2C5_R>; + #address-cells = <1>; + #size-cells = <0>; ++ dmas = <&dmamux1 115 0x400 0x80000001>, ++ <&dmamux1 116 0x400 0x80000001>; ++ dma-names = "rx", "tx"; ++ power-domains = <&pd_core>; ++ st,syscfg-fmp = <&syscfg 0x4 0x10>; ++ wakeup-source; + status = "disabled"; + }; + +@@ -515,7 +667,7 @@ + compatible = "st,stm32-cec"; + reg = <0x40016000 0x400>; + interrupts = ; +- clocks = <&rcc CEC_K>, <&clk_lse>; ++ clocks = <&rcc CEC_K>, <&scmi0_clk CK_SCMI0_LSE>; + clock-names = "cec", "hdmi-cec"; + status = "disabled"; + }; +@@ -531,14 +683,14 @@ + + dac1: dac@1 { + compatible = "st,stm32-dac"; +- #io-channels-cells = <1>; ++ #io-channel-cells = <1>; + reg = <1>; + status = "disabled"; + }; + + dac2: dac@2 { + compatible = "st,stm32-dac"; +- #io-channels-cells = <1>; ++ #io-channel-cells = <1>; + reg = <2>; + status = "disabled"; + }; +@@ -547,16 +699,28 @@ + uart7: serial@40018000 { + compatible = "st,stm32h7-uart"; + reg = <0x40018000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc UART7_K>; ++ resets = <&rcc UART7_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 79 0x400 0x5>, ++ <&dmamux1 80 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart8: serial@40019000 { + compatible = "st,stm32h7-uart"; + reg = <0x40019000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 33 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc UART8_K>; ++ resets = <&rcc UART8_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 81 0x400 0x5>, ++ <&dmamux1 82 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -567,13 +731,13 @@ + reg = <0x44000000 0x400>; + clocks = <&rcc TIM1_K>; + clock-names = "int"; +- dmas = <&dmamux1 11 0x400 0x1>, +- <&dmamux1 12 0x400 0x1>, +- <&dmamux1 13 0x400 0x1>, +- <&dmamux1 14 0x400 0x1>, +- <&dmamux1 15 0x400 0x1>, +- <&dmamux1 16 0x400 0x1>, +- <&dmamux1 17 0x400 0x1>; ++ dmas = <&dmamux1 11 0x400 0x80000001>, ++ <&dmamux1 12 0x400 0x80000001>, ++ <&dmamux1 13 0x400 0x80000001>, ++ <&dmamux1 14 0x400 0x80000001>, ++ <&dmamux1 15 0x400 0x80000001>, ++ <&dmamux1 16 0x400 0x80000001>, ++ <&dmamux1 17 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4", + "up", "trig", "com"; + status = "disabled"; +@@ -589,6 +753,11 @@ + reg = <0>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + timers8: timer@44001000 { +@@ -598,13 +767,13 @@ + reg = <0x44001000 0x400>; + clocks = <&rcc TIM8_K>; + clock-names = "int"; +- dmas = <&dmamux1 47 0x400 0x1>, +- <&dmamux1 48 0x400 0x1>, +- <&dmamux1 49 0x400 0x1>, +- <&dmamux1 50 0x400 0x1>, +- <&dmamux1 51 0x400 0x1>, +- <&dmamux1 52 0x400 0x1>, +- <&dmamux1 53 0x400 0x1>; ++ dmas = <&dmamux1 47 0x400 0x80000001>, ++ <&dmamux1 48 0x400 0x80000001>, ++ <&dmamux1 49 0x400 0x80000001>, ++ <&dmamux1 50 0x400 0x80000001>, ++ <&dmamux1 51 0x400 0x80000001>, ++ <&dmamux1 52 0x400 0x80000001>, ++ <&dmamux1 53 0x400 0x80000001>; + dma-names = "ch1", "ch2", "ch3", "ch4", + "up", "trig", "com"; + status = "disabled"; +@@ -620,13 +789,24 @@ + reg = <7>; + status = "disabled"; + }; ++ ++ counter { ++ compatible = "st,stm32-timer-counter"; ++ status = "disabled"; ++ }; + }; + + usart6: serial@44003000 { + compatible = "st,stm32h7-uart"; + reg = <0x44003000 0x400>; +- interrupts = ; ++ interrupts-extended = <&exti 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc USART6_K>; ++ resets = <&rcc USART6_R>; ++ wakeup-source; ++ power-domains = <&pd_core>; ++ dmas = <&dmamux1 71 0x400 0x5>, ++ <&dmamux1 72 0x400 0x1>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -638,9 +818,10 @@ + 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"; + }; + +@@ -663,9 +844,10 @@ + 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"; + }; + +@@ -676,10 +858,10 @@ + reg = <0x44006000 0x400>; + clocks = <&rcc TIM15_K>; + clock-names = "int"; +- dmas = <&dmamux1 105 0x400 0x1>, +- <&dmamux1 106 0x400 0x1>, +- <&dmamux1 107 0x400 0x1>, +- <&dmamux1 108 0x400 0x1>; ++ dmas = <&dmamux1 105 0x400 0x80000001>, ++ <&dmamux1 106 0x400 0x80000001>, ++ <&dmamux1 107 0x400 0x80000001>, ++ <&dmamux1 108 0x400 0x80000001>; + dma-names = "ch1", "up", "trig", "com"; + status = "disabled"; + +@@ -703,8 +885,8 @@ + reg = <0x44007000 0x400>; + clocks = <&rcc TIM16_K>; + clock-names = "int"; +- dmas = <&dmamux1 109 0x400 0x1>, +- <&dmamux1 110 0x400 0x1>; ++ dmas = <&dmamux1 109 0x400 0x80000001>, ++ <&dmamux1 110 0x400 0x80000001>; + dma-names = "ch1", "up"; + status = "disabled"; + +@@ -727,8 +909,8 @@ + reg = <0x44008000 0x400>; + clocks = <&rcc TIM17_K>; + clock-names = "int"; +- dmas = <&dmamux1 111 0x400 0x1>, +- <&dmamux1 112 0x400 0x1>; ++ dmas = <&dmamux1 111 0x400 0x80000001>, ++ <&dmamux1 112 0x400 0x80000001>; + dma-names = "ch1", "up"; + status = "disabled"; + +@@ -753,9 +935,10 @@ + 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"; + }; + +@@ -923,32 +1106,6 @@ + }; + }; + +- 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>; +@@ -961,9 +1118,19 @@ + , + ; + clocks = <&rcc DMA1>; ++ resets = <&rcc DMA1_R>; + #dma-cells = <4>; + st,mem2mem; + dma-requests = <8>; ++ 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"; + }; + + dma2: dma@48001000 { +@@ -978,19 +1145,30 @@ + , + ; + clocks = <&rcc DMA2>; ++ resets = <&rcc DMA2_R>; + #dma-cells = <4>; + st,mem2mem; + dma-requests = <8>; ++ 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"; + }; + + dmamux1: dma-router@48002000 { + compatible = "st,stm32h7-dmamux"; +- reg = <0x48002000 0x1c>; ++ reg = <0x48002000 0x40>; + #dma-cells = <3>; + dma-requests = <128>; + dma-masters = <&dma1 &dma2>; + dma-channels = <16>; + clocks = <&rcc DMAMUX>; ++ resets = <&rcc DMAMUX_R>; + }; + + adc: adc@48003000 { +@@ -1013,7 +1191,7 @@ + reg = <0x0>; + interrupt-parent = <&adc>; + interrupts = <0>; +- dmas = <&dmamux1 9 0x400 0x01>; ++ dmas = <&dmamux1 9 0x400 0x80000001>; + dma-names = "rx"; + status = "disabled"; + }; +@@ -1024,39 +1202,65 @@ + reg = <0x100>; + interrupt-parent = <&adc>; + interrupts = <1>; +- dmas = <&dmamux1 10 0x400 0x01>; ++ dmas = <&dmamux1 10 0x400 0x80000001>; + dma-names = "rx"; + status = "disabled"; + }; + }; + ++ sdmmc3: sdmmc@48004000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x48004000 0x400>, <0x48005000 0x400>; ++ interrupts = ; ++ interrupt-names = "cmd_irq"; ++ clocks = <&rcc SDMMC3_K>; ++ clock-names = "apb_pclk"; ++ resets = <&rcc SDMMC3_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <120000000>; ++ status = "disabled"; ++ }; ++ + usbotg_hs: usb-otg@49000000 { +- compatible = "snps,dwc2"; ++ compatible = "st,stm32mp1-hsotg", "snps,dwc2"; + reg = <0x49000000 0x10000>; + clocks = <&rcc USBO_K>; + clock-names = "otg"; + resets = <&rcc USBO_R>; + reset-names = "dwc2"; +- interrupts = ; +- g-rx-fifo-size = <256>; ++ interrupts-extended = <&exti 44 IRQ_TYPE_LEVEL_HIGH>; ++ 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>; ++ wakeup-source; + status = "disabled"; + }; + ++ hsem: hwspinlock@4c000000 { ++ compatible = "st,stm32-hwspinlock"; ++ #hwlock-cells = <2>; ++ reg = <0x4c000000 0x400>; ++ clocks = <&rcc HSEM>; ++ clock-names = "hsem"; ++ }; ++ + 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"; ++ <&exti 61 1>, ++ <&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "rx", "tx"; + clocks = <&rcc IPCC>; + wakeup-source; ++ power-domains = <&pd_core>; + status = "disabled"; + }; + +@@ -1067,16 +1271,68 @@ + resets = <&rcc CAMITF_R>; + clocks = <&rcc DCMI>; + clock-names = "mclk"; +- dmas = <&dmamux1 75 0x400 0x0d>; ++ dmas = <&dmamux1 75 0x400 0xe0000001>; + dma-names = "tx"; + status = "disabled"; + }; + + rcc: rcc@50000000 { +- compatible = "st,stm32mp1-rcc", "syscon"; ++ compatible = "st,stm32mp1-rcc-secure", "st,stm32mp1-rcc", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; ++ interrupts = ; ++ ++ clock-names = "hse", "hsi", "csi", "lse", "lsi"; ++ clocks = <&scmi0_clk CK_SCMI0_HSE>, ++ <&scmi0_clk CK_SCMI0_HSI>, ++ <&scmi0_clk CK_SCMI0_CSI>, ++ <&scmi0_clk CK_SCMI0_LSE>, ++ <&scmi0_clk CK_SCMI0_LSI>; ++ }; ++ ++ pwr_regulators: pwr@50001000 { ++ compatible = "st,stm32mp1,pwr-reg"; ++ reg = <0x50001000 0x10>; ++ 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>; ++ }; ++ ++ usb33: usb33 { ++ regulator-name = "usb33"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ pwr_mcu: pwr_mcu@50001014 { ++ compatible = "syscon"; ++ reg = <0x50001014 0x4>; ++ }; ++ ++ pwr_irq: pwr@50001020 { ++ compatible = "st,stm32mp1-pwr"; ++ reg = <0x50001020 0x100>; ++ interrupts = ; ++ 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>; + }; + + exti: interrupt-controller@5000d000 { +@@ -1084,6 +1340,18 @@ + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5000d000 0x400>; ++ hwlocks = <&hsem 1 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_irq>; ++ st,irq-number = <6>; ++ }; + }; + + syscfg: syscon@50020000 { +@@ -1219,12 +1487,11 @@ + status = "disabled"; + }; + +- cryp1: cryp@54001000 { +- compatible = "st,stm32mp1-cryp"; +- reg = <0x54001000 0x400>; +- interrupts = ; +- clocks = <&rcc CRYP1>; +- resets = <&rcc CRYP1_R>; ++ hdp: hdp@5002a000 { ++ compatible = "st,stm32mp1-hdp"; ++ reg = <0x5002a000 0x400>; ++ clocks = <&rcc HDP>; ++ clock-names = "hdp"; + status = "disabled"; + }; + +@@ -1232,9 +1499,9 @@ + compatible = "st,stm32f756-hash"; + reg = <0x54002000 0x400>; + interrupts = ; +- clocks = <&rcc HASH1>; +- resets = <&rcc HASH1_R>; +- dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0>; ++ clocks = <&scmi0_clk CK_SCMI0_HASH1>; ++ resets = <&scmi0_reset RST_SCMI0_HASH1>; ++ dmas = <&mdma1 31 0x2 0x1000A02 0x0 0x0 0x0>; + dma-names = "in"; + dma-maxburst = <2>; + status = "disabled"; +@@ -1243,8 +1510,8 @@ + rng1: rng@54003000 { + compatible = "st,stm32-rng"; + reg = <0x54003000 0x400>; +- clocks = <&rcc RNG1_K>; +- resets = <&rcc RNG1_R>; ++ clocks = <&scmi0_clk CK_SCMI0_RNG1>; ++ resets = <&scmi0_reset RST_SCMI0_RNG1>; + status = "disabled"; + }; + +@@ -1253,7 +1520,8 @@ + reg = <0x58000000 0x1000>; + interrupts = ; + clocks = <&rcc MDMA>; +- #dma-cells = <5>; ++ resets = <&scmi0_reset RST_SCMI0_MDMA>; ++ #dma-cells = <6>; + dma-channels = <32>; + dma-requests = <48>; + }; +@@ -1268,9 +1536,9 @@ + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; +- dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>, +- <&mdma1 20 0x10 0x12000a08 0x0 0x0>, +- <&mdma1 21 0x10 0x12000a0a 0x0 0x0>; ++ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0 0x0>, ++ <&mdma1 20 0x2 0x12000a08 0x0 0x0 0x0>, ++ <&mdma1 21 0x2 0x12000a0a 0x0 0x0 0x0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; +@@ -1282,8 +1550,8 @@ + reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = ; +- dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>, +- <&mdma1 22 0x10 0x100008 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>; +@@ -1292,16 +1560,32 @@ + + sdmmc1: sdmmc@58005000 { + compatible = "arm,pl18x", "arm,primecell"; +- arm,primecell-periphid = <0x10153180>; +- reg = <0x58005000 0x1000>; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x58005000 0x1000>, <0x58006000 0x1000>; + interrupts = ; +- interrupt-names = "cmd_irq"; ++ interrupt-names = "cmd_irq"; + clocks = <&rcc SDMMC1_K>; + clock-names = "apb_pclk"; + resets = <&rcc SDMMC1_R>; + cap-sd-highspeed; + cap-mmc-highspeed; + max-frequency = <120000000>; ++ status = "disabled"; ++ }; ++ ++ sdmmc2: sdmmc@58007000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x58007000 0x1000>, <0x58008000 0x1000>; ++ interrupts = ; ++ interrupt-names = "cmd_irq"; ++ clocks = <&rcc SDMMC2_K>; ++ clock-names = "apb_pclk"; ++ resets = <&rcc SDMMC2_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <120000000>; ++ status = "disabled"; + }; + + crc1: crc@58009000 { +@@ -1321,23 +1605,25 @@ + compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; + reg = <0x5800a000 0x2000>; + reg-names = "stmmaceth"; +- interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; +- interrupt-names = "macirq"; ++ interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>, ++ <&exti 70 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq", ++ "eth_wake_irq"; + clock-names = "stmmaceth", + "mac-clk-tx", + "mac-clk-rx", +- "ethstp", +- "syscfg-clk"; ++ "ethstp"; + clocks = <&rcc ETHMAC>, + <&rcc ETHTX>, + <&rcc ETHRX>, +- <&rcc ETHSTP>, +- <&rcc SYSCFG>; ++ <&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"; + }; + +@@ -1355,28 +1641,10 @@ + reg = <0x5800d000 0x1000>; + clocks = <&rcc USBH>; + resets = <&rcc USBH_R>; +- interrupts = ; ++ interrupts-extended = <&exti 43 IRQ_TYPE_LEVEL_HIGH>; + companion = <&usbh_ohci>; +- 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"; +- }; +- +- dsi: dsi@5a000000 { +- compatible = "st,stm32-dsi"; +- reg = <0x5a000000 0x800>; +- clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>; +- clock-names = "pclk", "ref", "px_clk"; +- resets = <&rcc DSI_R>; +- reset-names = "apb"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + }; + +@@ -1394,7 +1662,7 @@ + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; +- clocks = <&rcc IWDG2>, <&rcc CK_LSI>; ++ clocks = <&rcc IWDG2>, <&scmi0_clk CK_SCMI0_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; +@@ -1402,10 +1670,13 @@ + 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 { +@@ -1419,11 +1690,22 @@ + }; + }; + ++ ddrperfm: perf@5a007000 { ++ compatible = "st,stm32-ddr-pmu"; ++ reg = <0x5a007000 0x400>; ++ clocks = <&rcc DDRPERFM>, <&scmi0_clk CK_SCMI0_PLL2_R>; ++ clock-names = "bus", "ddr"; ++ resets = <&rcc DDRPERFM_R>; ++ }; ++ + usart1: serial@5c000000 { + compatible = "st,stm32h7-uart"; + reg = <0x5c000000 0x400>; +- interrupts = ; +- clocks = <&rcc USART1_K>; ++ interrupts-extended = <&exti 26 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&scmi0_clk CK_SCMI0_USART1>; ++ resets = <&scmi0_reset RST_SCMI0_USART1>; ++ wakeup-source; ++ power-domains = <&pd_core>; + status = "disabled"; + }; + +@@ -1433,33 +1715,41 @@ + compatible = "st,stm32h7-spi"; + reg = <0x5c001000 0x400>; + interrupts = ; +- clocks = <&rcc SPI6_K>; +- resets = <&rcc SPI6_R>; +- dmas = <&mdma1 34 0x0 0x40008 0x0 0x0>, +- <&mdma1 35 0x0 0x40002 0x0 0x0>; ++ clocks = <&scmi0_clk CK_SCMI0_SPI6>; ++ resets = <&scmi0_reset RST_SCMI0_SPI6>; ++ 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"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x5c002000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; +- clocks = <&rcc I2C4_K>; +- resets = <&rcc I2C4_R>; ++ interrupts-extended = <&exti 24 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&scmi0_clk CK_SCMI0_I2C4>; ++ resets = <&scmi0_reset RST_SCMI0_I2C4>; + #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>; ++ wakeup-source; + status = "disabled"; + }; + + rtc: rtc@5c004000 { + compatible = "st,stm32mp1-rtc"; + reg = <0x5c004000 0x400>; +- clocks = <&rcc RTCAPB>, <&rcc RTC>; ++ clocks = <&scmi0_clk CK_SCMI0_RTCAPB>, ++ <&scmi0_clk CK_SCMI0_RTC>; + clock-names = "pclk", "rtc_ck"; +- interrupts = ; ++ interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + +@@ -1468,6 +1758,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>; + }; +@@ -1477,17 +1771,200 @@ + }; + + i2c6: i2c@5c009000 { +- compatible = "st,stm32f7-i2c"; ++ compatible = "st,stm32mp15-i2c"; + reg = <0x5c009000 0x400>; + interrupt-names = "event", "error"; +- interrupts = , +- ; +- clocks = <&rcc I2C6_K>; +- resets = <&rcc I2C6_R>; ++ interrupts-extended = <&exti 54 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&scmi0_clk CK_SCMI0_I2C6>; ++ resets = <&scmi0_reset RST_SCMI0_I2C6>; + #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>; ++ wakeup-source; + 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>; ++ }; ++ }; ++ ++ /* ++ * Break node order to solve dependency probe issue between ++ * pinctrl and exti. ++ */ ++ pinctrl: pin-controller@50002000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp157-pinctrl"; ++ ranges = <0 0x50002000 0xa400>; ++ interrupt-parent = <&exti>; ++ st,syscfg = <&exti 0x60 0xff>; ++ hwlocks = <&hsem 0 1>; ++ pins-are-numbered; ++ ++ gpioa: gpio@50002000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x0 0x400>; ++ clocks = <&rcc GPIOA>; ++ st,bank-name = "GPIOA"; ++ status = "disabled"; ++ }; ++ ++ gpiob: gpio@50003000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x1000 0x400>; ++ clocks = <&rcc GPIOB>; ++ st,bank-name = "GPIOB"; ++ status = "disabled"; ++ }; ++ ++ gpioc: gpio@50004000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x2000 0x400>; ++ clocks = <&rcc GPIOC>; ++ st,bank-name = "GPIOC"; ++ status = "disabled"; ++ }; ++ ++ gpiod: gpio@50005000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x3000 0x400>; ++ clocks = <&rcc GPIOD>; ++ st,bank-name = "GPIOD"; ++ status = "disabled"; ++ }; ++ ++ gpioe: gpio@50006000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x4000 0x400>; ++ clocks = <&rcc GPIOE>; ++ st,bank-name = "GPIOE"; ++ status = "disabled"; ++ }; ++ ++ gpiof: gpio@50007000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x5000 0x400>; ++ clocks = <&rcc GPIOF>; ++ st,bank-name = "GPIOF"; ++ status = "disabled"; ++ }; ++ ++ gpiog: gpio@50008000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x6000 0x400>; ++ clocks = <&rcc GPIOG>; ++ st,bank-name = "GPIOG"; ++ status = "disabled"; ++ }; ++ ++ gpioh: gpio@50009000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x7000 0x400>; ++ clocks = <&rcc GPIOH>; ++ st,bank-name = "GPIOH"; ++ status = "disabled"; ++ }; ++ ++ gpioi: gpio@5000a000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x8000 0x400>; ++ clocks = <&rcc GPIOI>; ++ st,bank-name = "GPIOI"; ++ status = "disabled"; ++ }; ++ ++ gpioj: gpio@5000b000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x9000 0x400>; ++ clocks = <&rcc GPIOJ>; ++ st,bank-name = "GPIOJ"; ++ status = "disabled"; ++ }; ++ ++ gpiok: gpio@5000c000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0xa000 0x400>; ++ clocks = <&rcc GPIOK>; ++ st,bank-name = "GPIOK"; ++ status = "disabled"; ++ }; ++ }; ++ ++ pinctrl_z: pin-controller-z@54004000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp157-z-pinctrl"; ++ ranges = <0 0x54004000 0x400>; ++ pins-are-numbered; ++ interrupt-parent = <&exti>; ++ st,syscfg = <&exti 0x60 0xff>; ++ hwlocks = <&hsem 0 1>; ++ ++ gpioz: gpio@54004000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0 0x400>; ++ clocks = <&scmi0_clk CK_SCMI0_GPIOZ>; ++ st,bank-name = "GPIOZ"; ++ st,bank-ioport = <11>; ++ status = "disabled"; ++ }; ++ }; + }; + + mlahb { +@@ -1503,10 +1980,18 @@ + reg = <0x10000000 0x40000>, + <0x30000000 0x40000>, + <0x38000000 0x10000>; +- resets = <&rcc MCU_R>; ++ resets = <&scmi0_reset RST_SCMI0_MCU>; + st,syscfg-holdboot = <&rcc 0x10C 0x1>; + st,syscfg-tz = <&rcc 0x000 0x1>; ++ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; ++ st,syscfg-copro-state = <&tamp 0x148 0xFFFFFFFF>; ++ st,syscfg-pdds = <&pwr_mcu 0x0 0x1>; + status = "disabled"; ++ ++ m4_system_resources { ++ compatible = "rproc-srm-core"; ++ status = "disabled"; ++ }; + }; + }; + }; +diff --git a/arch/arm/boot/dts/stm32mp153.dtsi b/arch/arm/boot/dts/stm32mp153.dtsi +new file mode 100644 +index 000000000..cf16b843c +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp153.dtsi +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include "stm32mp151.dtsi" ++ ++/ { ++ cpus { ++ cpu1: cpu@1 { ++ compatible = "arm,cortex-a7"; ++ device_type = "cpu"; ++ reg = <1>; ++ clocks = <&scmi0_clk CK_SCMI0_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ }; ++ }; ++ ++ arm-pmu { ++ interrupts = , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>; ++ }; ++ ++ soc { ++ 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 = <&scmi0_clk CK_SCMI0_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 = <&scmi0_clk CK_SCMI0_HSE>, <&rcc FDCAN_K>; ++ clock-names = "hclk", "cclk"; ++ bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi +new file mode 100644 +index 000000000..b4030e5c9 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi +@@ -0,0 +1,524 @@ ++// 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 */ ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi +new file mode 100644 +index 000000000..60454aee4 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi +@@ -0,0 +1,442 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++&m4_rproc { ++ m4_system_resources { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ m4_timers2: timer@40000000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40000000 0x400>; ++ clocks = <&rcc TIM2_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers3: timer@40001000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40001000 0x400>; ++ clocks = <&rcc TIM3_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers4: timer@40002000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40002000 0x400>; ++ clocks = <&rcc TIM4_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers5: timer@40003000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40003000 0x400>; ++ clocks = <&rcc TIM5_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers6: timer@40004000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40004000 0x400>; ++ clocks = <&rcc TIM6_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers7: timer@40005000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40005000 0x400>; ++ clocks = <&rcc TIM7_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers12: timer@40006000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40006000 0x400>; ++ clocks = <&rcc TIM12_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers13: timer@40007000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40007000 0x400>; ++ clocks = <&rcc TIM13_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers14: timer@40008000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40008000 0x400>; ++ clocks = <&rcc TIM14_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_lptimer1: timer@40009000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40009000 0x400>; ++ clocks = <&rcc LPTIM1_K>; ++ clock-names = "mux"; ++ status = "disabled"; ++ }; ++ m4_spi2: spi@4000b000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000b000 0x400>; ++ clocks = <&rcc SPI2_K>; ++ status = "disabled"; ++ }; ++ m4_i2s2: audio-controller@4000b000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000b000 0x400>; ++ status = "disabled"; ++ }; ++ m4_spi3: spi@4000c000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000c000 0x400>; ++ clocks = <&rcc SPI3_K>; ++ status = "disabled"; ++ }; ++ m4_i2s3: audio-controller@4000c000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000c000 0x400>; ++ status = "disabled"; ++ }; ++ m4_spdifrx: audio-controller@4000d000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000d000 0x400>; ++ clocks = <&rcc SPDIF_K>; ++ clock-names = "kclk"; ++ status = "disabled"; ++ }; ++ m4_usart2: serial@4000e000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000e000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <27 1>; ++ clocks = <&rcc USART2_K>; ++ status = "disabled"; ++ }; ++ m4_usart3: serial@4000f000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4000f000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <28 1>; ++ clocks = <&rcc USART3_K>; ++ status = "disabled"; ++ }; ++ m4_uart4: serial@40010000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40010000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <30 1>; ++ clocks = <&rcc UART4_K>; ++ status = "disabled"; ++ }; ++ m4_uart5: serial@40011000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40011000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <31 1>; ++ clocks = <&rcc UART5_K>; ++ status = "disabled"; ++ }; ++ m4_i2c1: i2c@40012000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40012000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <21 1>; ++ clocks = <&rcc I2C1_K>; ++ status = "disabled"; ++ }; ++ m4_i2c2: i2c@40013000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40013000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <22 1>; ++ clocks = <&rcc I2C2_K>; ++ status = "disabled"; ++ }; ++ m4_i2c3: i2c@40014000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40014000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <23 1>; ++ clocks = <&rcc I2C3_K>; ++ status = "disabled"; ++ }; ++ m4_i2c5: i2c@40015000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40015000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <25 1>; ++ clocks = <&rcc I2C5_K>; ++ status = "disabled"; ++ }; ++ m4_cec: cec@40016000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40016000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <69 1>; ++ clocks = <&rcc CEC_K>, <&scmi0_clk CK_SCMI0_LSE>; ++ clock-names = "cec", "hdmi-cec"; ++ status = "disabled"; ++ }; ++ m4_dac: dac@40017000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40017000 0x400>; ++ clocks = <&rcc DAC12>; ++ clock-names = "pclk"; ++ status = "disabled"; ++ }; ++ m4_uart7: serial@40018000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40018000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <32 1>; ++ clocks = <&rcc UART7_K>; ++ status = "disabled"; ++ }; ++ m4_uart8: serial@40019000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x40019000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <33 1>; ++ clocks = <&rcc UART8_K>; ++ status = "disabled"; ++ }; ++ m4_timers1: timer@44000000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44000000 0x400>; ++ clocks = <&rcc TIM1_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers8: timer@44001000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44001000 0x400>; ++ clocks = <&rcc TIM8_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_usart6: serial@44003000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44003000 0x400>; ++ interrupt-parent = <&exti>; ++ interrupts = <29 1>; ++ clocks = <&rcc USART6_K>; ++ status = "disabled"; ++ }; ++ m4_spi1: spi@44004000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44004000 0x400>; ++ clocks = <&rcc SPI1_K>; ++ status = "disabled"; ++ }; ++ m4_i2s1: audio-controller@44004000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44004000 0x400>; ++ status = "disabled"; ++ }; ++ m4_spi4: spi@44005000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44005000 0x400>; ++ clocks = <&rcc SPI4_K>; ++ status = "disabled"; ++ }; ++ m4_timers15: timer@44006000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44006000 0x400>; ++ clocks = <&rcc TIM15_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers16: timer@44007000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44007000 0x400>; ++ clocks = <&rcc TIM16_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_timers17: timer@44008000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44008000 0x400>; ++ clocks = <&rcc TIM17_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ m4_spi5: spi@44009000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x44009000 0x400>; ++ clocks = <&rcc SPI5_K>; ++ status = "disabled"; ++ }; ++ m4_sai1: sai@4400a000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400a000 0x4>; ++ clocks = <&rcc SAI1_K>; ++ clock-names = "sai_ck"; ++ status = "disabled"; ++ }; ++ m4_sai2: sai@4400b000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400b000 0x4>; ++ clocks = <&rcc SAI2_K>; ++ clock-names = "sai_ck"; ++ status = "disabled"; ++ }; ++ m4_sai3: sai@4400c000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400c000 0x4>; ++ clocks = <&rcc SAI3_K>; ++ clock-names = "sai_ck"; ++ status = "disabled"; ++ }; ++ m4_dfsdm: dfsdm@4400d000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400d000 0x800>; ++ clocks = <&rcc DFSDM_K>, <&rcc ADFSDM_K>; ++ clock-names = "dfsdm", "audio"; ++ status = "disabled"; ++ }; ++ m4_m_can1: can@4400e000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400e000 0x400>, <0x44011000 0x2800>; ++ clocks = <&scmi0_clk CK_SCMI0_HSE>, <&rcc FDCAN_K>; ++ clock-names = "hclk", "cclk"; ++ status = "disabled"; ++ }; ++ m4_m_can2: can@4400f000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4400f000 0x400>, <0x44011000 0x2800>; ++ clocks = <&scmi0_clk CK_SCMI0_HSE>, <&rcc FDCAN_K>; ++ clock-names = "hclk", "cclk"; ++ status = "disabled"; ++ }; ++ m4_dma1: dma@48000000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x48000000 0x400>; ++ clocks = <&rcc DMA1>; ++ status = "disabled"; ++ }; ++ m4_dma2: dma@48001000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x48001000 0x400>; ++ clocks = <&rcc DMA2>; ++ status = "disabled"; ++ }; ++ m4_dmamux1: dma-router@48002000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x48002000 0x1c>; ++ clocks = <&rcc DMAMUX>; ++ status = "disabled"; ++ }; ++ m4_adc: adc@48003000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x48003000 0x400>; ++ clocks = <&rcc ADC12>, <&rcc ADC12_K>; ++ clock-names = "bus", "adc"; ++ status = "disabled"; ++ }; ++ m4_sdmmc3: sdmmc@48004000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x48004000 0x400>, <0x48005000 0x400>; ++ clocks = <&rcc SDMMC3_K>; ++ status = "disabled"; ++ }; ++ m4_usbotg_hs: usb-otg@49000000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x49000000 0x10000>; ++ clocks = <&rcc USBO_K>; ++ clock-names = "otg"; ++ status = "disabled"; ++ }; ++ m4_hash2: hash@4c002000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4c002000 0x400>; ++ clocks = <&rcc HASH2>; ++ status = "disabled"; ++ }; ++ m4_rng2: rng@4c003000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4c003000 0x400>; ++ clocks = <&rcc RNG2_K>; ++ status = "disabled"; ++ }; ++ m4_crc2: crc@4c004000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4c004000 0x400>; ++ clocks = <&rcc CRC2>; ++ status = "disabled"; ++ }; ++ m4_cryp2: cryp@4c005000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4c005000 0x400>; ++ clocks = <&rcc CRYP2>; ++ status = "disabled"; ++ }; ++ m4_dcmi: dcmi@4c006000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x4c006000 0x400>; ++ clocks = <&rcc DCMI>; ++ clock-names = "mclk"; ++ status = "disabled"; ++ }; ++ m4_lptimer2: timer@50021000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x50021000 0x400>; ++ clocks = <&rcc LPTIM2_K>; ++ clock-names = "mux"; ++ status = "disabled"; ++ }; ++ m4_lptimer3: timer@50022000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x50022000 0x400>; ++ clocks = <&rcc LPTIM3_K>; ++ clock-names = "mux"; ++ status = "disabled"; ++ }; ++ m4_lptimer4: timer@50023000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x50023000 0x400>; ++ clocks = <&rcc LPTIM4_K>; ++ clock-names = "mux"; ++ status = "disabled"; ++ }; ++ m4_lptimer5: timer@50024000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x50024000 0x400>; ++ clocks = <&rcc LPTIM5_K>; ++ clock-names = "mux"; ++ status = "disabled"; ++ }; ++ m4_sai4: sai@50027000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x50027000 0x4>; ++ clocks = <&rcc SAI4_K>; ++ clock-names = "sai_ck"; ++ status = "disabled"; ++ }; ++ m4_qspi: qspi@58003000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; ++ clocks = <&rcc QSPI_K>; ++ status = "disabled"; ++ }; ++ m4_ethernet0: ethernet@5800a000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x5800a000 0x2000>; ++ 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"; ++ }; ++ }; ++}; ++ +diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +deleted file mode 100644 +index 0a3a7d667..000000000 +--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi ++++ /dev/null +@@ -1,925 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved +- * Author: Ludovic Barre for STMicroelectronics. +- */ +-#include +- +-/ { +- soc { +- pinctrl: pin-controller@50002000 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,stm32mp157-pinctrl"; +- ranges = <0 0x50002000 0xa400>; +- interrupt-parent = <&exti>; +- st,syscfg = <&exti 0x60 0xff>; +- pins-are-numbered; +- +- gpioa: gpio@50002000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x0 0x400>; +- clocks = <&rcc GPIOA>; +- st,bank-name = "GPIOA"; +- status = "disabled"; +- }; +- +- gpiob: gpio@50003000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x1000 0x400>; +- clocks = <&rcc GPIOB>; +- st,bank-name = "GPIOB"; +- status = "disabled"; +- }; +- +- gpioc: gpio@50004000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x2000 0x400>; +- clocks = <&rcc GPIOC>; +- st,bank-name = "GPIOC"; +- status = "disabled"; +- }; +- +- gpiod: gpio@50005000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x3000 0x400>; +- clocks = <&rcc GPIOD>; +- st,bank-name = "GPIOD"; +- status = "disabled"; +- }; +- +- gpioe: gpio@50006000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x4000 0x400>; +- clocks = <&rcc GPIOE>; +- st,bank-name = "GPIOE"; +- status = "disabled"; +- }; +- +- gpiof: gpio@50007000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x5000 0x400>; +- clocks = <&rcc GPIOF>; +- st,bank-name = "GPIOF"; +- status = "disabled"; +- }; +- +- gpiog: gpio@50008000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x6000 0x400>; +- clocks = <&rcc GPIOG>; +- st,bank-name = "GPIOG"; +- status = "disabled"; +- }; +- +- gpioh: gpio@50009000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x7000 0x400>; +- clocks = <&rcc GPIOH>; +- st,bank-name = "GPIOH"; +- status = "disabled"; +- }; +- +- gpioi: gpio@5000a000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x8000 0x400>; +- clocks = <&rcc GPIOI>; +- st,bank-name = "GPIOI"; +- status = "disabled"; +- }; +- +- gpioj: gpio@5000b000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0x9000 0x400>; +- clocks = <&rcc GPIOJ>; +- st,bank-name = "GPIOJ"; +- status = "disabled"; +- }; +- +- gpiok: gpio@5000c000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0xa000 0x400>; +- clocks = <&rcc GPIOK>; +- st,bank-name = "GPIOK"; +- status = "disabled"; +- }; +- +- cec_pins_a: cec-0 { +- pins { +- pinmux = ; +- bias-disable; +- drive-open-drain; +- 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 */ +- }; +- }; +- +- 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 */ +- }; +- }; +- +- ethernet0_rgmii_pins_a: rgmii-0 { +- pins1 { +- pinmux = , /* ETH_RGMII_CLK125 */ +- , /* ETH_RGMII_GTX_CLK */ +- , /* ETH_RGMII_TXD0 */ +- , /* ETH_RGMII_TXD1 */ +- , /* ETH_RGMII_TXD2 */ +- , /* ETH_RGMII_TXD3 */ +- , /* ETH_RGMII_TX_CTL */ +- , /* ETH_MDIO */ +- ; /* ETH_MDC */ +- bias-disable; +- drive-push-pull; +- slew-rate = <3>; +- }; +- pins2 { +- pinmux = , /* ETH_RGMII_RXD0 */ +- , /* ETH_RGMII_RXD1 */ +- , /* ETH_RGMII_RXD2 */ +- , /* ETH_RGMII_RXD3 */ +- , /* ETH_RGMII_RX_CLK */ +- ; /* ETH_RGMII_RX_CTL */ +- bias-disable; +- }; +- }; +- +- ethernet0_rgmii_pins_sleep_a: rgmii-sleep-0 { +- pins1 { +- pinmux = , /* ETH_RGMII_CLK125 */ +- , /* ETH_RGMII_GTX_CLK */ +- , /* ETH_RGMII_TXD0 */ +- , /* ETH_RGMII_TXD1 */ +- , /* ETH_RGMII_TXD2 */ +- , /* ETH_RGMII_TXD3 */ +- , /* ETH_RGMII_TX_CTL */ +- , /* ETH_MDIO */ +- , /* ETH_MDC */ +- , /* ETH_RGMII_RXD0 */ +- , /* ETH_RGMII_RXD1 */ +- , /* ETH_RGMII_RXD2 */ +- , /* ETH_RGMII_RXD3 */ +- , /* ETH_RGMII_RX_CLK */ +- ; /* ETH_RGMII_RX_CTL */ +- }; +- }; +- +- 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 */ +- }; +- }; +- +- 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 */ +- }; +- }; +- +- i2c1_pins_b: i2c1-2 { +- pins { +- pinmux = , /* I2C1_SCL */ +- ; /* I2C1_SDA */ +- bias-disable; +- drive-open-drain; +- slew-rate = <0>; +- }; +- }; +- +- i2c1_pins_sleep_b: i2c1-3 { +- 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 */ +- }; +- }; +- +- i2c2_pins_b1: i2c2-2 { +- pins { +- pinmux = ; /* I2C2_SDA */ +- bias-disable; +- drive-open-drain; +- slew-rate = <0>; +- }; +- }; +- +- i2c2_pins_sleep_b1: i2c2-3 { +- pins { +- pinmux = ; /* 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 = <1>; +- 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 */ +- }; +- }; +- +- pwm2_pins_a: pwm2-0 { +- pins { +- pinmux = ; /* TIM2_CH4 */ +- bias-pull-down; +- drive-push-pull; +- slew-rate = <0>; +- }; +- }; +- +- pwm8_pins_a: pwm8-0 { +- pins { +- pinmux = ; /* TIM8_CH4 */ +- bias-pull-down; +- drive-push-pull; +- slew-rate = <0>; +- }; +- }; +- +- pwm12_pins_a: pwm12-0 { +- pins { +- pinmux = ; /* TIM12_CH1 */ +- bias-pull-down; +- drive-push-pull; +- slew-rate = <0>; +- }; +- }; +- +- 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 */ +- }; +- }; +- +- 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 */ +- }; +- }; +- +- 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 { +- pins { +- pinmux = , /* SDMMC1_D0 */ +- , /* SDMMC1_D1 */ +- , /* SDMMC1_D2 */ +- , /* SDMMC1_D3 */ +- , /* SDMMC1_CK */ +- ; /* SDMMC1_CMD */ +- slew-rate = <3>; +- drive-push-pull; +- bias-disable; +- }; +- }; +- +- sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 { +- pins1 { +- pinmux = , /* SDMMC1_D0 */ +- , /* SDMMC1_D1 */ +- , /* SDMMC1_D2 */ +- , /* SDMMC1_D3 */ +- ; /* SDMMC1_CK */ +- slew-rate = <3>; +- drive-push-pull; +- bias-disable; +- }; +- pins2{ +- pinmux = ; /* SDMMC1_CMD */ +- slew-rate = <3>; +- drive-open-drain; +- bias-disable; +- }; +- }; +- +- sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { +- pins { +- pinmux = , /* SDMMC1_D0 */ +- , /* SDMMC1_D1 */ +- , /* SDMMC1_D2 */ +- , /* SDMMC1_D3 */ +- , /* SDMMC1_CK */ +- ; /* SDMMC1_CMD */ +- }; +- }; +- +- sdmmc1_dir_pins_a: sdmmc1-dir-0 { +- pins1 { +- pinmux = , /* SDMMC1_D0DIR */ +- , /* SDMMC1_D123DIR */ +- ; /* SDMMC1_CDIR */ +- slew-rate = <3>; +- drive-push-pull; +- bias-pull-up; +- }; +- pins2{ +- pinmux = ; /* SDMMC1_CKIN */ +- bias-pull-up; +- }; +- }; +- +- sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 { +- pins { +- pinmux = , /* SDMMC1_D0DIR */ +- , /* SDMMC1_D123DIR */ +- , /* SDMMC1_CDIR */ +- ; /* SDMMC1_CKIN */ +- }; +- }; +- +- spdifrx_pins_a: spdifrx-0 { +- pins { +- pinmux = ; /* SPDIF_IN1 */ +- bias-disable; +- }; +- }; +- +- spdifrx_sleep_pins_a: spdifrx-1 { +- pins { +- pinmux = ; /* SPDIF_IN1 */ +- }; +- }; +- +- uart4_pins_a: uart4-0 { +- pins1 { +- pinmux = ; /* UART4_TX */ +- bias-disable; +- drive-push-pull; +- slew-rate = <0>; +- }; +- pins2 { +- pinmux = ; /* UART4_RX */ +- bias-disable; +- }; +- }; +- +- uart4_pins_b: uart4-1 { +- pins1 { +- pinmux = ; /* UART4_TX */ +- bias-disable; +- drive-push-pull; +- slew-rate = <0>; +- }; +- pins2 { +- pinmux = ; /* UART4_RX */ +- bias-disable; +- }; +- }; +- +- uart7_pins_a: uart7-0 { +- pins1 { +- pinmux = ; /* UART4_TX */ +- bias-disable; +- drive-push-pull; +- slew-rate = <0>; +- }; +- pins2 { +- pinmux = , /* UART4_RX */ +- , /* UART4_CTS */ +- ; /* UART4_RTS */ +- bias-disable; +- }; +- }; +- }; +- +- pinctrl_z: pin-controller-z@54004000 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,stm32mp157-z-pinctrl"; +- ranges = <0 0x54004000 0x400>; +- pins-are-numbered; +- interrupt-parent = <&exti>; +- st,syscfg = <&exti 0x60 0xff>; +- +- gpioz: gpio@54004000 { +- gpio-controller; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- reg = <0 0x400>; +- clocks = <&rcc GPIOZ>; +- st,bank-name = "GPIOZ"; +- st,bank-ioport = <11>; +- status = "disabled"; +- }; +- +- i2c2_pins_b2: i2c2-0 { +- pins { +- pinmux = ; /* I2C2_SCL */ +- bias-disable; +- drive-open-drain; +- slew-rate = <0>; +- }; +- }; +- +- i2c2_pins_sleep_b2: i2c2-1 { +- pins { +- pinmux = ; /* I2C2_SCL */ +- }; +- }; +- +- i2c4_pins_a: i2c4-0 { +- pins { +- pinmux = , /* I2C4_SCL */ +- ; /* I2C4_SDA */ +- bias-disable; +- drive-open-drain; +- 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; +- }; +- }; +- }; +- }; +-}; +diff --git a/arch/arm/boot/dts/stm32mp157.dtsi b/arch/arm/boot/dts/stm32mp157.dtsi +new file mode 100644 +index 000000000..ce1d83aa7 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157.dtsi +@@ -0,0 +1,32 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include "stm32mp153.dtsi" ++ ++/ { ++ soc { ++ 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"; ++ }; ++ ++ dsi: dsi@5a000000 { ++ compatible = "st,stm32-dsi"; ++ reg = <0x5a000000 0x800>; ++ phy-dsi-supply = <®18>; ++ clocks = <&rcc DSI_K>, <&scmi0_clk CK_SCMI0_HSE>, <&rcc DSI_PX>; ++ clock-names = "pclk", "ref", "px_clk"; ++ resets = <&rcc DSI_R>; ++ reset-names = "apb"; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157a-avenger96.dts b/arch/arm/boot/dts/stm32mp157a-avenger96.dts +index 2e4742c53..887b76662 100644 +--- a/arch/arm/boot/dts/stm32mp157a-avenger96.dts ++++ b/arch/arm/boot/dts/stm32mp157a-avenger96.dts +@@ -6,9 +6,10 @@ + + /dts-v1/; + +-#include "stm32mp157c.dtsi" +-#include "stm32mp157xac-pinctrl.dtsi" +-#include ++#include "stm32mp157.dtsi" ++#include "stm32mp15xa.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxac-pinctrl.dtsi" + #include + + / { +@@ -252,14 +253,13 @@ + 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; ++ regulator-active-discharge = <1>; + }; + }; + +@@ -282,6 +282,11 @@ + status = "okay"; + }; + ++&pwr_regulators { ++ vdd-supply = <&vdd>; ++ vdd_3v3_usbfs-supply = <&vdd_usb>; ++}; ++ + &rng1 { + status = "okay"; + }; +@@ -295,7 +300,7 @@ + pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; + pinctrl-1 = <&sdmmc1_b4_od_pins_a>; + pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; +- broken-cd; ++ cd-gpios = <&gpioi 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + st,sig-dir; + st,neg-edge; + st,use-ckin; +diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts +index 0615d1c8a..baff3f694 100644 +--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts ++++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts +@@ -6,11 +6,11 @@ + + /dts-v1/; + +-#include "stm32mp157c.dtsi" +-#include "stm32mp157xac-pinctrl.dtsi" +-#include +-#include +- ++#include "stm32mp157.dtsi" ++#include "stm32mp15xa.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxac-pinctrl.dtsi" ++#include "stm32mp15xx-dkx.dtsi" + / { + model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; + compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; +@@ -18,434 +18,27 @@ + aliases { + ethernet0 = ðernet0; + serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + +- memory@c0000000 { +- reg = <0xc0000000 0x20000000>; +- }; +- + reserved-memory { +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; +- +- mcuram2: mcuram2@10000000 { +- compatible = "shared-dma-pool"; +- reg = <0x10000000 0x40000>; +- no-map; +- }; +- +- vdev0vring0: vdev0vring0@10040000 { +- compatible = "shared-dma-pool"; +- reg = <0x10040000 0x1000>; +- no-map; +- }; +- +- vdev0vring1: vdev0vring1@10041000 { +- compatible = "shared-dma-pool"; +- reg = <0x10041000 0x1000>; +- no-map; +- }; +- +- vdev0buffer: vdev0buffer@10042000 { +- compatible = "shared-dma-pool"; +- reg = <0x10042000 0x4000>; +- no-map; +- }; +- +- mcuram: mcuram@30000000 { +- compatible = "shared-dma-pool"; +- reg = <0x30000000 0x40000>; ++ gpu_reserved: gpu@da000000 { ++ reg = <0xda000000 0x4000000>; + no-map; + }; + +- retram: retram@38000000 { +- compatible = "shared-dma-pool"; +- reg = <0x38000000 0x10000>; ++ optee_memory: optee@0xde000000 { ++ reg = <0xde000000 0x02000000>; + no-map; + }; +- +- gpu_reserved: gpu@d4000000 { +- reg = <0xd4000000 0x4000000>; +- no-map; +- }; +- }; +- +- 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>; +- status = "okay"; +- }; +-}; +- +-&cec { +- pinctrl-names = "default", "sleep"; +- pinctrl-0 = <&cec_pins_b>; +- pinctrl-1 = <&cec_pins_sleep_b>; +- 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-id"; +- 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; +- +- 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>; +- }; +- }; +- }; +- }; +- +- cs42l51: cs42l51@4a { +- compatible = "cirrus,cs42l51"; +- reg = <0x4a>; +- #sound-dai-cells = <0>; +- 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"; +- status = "okay"; +- +- 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; +- }; +- }; + }; + }; + +-&i2c4 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c4_pins_a>; +- i2c-scl-rising-time-ns = <185>; +- i2c-scl-falling-time-ns = <20>; +- status = "okay"; +- /* spare dmas for other usage */ +- /delete-property/dmas; +- /delete-property/dma-names; +- +- pmic: stpmic@33 { +- compatible = "st,stpmic1"; +- reg = <0x33>; +- interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>; +- interrupt-controller; +- #interrupt-cells = <2>; +- status = "okay"; +- +- 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 = ; +- }; +- +- vbus_sw: pwr_sw2 { +- regulator-name = "vbus_sw"; +- interrupts = ; +- regulator-active-discharge; +- }; +- }; +- +- onkey { +- compatible = "st,stpmic1-onkey"; +- interrupts = , ; +- interrupt-names = "onkey-falling", "onkey-rising"; +- power-off-time-sec = <10>; +- status = "okay"; +- }; +- +- watchdog { +- compatible = "st,stpmic1-wdt"; +- status = "disabled"; +- }; +- }; +-}; +- +-&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>; +- status = "okay"; +-}; +- +-&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>; +- clocks = <&rcc SAI2_K>, <&sai2a>; +- clock-names = "sai_ck", "MCLK"; +- status = "okay"; +- +- 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"; +-}; +- +-&uart4 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart4_pins_a>; ++&optee { + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/stm32mp157a-ed1.dts b/arch/arm/boot/dts/stm32mp157a-ed1.dts +new file mode 100644 +index 000000000..5dca95684 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157a-ed1.dts +@@ -0,0 +1,52 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157.dtsi" ++#include "stm32mp15xa.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxaa-pinctrl.dtsi" ++#include "stm32mp157-m4-srm.dtsi" ++#include "stm32mp157-m4-srm-pinctrl.dtsi" ++#include "stm32mp15xx-edx.dtsi" ++ ++/ { ++ model = "STMicroelectronics STM32MP157A eval daughter"; ++ compatible = "st,stm32mp157a-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial0 = &uart4; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@f6000000 { ++ reg = <0xf6000000 0x8000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@fe000000 { ++ reg = <0xfe000000 0x02000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&gpu { ++ contiguous-area = <&gpu_reserved>; ++ status = "okay"; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157a-ev1.dts b/arch/arm/boot/dts/stm32mp157a-ev1.dts +new file mode 100644 +index 000000000..29ecd15c3 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157a-ev1.dts +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157a-ed1.dts" ++#include "stm32mp15xx-evx.dtsi" ++#include ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157A eval daughter on eval mother"; ++ compatible = "st,stm32mp157a-ev1", "st,stm32mp157a-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial1 = &usart3; ++ ethernet0 = ðernet0; ++ }; ++}; ++ ++&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: panel-dsi@0 { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ backlight = <&panel_backlight>; ++ power-supply = <&v3v3>; ++ status = "okay"; ++ ++ port { ++ dsi_panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ panel = <&panel_dsi>; ++ pinctrl-0 = <&goodix_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ interrupts = <14 IRQ_TYPE_EDGE_RISING>; ++ interrupt-parent = <&stmfx_pinctrl>; ++ }; ++}; ++ ++&m_can1 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&m_can1_pins_a>; ++ pinctrl-1 = <&m_can1_sleep_pins_a>; ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts +new file mode 100644 +index 000000000..1bffbc629 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts +@@ -0,0 +1,46 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157c-dk2.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C-DK2 configured to run Linux A7 examples"; ++ compatible = "st,stm32mp157c-dk2-a7-examples", "st,stm32mp157c-dk2", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&i2c5 { ++ status = "okay"; ++}; ++ ++&timers1 { ++ status = "okay"; ++}; ++ ++&timers3 { ++ status = "okay"; ++}; ++ ++&timers4 { ++ status = "okay"; ++}; ++ ++&timers5 { ++ status = "okay"; ++}; ++ ++&timers6 { ++ status = "okay"; ++}; ++ ++&timers12 { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts +new file mode 100644 +index 000000000..14eac740d +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157c-dk2.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C-DK2 configured to run M4 examples"; ++ compatible = "st,stm32mp157c-dk2-m4-examples", "st,stm32mp157c-dk2", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "disabled"; ++}; ++ ++&dac { ++ status = "disabled"; ++}; ++ ++&dma2 { ++ status = "disabled"; ++}; ++ ++&dmamux1 { ++ dma-masters = <&dma1>; ++ dma-channels = <8>; ++}; ++ ++&m4_adc { ++ vref-supply = <&vrefbuf>; ++ status = "okay"; ++}; ++ ++&m4_dac { ++ vref-supply = <&vrefbuf>; ++ status = "okay"; ++}; ++ ++&m4_dma2 { ++ status = "okay"; ++}; ++ ++&m4_crc2 { ++ status = "okay"; ++}; ++ ++&m4_cryp2 { ++ status = "okay"; ++}; ++ ++&m4_hash2 { ++ status = "okay"; ++}; ++ ++&m4_i2c5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_i2c5_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_rng2 { ++ status = "okay"; ++}; ++ ++&m4_rproc { ++ m4_system_resources { ++ status = "okay"; ++ ++ button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <14 2>; ++ interrupt-names = "irq"; ++ status = "okay"; ++ }; ++ ++ m4_led: m4_led { ++ compatible = "rproc-srm-dev"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_spi4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_spi4_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ status = "okay"; ++}; ++ ++&m4_timers1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm1_pins_a_ch1>; ++ status = "okay"; ++}; ++ ++&m4_uart7 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_uart7_pins_a>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ m4_leds_orange_pins: m4-leds-orange-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_pwm1_pins_a_ch1: m4-pwm1-0-ch1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++}; ++ ++&timers1 { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts +index 20ea601a5..a7d5e86a1 100644 +--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts ++++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts +@@ -6,26 +6,55 @@ + + /dts-v1/; + +-#include "stm32mp157a-dk1.dts" ++#include "stm32mp157.dtsi" ++#include "stm32mp15xc.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxac-pinctrl.dtsi" ++#include "stm32mp15xx-dkx.dtsi" ++#include + + / { + model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; + compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; + +- reg18: reg18 { +- compatible = "regulator-fixed"; +- regulator-name = "reg18"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-always-on; ++ aliases { ++ ethernet0 = ðernet0; ++ serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; ++ serial3 = &usart2; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@da000000 { ++ reg = <0xda000000 0x4000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@0xde000000 { ++ reg = <0xde000000 0x02000000>; ++ no-map; ++ }; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; + }; + }; + ++&cryp1 { ++ status="okay"; ++}; ++ + &dsi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +- phy-dsi-supply = <®18>; + + ports { + #address-cells = <1>; +@@ -46,7 +75,7 @@ + }; + }; + +- panel@0 { ++ panel_otm8009a: panel-otm8009a@0 { + compatible = "orisetech,otm8009a"; + reg = <0>; + reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; +@@ -61,6 +90,31 @@ + }; + }; + ++&i2c1 { ++ touchscreen@2a { ++ compatible = "focaltech,ft6236"; ++ reg = <0x2a>; ++ interrupts = <2 2>; ++ interrupt-parent = <&gpiof>; ++ interrupt-controller; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ panel = <&panel_otm8009a>; ++ status = "okay"; ++ }; ++ touchscreen@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ interrupts = <2 2>; ++ interrupt-parent = <&gpiof>; ++ interrupt-controller; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ panel = <&panel_otm8009a>; ++ status = "okay"; ++ }; ++}; ++ + <dc { + status = "okay"; + +@@ -74,3 +128,57 @@ + }; + }; + }; ++ ++&rtc { ++ st,lsco = ; ++ pinctrl-0 = <&rtc_out2_rmp_pins_a>; ++ pinctrl-names = "default"; ++}; ++ ++/* 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-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>; ++ 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>; ++ uart-has-rtscts; ++ status = "okay"; ++ ++ bluetooth { ++ shutdown-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ vbat-supply = <&v3v3>; ++ vddio-supply = <&v3v3>; ++ }; ++}; ++ ++&optee_memory { ++ status = "okay"; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts +index 1d426ea8b..bf2d7e7b7 100644 +--- a/arch/arm/boot/dts/stm32mp157c-ed1.dts ++++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts +@@ -1,14 +1,17 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + /* +- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved +- * Author: Ludovic Barre for STMicroelectronics. ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. + */ + /dts-v1/; + +-#include "stm32mp157c.dtsi" +-#include "stm32mp157xaa-pinctrl.dtsi" +-#include +-#include ++#include "stm32mp157.dtsi" ++#include "stm32mp15xc.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxaa-pinctrl.dtsi" ++#include "stm32mp157-m4-srm.dtsi" ++#include "stm32mp157-m4-srm-pinctrl.dtsi" ++#include "stm32mp15xx-edx.dtsi" + + / { + model = "STMicroelectronics STM32MP157C eval daughter"; +@@ -18,94 +21,29 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory@c0000000 { +- device_type = "memory"; +- reg = <0xC0000000 0x40000000>; ++ aliases { ++ serial0 = &uart4; + }; + + reserved-memory { +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; +- +- mcuram2: mcuram2@10000000 { +- compatible = "shared-dma-pool"; +- reg = <0x10000000 0x40000>; +- no-map; +- }; +- +- vdev0vring0: vdev0vring0@10040000 { +- compatible = "shared-dma-pool"; +- reg = <0x10040000 0x1000>; ++ gpu_reserved: gpu@f6000000 { ++ reg = <0xf6000000 0x8000000>; + no-map; + }; + +- vdev0vring1: vdev0vring1@10041000 { +- compatible = "shared-dma-pool"; +- reg = <0x10041000 0x1000>; +- no-map; +- }; +- +- vdev0buffer: vdev0buffer@10042000 { +- compatible = "shared-dma-pool"; +- reg = <0x10042000 0x4000>; +- no-map; +- }; +- +- mcuram: mcuram@30000000 { +- compatible = "shared-dma-pool"; +- reg = <0x30000000 0x40000>; +- no-map; +- }; +- +- retram: retram@38000000 { +- compatible = "shared-dma-pool"; +- reg = <0x38000000 0x10000>; +- no-map; +- }; +- +- gpu_reserved: gpu@e8000000 { +- reg = <0xe8000000 0x8000000>; ++ optee_memory: optee@fe000000 { ++ reg = <0xfe000000 0x02000000>; + no-map; + }; + }; ++}; + +- aliases { +- serial0 = &uart4; +- }; +- +- reg11: reg11 { +- compatible = "regulator-fixed"; +- regulator-name = "reg11"; +- regulator-min-microvolt = <1100000>; +- regulator-max-microvolt = <1100000>; +- regulator-always-on; +- }; +- +- reg18: reg18 { +- compatible = "regulator-fixed"; +- regulator-name = "reg18"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-always-on; +- }; +- +- sd_switch: regulator-sd_switch { +- compatible = "regulator-gpio"; +- regulator-name = "sd_switch"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <2900000>; +- regulator-type = "voltage"; +- regulator-always-on; +- +- gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; +- gpios-states = <0>; +- states = <1800000 0x1 2900000 0x0>; +- }; ++&cpu1{ ++ cpu-supply = <&vddcore>; + }; + +-&dts { +- status = "okay"; ++&cryp1 { ++ status="okay"; + }; + + &gpu { +@@ -113,219 +51,6 @@ + status = "okay"; + }; + +-&i2c4 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c4_pins_a>; +- i2c-scl-rising-time-ns = <185>; +- i2c-scl-falling-time-ns = <20>; ++&optee { + status = "okay"; +- /* spare dmas for other usage */ +- /delete-property/dmas; +- /delete-property/dma-names; +- +- pmic: stpmic@33 { +- compatible = "st,stpmic1"; +- reg = <0x33>; +- interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>; +- interrupt-controller; +- #interrupt-cells = <2>; +- status = "okay"; +- +- regulators { +- compatible = "st,stpmic1-regulators"; +- ldo1-supply = <&v3v3>; +- ldo2-supply = <&v3v3>; +- ldo3-supply = <&vdd_ddr>; +- ldo5-supply = <&v3v3>; +- 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>; +- }; +- +- vdda: ldo1 { +- regulator-name = "vdda"; +- regulator-min-microvolt = <2900000>; +- regulator-max-microvolt = <2900000>; +- interrupts = ; +- }; +- +- v2v8: ldo2 { +- regulator-name = "v2v8"; +- regulator-min-microvolt = <2800000>; +- regulator-max-microvolt = <2800000>; +- 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 = ; +- }; +- +- vdd_sd: ldo5 { +- regulator-name = "vdd_sd"; +- regulator-min-microvolt = <2900000>; +- regulator-max-microvolt = <2900000>; +- interrupts = ; +- regulator-boot-on; +- }; +- +- v1v8: ldo6 { +- regulator-name = "v1v8"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- 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 = ; +- }; +- +- vbus_sw: pwr_sw2 { +- regulator-name = "vbus_sw"; +- interrupts = ; +- regulator-active-discharge; +- }; +- }; +- +- onkey { +- compatible = "st,stpmic1-onkey"; +- interrupts = , ; +- interrupt-names = "onkey-falling", "onkey-rising"; +- power-off-time-sec = <10>; +- 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>; +- status = "okay"; +-}; +- +-&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,sig-dir; +- st,neg-edge; +- st,use-ckin; +- bus-width = <4>; +- vmmc-supply = <&vdd_sd>; +- vqmmc-supply = <&sd_switch>; +- 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-0 = <&uart4_pins_a>; +- status = "okay"; +-}; +- +-&usbphyc_port0 { +- phy-supply = <&vdd_usb>; +- vdda1v1-supply = <®11>; +- vdda1v8-supply = <®18>; +-}; +- +-&usbphyc_port1 { +- phy-supply = <&vdd_usb>; +- vdda1v1-supply = <®11>; +- vdda1v8-supply = <®18>; + }; +diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts +new file mode 100644 +index 000000000..25c9f4f2f +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts +@@ -0,0 +1,53 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157c-ev1.dts" ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157C-EV1 configured to run Linux A7 examples"; ++ compatible = "st,stm32mp157c-ev1-a7-examples", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; ++ ++ test_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ autorepeat; ++ status = "okay"; ++ /* gpio needs vdd core in retention for wakeup */ ++ power-domains = <&pd_core_ret>; ++ ++ button@1 { ++ label = "PA13"; ++ linux,code = ; ++ interrupts-extended = <&gpioa 13 IRQ_TYPE_EDGE_FALLING>; ++ status = "okay"; ++ wakeup-source; ++ }; ++ }; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&dac { ++ status = "okay"; ++}; ++ ++&timers2 { ++ status = "okay"; ++}; ++ ++&timers8 { ++ status = "okay"; ++}; ++ ++&timers12 { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts +new file mode 100644 +index 000000000..b1bb38efb +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts +@@ -0,0 +1,146 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157c-ev1.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C-EV1 configured to run M4 examples"; ++ compatible = "st,stm32mp157c-ev1-m4-examples", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "disabled"; ++}; ++ ++&dac { ++ status = "disabled"; ++}; ++ ++&dcmi { ++ status = "disabled"; ++}; ++ ++&dma2 { ++ status = "disabled"; ++}; ++ ++&dmamux1 { ++ dma-masters = <&dma1>; ++ dma-channels = <8>; ++}; ++ ++&fmc { ++ status = "disabled"; ++}; ++ ++&i2c5 { ++ status = "disabled"; ++}; ++ ++&m4_adc { ++ vref-supply = <&vdda>; ++ status = "okay"; ++}; ++ ++&m4_crc2 { ++ status = "okay"; ++}; ++ ++&m4_cryp2 { ++ status = "okay"; ++}; ++ ++&m4_dac { ++ vref-supply = <&vdda>; ++ status = "okay"; ++}; ++ ++&m4_dma2 { ++ status = "okay"; ++}; ++ ++&m4_hash2 { ++ status = "okay"; ++}; ++ ++&m4_i2c5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_i2c5_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_qspi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_qspi_clk_pins_a &m4_qspi_bk1_pins_a ++ &m4_qspi_bk2_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_rproc { ++ m4_system_resources { ++ status = "okay"; ++ ++ /* button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <14 2>; ++ interrupt-names = "irq"; ++ status = "okay"; ++ };*/ ++ ++ m4_led: m4_led { ++ compatible = "rproc-srm-dev"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_rng2 { ++ status = "okay"; ++}; ++ ++&m4_spi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_spi1_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm2_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_usart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_usart3_pins_a>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ m4_leds_orange_pins: m4-leds-orange-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++}; ++ ++&qspi { ++ status = "disabled"; ++}; ++ ++&sai2b { ++ status = "disabled"; ++}; ++ ++&timers2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts +index 91fc0a315..c60727d9b 100644 +--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts ++++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts +@@ -1,13 +1,14 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + /* +- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved +- * Author: Ludovic Barre for STMicroelectronics. ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. + */ + /dts-v1/; + + #include "stm32mp157c-ed1.dts" +-#include ++#include "stm32mp15xx-evx.dtsi" + #include ++#include + + / { + model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; +@@ -18,90 +19,14 @@ + }; + + aliases { +- serial0 = &uart4; ++ 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"; +- }; +-}; +- +-&cec { +- pinctrl-names = "default"; +- pinctrl-0 = <&cec_pins_a>; +- status = "okay"; +-}; +- +-&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>; +- }; +- }; + }; + + &dsi { + #address-cells = <1>; + #size-cells = <0>; +- phy-dsi-supply = <®18>; + status = "okay"; + + ports { +@@ -123,7 +48,7 @@ + }; + }; + +- panel-dsi@0 { ++ panel_dsi: panel-dsi@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; +@@ -139,113 +64,17 @@ + }; + }; + +-ðernet0 { +- status = "okay"; +- pinctrl-0 = <ðernet0_rgmii_pins_a>; +- pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; +- pinctrl-names = "default", "sleep"; +- phy-mode = "rgmii-id"; +- 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@0 { +- reg = <0>; +- nand-on-flash-bbt; +- #address-cells = <1>; +- #size-cells = <1>; +- }; +-}; +- + &i2c2 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c2_pins_a>; +- i2c-scl-rising-time-ns = <185>; +- i2c-scl-falling-time-ns = <20>; +- status = "okay"; +- +- ov5640: camera@3c { +- compatible = "ovti,ov5640"; +- reg = <0x3c>; +- clocks = <&clk_ext_camera>; +- clock-names = "xclk"; +- DOVDD-supply = <&v2v8>; +- powerdown-gpios = <&stmfx_pinctrl 18 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>; +- reset-gpios = <&stmfx_pinctrl 19 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; +- rotation = <180>; ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ panel = <&panel_dsi>; ++ pinctrl-0 = <&goodix_pins>; ++ pinctrl-names = "default"; + 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>; +- }; +- }; +- }; +- +- 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>; +- +- joystick_pins: joystick { +- pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; +- bias-pull-down; +- }; +- }; +- }; +-}; +- +-&i2c5 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c5_pins_a>; +- i2c-scl-rising-time-ns = <185>; +- i2c-scl-falling-time-ns = <20>; +- status = "okay"; +-}; +- +-<dc { +- status = "okay"; +- +- port { +- #address-cells = <1>; +- #size-cells = <0>; +- +- ltdc_ep0_out: endpoint@0 { +- reg = <0>; +- remote-endpoint = <&dsi_in>; +- }; ++ interrupts = <14 IRQ_TYPE_EDGE_RISING>; ++ interrupt-parent = <&stmfx_pinctrl>; + }; + }; + +@@ -255,97 +84,3 @@ + pinctrl-1 = <&m_can1_sleep_pins_a>; + status = "okay"; + }; +- +-&qspi { +- 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>; +- #address-cells = <1>; +- #size-cells = <1>; +- }; +- +- flash1: mx66l51235l@1 { +- compatible = "jedec,spi-nor"; +- reg = <1>; +- spi-rx-bus-width = <4>; +- spi-max-frequency = <108000000>; +- #address-cells = <1>; +- #size-cells = <1>; +- }; +-}; +- +-&spi1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&spi1_pins_a>; +- status = "disabled"; +-}; +- +-&timers2 { +- /* spare dmas for other usage (un-delete to enable pwm capture) */ +- /delete-property/dmas; +- /delete-property/dma-names; +- status = "disabled"; +- pwm { +- pinctrl-0 = <&pwm2_pins_a>; +- pinctrl-names = "default"; +- status = "okay"; +- }; +- timer@1 { +- status = "okay"; +- }; +-}; +- +-&timers8 { +- /delete-property/dmas; +- /delete-property/dma-names; +- status = "disabled"; +- pwm { +- pinctrl-0 = <&pwm8_pins_a>; +- pinctrl-names = "default"; +- status = "okay"; +- }; +- timer@7 { +- status = "okay"; +- }; +-}; +- +-&timers12 { +- /delete-property/dmas; +- /delete-property/dma-names; +- status = "disabled"; +- pwm { +- pinctrl-0 = <&pwm12_pins_a>; +- pinctrl-names = "default"; +- status = "okay"; +- }; +- timer@11 { +- status = "okay"; +- }; +-}; +- +-&usbh_ehci { +- phys = <&usbphyc_port0>; +- phy-names = "usb"; +- status = "okay"; +-}; +- +-&usbotg_hs { +- dr_mode = "peripheral"; +- phys = <&usbphyc_port1 0>; +- phy-names = "usb2-phy"; +- status = "okay"; +-}; +- +-&usbphyc { +- status = "okay"; +-}; +diff --git a/arch/arm/boot/dts/stm32mp157d-dk1.dts b/arch/arm/boot/dts/stm32mp157d-dk1.dts +new file mode 100644 +index 000000000..c7d65a65e +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157d-dk1.dts +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157.dtsi" ++#include "stm32mp15xd.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxac-pinctrl.dtsi" ++#include "stm32mp15xx-dkx.dtsi" ++/ { ++ model = "STMicroelectronics STM32MP157D-DK1 Discovery Board"; ++ compatible = "st,stm32mp157d-dk1", "st,stm32mp157"; ++ ++ aliases { ++ ethernet0 = ðernet0; ++ serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@da000000 { ++ reg = <0xda000000 0x4000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@0xde000000 { ++ reg = <0xde000000 0x02000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157d-ed1.dts b/arch/arm/boot/dts/stm32mp157d-ed1.dts +new file mode 100644 +index 000000000..ee55ac8f3 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157d-ed1.dts +@@ -0,0 +1,52 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157.dtsi" ++#include "stm32mp15xd.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxaa-pinctrl.dtsi" ++#include "stm32mp157-m4-srm.dtsi" ++#include "stm32mp157-m4-srm-pinctrl.dtsi" ++#include "stm32mp15xx-edx.dtsi" ++ ++/ { ++ model = "STMicroelectronics STM32MP157D eval daughter"; ++ compatible = "st,stm32mp157d-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial0 = &uart4; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@f6000000 { ++ reg = <0xf6000000 0x8000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@fe000000 { ++ reg = <0xfe000000 0x02000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&gpu { ++ contiguous-area = <&gpu_reserved>; ++ status = "okay"; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157d-ev1.dts b/arch/arm/boot/dts/stm32mp157d-ev1.dts +new file mode 100644 +index 000000000..a4752c100 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157d-ev1.dts +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157d-ed1.dts" ++#include "stm32mp15xx-evx.dtsi" ++#include ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157D eval daughter on eval mother"; ++ compatible = "st,stm32mp157d-ev1", "st,stm32mp157d-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial1 = &usart3; ++ ethernet0 = ðernet0; ++ }; ++}; ++ ++&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: panel-dsi@0 { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ backlight = <&panel_backlight>; ++ power-supply = <&v3v3>; ++ status = "okay"; ++ ++ port { ++ dsi_panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ panel = <&panel_dsi>; ++ pinctrl-0 = <&goodix_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ interrupts = <14 IRQ_TYPE_EDGE_RISING>; ++ interrupt-parent = <&stmfx_pinctrl>; ++ }; ++}; ++ ++&m_can1 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&m_can1_pins_a>; ++ pinctrl-1 = <&m_can1_sleep_pins_a>; ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts +new file mode 100644 +index 000000000..2a8c46059 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts +@@ -0,0 +1,46 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157f-dk2.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157F-DK2 configured to run Linux A7 examples"; ++ compatible = "st,stm32mp157f-dk2-a7-examples", "st,stm32mp157f-dk2", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&i2c5 { ++ status = "okay"; ++}; ++ ++&timers1 { ++ status = "okay"; ++}; ++ ++&timers3 { ++ status = "okay"; ++}; ++ ++&timers4 { ++ status = "okay"; ++}; ++ ++&timers5 { ++ status = "okay"; ++}; ++ ++&timers6 { ++ status = "okay"; ++}; ++ ++&timers12 { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts +new file mode 100644 +index 000000000..726522997 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157f-dk2.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157F-DK2 configured to run M4 examples"; ++ compatible = "st,stm32mp157f-dk2-m4-examples", "st,stm32mp157f-dk2", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "disabled"; ++}; ++ ++&dac { ++ status = "disabled"; ++}; ++ ++&dma2 { ++ status = "disabled"; ++}; ++ ++&dmamux1 { ++ dma-masters = <&dma1>; ++ dma-channels = <8>; ++}; ++ ++&m4_adc { ++ vref-supply = <&vrefbuf>; ++ status = "okay"; ++}; ++ ++&m4_dac { ++ vref-supply = <&vrefbuf>; ++ status = "okay"; ++}; ++ ++&m4_dma2 { ++ status = "okay"; ++}; ++ ++&m4_crc2 { ++ status = "okay"; ++}; ++ ++&m4_cryp2 { ++ status = "okay"; ++}; ++ ++&m4_hash2 { ++ status = "okay"; ++}; ++ ++&m4_i2c5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_i2c5_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_rng2 { ++ status = "okay"; ++}; ++ ++&m4_rproc { ++ m4_system_resources { ++ status = "okay"; ++ ++ button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <14 2>; ++ interrupt-names = "irq"; ++ status = "okay"; ++ }; ++ ++ m4_led: m4_led { ++ compatible = "rproc-srm-dev"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_spi4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_spi4_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ status = "okay"; ++}; ++ ++&m4_timers1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm1_pins_a_ch1>; ++ status = "okay"; ++}; ++ ++&m4_uart7 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_uart7_pins_a>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ m4_leds_orange_pins: m4-leds-orange-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_pwm1_pins_a_ch1: m4-pwm1-0-ch1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++}; ++ ++&timers1 { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-dk2.dts b/arch/arm/boot/dts/stm32mp157f-dk2.dts +new file mode 100644 +index 000000000..b57db3037 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-dk2.dts +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157.dtsi" ++#include "stm32mp15xf.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxac-pinctrl.dtsi" ++#include "stm32mp15xx-dkx.dtsi" ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157F-DK2 Discovery Board"; ++ compatible = "st,stm32mp157f-dk2", "st,stm32mp157"; ++ ++ aliases { ++ ethernet0 = ðernet0; ++ serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; ++ serial3 = &usart2; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@da000000 { ++ reg = <0xda000000 0x4000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@0xde000000 { ++ reg = <0xde000000 0x02000000>; ++ no-map; ++ status = "disabled"; ++ }; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&cryp1 { ++ status="okay"; ++}; ++ ++&dsi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ dsi_in: endpoint { ++ remote-endpoint = <<dc_ep1_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ }; ++ ++ panel_otm8009a: panel-otm8009a@0 { ++ compatible = "orisetech,otm8009a"; ++ reg = <0>; ++ reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; ++ power-supply = <&v3v3>; ++ 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>; ++ panel = <&panel_otm8009a>; ++ status = "okay"; ++ }; ++ touchscreen@38 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x38>; ++ interrupts = <2 2>; ++ interrupt-parent = <&gpiof>; ++ interrupt-controller; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ panel = <&panel_otm8009a>; ++ 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 { ++ arm,primecell-periphid = <0x10153180>; ++ 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>; ++ 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>; ++ uart-has-rtscts; ++ status = "okay"; ++ ++ bluetooth { ++ shutdown-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ vbat-supply = <&v3v3>; ++ vddio-supply = <&v3v3>; ++ }; ++}; ++ ++&optee_memory { ++ status = "okay"; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-ed1.dts b/arch/arm/boot/dts/stm32mp157f-ed1.dts +new file mode 100644 +index 000000000..65380693c +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-ed1.dts +@@ -0,0 +1,56 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157.dtsi" ++#include "stm32mp15xf.dtsi" ++#include "stm32mp15-pinctrl.dtsi" ++#include "stm32mp15xxaa-pinctrl.dtsi" ++#include "stm32mp157-m4-srm.dtsi" ++#include "stm32mp157-m4-srm-pinctrl.dtsi" ++#include "stm32mp15xx-edx.dtsi" ++ ++/ { ++ model = "STMicroelectronics STM32MP157F eval daughter"; ++ compatible = "st,stm32mp157f-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial0 = &uart4; ++ }; ++ ++ reserved-memory { ++ gpu_reserved: gpu@f6000000 { ++ reg = <0xf6000000 0x8000000>; ++ no-map; ++ }; ++ ++ optee_memory: optee@0xfe000000 { ++ reg = <0xfe000000 0x02000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cryp1 { ++ status="okay"; ++}; ++ ++&gpu { ++ contiguous-area = <&gpu_reserved>; ++ status = "okay"; ++}; ++ ++&optee { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts +new file mode 100644 +index 000000000..17d92b7be +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts +@@ -0,0 +1,53 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157f-ev1.dts" ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157F-EV1 configured to run Linux A7 examples"; ++ compatible = "st,stm32mp157f-ev1-a7-examples", "st,stm32mp157f-ev1", "st,stm32mp157f-ed1", "st,stm32mp157"; ++ ++ test_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ autorepeat; ++ status = "okay"; ++ /* gpio needs vdd core in retention for wakeup */ ++ power-domains = <&pd_core_ret>; ++ ++ button@1 { ++ label = "PA13"; ++ linux,code = ; ++ interrupts-extended = <&gpioa 13 IRQ_TYPE_EDGE_FALLING>; ++ status = "okay"; ++ wakeup-source; ++ }; ++ }; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&dac { ++ status = "okay"; ++}; ++ ++&timers2 { ++ status = "okay"; ++}; ++ ++&timers8 { ++ status = "okay"; ++}; ++ ++&timers12 { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts +new file mode 100644 +index 000000000..d508be276 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts +@@ -0,0 +1,146 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157f-ev1.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157F-EV1 configured to run M4 examples"; ++ compatible = "st,stm32mp157f-ev1-m4-examples", "st,stm32mp157f-ev1", "st,stm32mp157f-ed1", "st,stm32mp157"; ++}; ++ ++&adc { ++ status = "disabled"; ++}; ++ ++&dac { ++ status = "disabled"; ++}; ++ ++&dcmi { ++ status = "disabled"; ++}; ++ ++&dma2 { ++ status = "disabled"; ++}; ++ ++&dmamux1 { ++ dma-masters = <&dma1>; ++ dma-channels = <8>; ++}; ++ ++&fmc { ++ status = "disabled"; ++}; ++ ++&i2c5 { ++ status = "disabled"; ++}; ++ ++&m4_adc { ++ vref-supply = <&vdda>; ++ status = "okay"; ++}; ++ ++&m4_crc2 { ++ status = "okay"; ++}; ++ ++&m4_cryp2 { ++ status = "okay"; ++}; ++ ++&m4_dac { ++ vref-supply = <&vdda>; ++ status = "okay"; ++}; ++ ++&m4_dma2 { ++ status = "okay"; ++}; ++ ++&m4_hash2 { ++ status = "okay"; ++}; ++ ++&m4_i2c5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_i2c5_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_qspi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_qspi_clk_pins_a &m4_qspi_bk1_pins_a ++ &m4_qspi_bk2_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_rproc { ++ m4_system_resources { ++ status = "okay"; ++ ++ /* button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <14 2>; ++ interrupt-names = "irq"; ++ status = "okay"; ++ };*/ ++ ++ m4_led: m4_led { ++ compatible = "rproc-srm-dev"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_rng2 { ++ status = "okay"; ++}; ++ ++&m4_spi1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_spi1_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm2_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_usart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_usart3_pins_a>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ m4_leds_orange_pins: m4-leds-orange-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++}; ++ ++&qspi { ++ status = "disabled"; ++}; ++ ++&sai2b { ++ status = "disabled"; ++}; ++ ++&timers2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157f-ev1.dts b/arch/arm/boot/dts/stm32mp157f-ev1.dts +new file mode 100644 +index 000000000..0c18333c0 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157f-ev1.dts +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157f-ed1.dts" ++#include "stm32mp15xx-evx.dtsi" ++#include ++#include ++ ++/ { ++ model = "STMicroelectronics STM32MP157F eval daughter on eval mother"; ++ compatible = "st,stm32mp157f-ev1", "st,stm32mp157f-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial1 = &usart3; ++ ethernet0 = ðernet0; ++ }; ++}; ++ ++&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: panel-dsi@0 { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ backlight = <&panel_backlight>; ++ power-supply = <&v3v3>; ++ status = "okay"; ++ ++ port { ++ dsi_panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ panel = <&panel_dsi>; ++ pinctrl-0 = <&goodix_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ interrupts = <14 IRQ_TYPE_EDGE_RISING>; ++ interrupt-parent = <&stmfx_pinctrl>; ++ }; ++}; ++ ++&m_can1 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&m_can1_pins_a>; ++ pinctrl-1 = <&m_can1_sleep_pins_a>; ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi +deleted file mode 100644 +index 875adf5e1..000000000 +--- a/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi ++++ /dev/null +@@ -1,90 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (C) STMicroelectronics 2019 - 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/boot/dts/stm32mp157xab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi +deleted file mode 100644 +index 961fa12a5..000000000 +--- a/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi ++++ /dev/null +@@ -1,62 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (C) STMicroelectronics 2019 - 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/boot/dts/stm32mp157xac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi +deleted file mode 100644 +index 26600f188..000000000 +--- a/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi ++++ /dev/null +@@ -1,78 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (C) STMicroelectronics 2019 - 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/boot/dts/stm32mp157xad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi +deleted file mode 100644 +index 910113f3e..000000000 +--- a/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi ++++ /dev/null +@@ -1,62 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (C) STMicroelectronics 2019 - 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/boot/dts/stm32mp15xa.dtsi b/arch/arm/boot/dts/stm32mp15xa.dtsi +new file mode 100644 +index 000000000..5ed7e594f +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xa.dtsi +@@ -0,0 +1,13 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++&cpu0_opp_table { ++ opp-650000000 { ++ opp-hz = /bits/ 64 <650000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x1>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xc.dtsi b/arch/arm/boot/dts/stm32mp15xc.dtsi +new file mode 100644 +index 000000000..adc1568a7 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xc.dtsi +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include "stm32mp15xa.dtsi" ++ ++/ { ++ soc { ++ cryp1: cryp@54001000 { ++ compatible = "st,stm32mp1-cryp"; ++ reg = <0x54001000 0x400>; ++ interrupts = ; ++ clocks = <&scmi0_clk CK_SCMI0_CRYP1>; ++ resets = <&scmi0_reset RST_SCMI0_CRYP1>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xd.dtsi b/arch/arm/boot/dts/stm32mp15xd.dtsi +new file mode 100644 +index 000000000..faa039ea2 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xd.dtsi +@@ -0,0 +1,42 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++&cpu0_opp_table { ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <1350000>; ++ opp-supported-hw = <0x2>; ++ }; ++ opp-400000000 { ++ opp-hz = /bits/ 64 <400000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x2>; ++ opp-suspend; ++ }; ++}; ++ ++&cpu_thermal { ++ trips { ++ cpu-crit { ++ temperature = <105000>; ++ hysteresis = <0>; ++ type = "critical"; ++ }; ++ ++ cpu_alert: cpu-alert { ++ temperature = <950000>; ++ hysteresis = <10000>; ++ type = "passive"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = <&cpu0 1 1>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xf.dtsi b/arch/arm/boot/dts/stm32mp15xf.dtsi +new file mode 100644 +index 000000000..77f50b9bd +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xf.dtsi +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include "stm32mp15xd.dtsi" ++ ++/ { ++ soc { ++ cryp1: cryp@54001000 { ++ compatible = "st,stm32mp1-cryp"; ++ reg = <0x54001000 0x400>; ++ interrupts = ; ++ clocks = <&scmi0_clk CK_SCMI0_CRYP1>; ++ resets = <&scmi0_reset RST_SCMI0_CRYP1>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi +new file mode 100644 +index 000000000..35169385f +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi +@@ -0,0 +1,768 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include "stm32mp157-m4-srm.dtsi" ++#include "stm32mp157-m4-srm-pinctrl.dtsi" ++#include ++ ++/ { ++ memory@c0000000 { ++ device_type = "memory"; ++ reg = <0xc0000000 0x20000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ mcuram2: mcuram2@10000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10000000 0x40000>; ++ no-map; ++ }; ++ ++ vdev0vring0: vdev0vring0@10040000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10040000 0x1000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@10041000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10041000 0x1000>; ++ no-map; ++ }; ++ ++ vdev0buffer: vdev0buffer@10042000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10042000 0x4000>; ++ no-map; ++ }; ++ ++ mcuram: mcuram@30000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x30000000 0x40000>; ++ no-map; ++ }; ++ ++ retram: retram@38000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x38000000 0x10000>; ++ no-map; ++ }; ++ }; ++ ++ 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; ++ }; ++ ++ vin: vin { ++ compatible = "regulator-fixed"; ++ regulator-name = "vin"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++}; ++ ++&adc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&adc12_ain_pins_a>, <&adc12_usb_cc_pins_a>; ++ vdd-supply = <&vdd>; ++ vdda-supply = <&vdd>; ++ vref-supply = <&vrefbuf>; ++ status = "disabled"; ++ 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. 5us). ++ */ ++ st,min-sample-time-nsecs = <5000>; ++ /* AIN connector, USB Type-C CC1 & CC2 */ ++ st,adc-channels = <0 1 6 13 18 19>; ++ status = "okay"; ++ }; ++ adc2: adc@100 { ++ /* AIN connector, USB Type-C CC1 & CC2 */ ++ st,adc-channels = <0 1 2 6 18 19>; ++ st,min-sample-time-nsecs = <5000>; ++ status = "okay"; ++ }; ++}; ++ ++&cec { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&cec_pins_b>; ++ pinctrl-1 = <&cec_pins_sleep_b>; ++ status = "okay"; ++}; ++ ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&crc1 { ++ 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-id"; ++ 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"; ++}; ++ ++&hash1 { ++ 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; ++ ++ 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>; ++ #sound-dai-cells = <0>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ sii9022_in: endpoint { ++ remote-endpoint = <<dc_ep0_out>; ++ }; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ sii9022_tx_endpoint: endpoint { ++ remote-endpoint = <&i2s2_endpoint>; ++ }; ++ }; ++ }; ++ }; ++ ++ cs42l51: cs42l51@4a { ++ compatible = "cirrus,cs42l51"; ++ reg = <0x4a>; ++ #sound-dai-cells = <0>; ++ 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"; ++ status = "okay"; ++ ++ 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; ++ }; ++ }; ++ }; ++}; ++ ++&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>; ++ clock-frequency = <400000>; ++ status = "okay"; ++ /* spare dmas for other usage */ ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ ++ 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"; ++ vdd-supply = <&vin>; ++ ++ connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C"; ++ power-role = "dual"; ++ power-opmode = "default"; ++ ++ port { ++ con_usbotg_hs_ep: endpoint { ++ remote-endpoint = <&usbotg_hs_ep>; ++ }; ++ }; ++ }; ++ }; ++ ++ pmic: stpmic@33 { ++ compatible = "st,stpmic1"; ++ reg = <0x33>; ++ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ status = "okay"; ++ ++ regulators { ++ compatible = "st,stpmic1-regulators"; ++ buck1-supply = <&vin>; ++ buck2-supply = <&vin>; ++ buck3-supply = <&vin>; ++ buck4-supply = <&vin>; ++ ldo1-supply = <&v3v3>; ++ ldo2-supply = <&vin>; ++ ldo3-supply = <&vdd_ddr>; ++ ldo4-supply = <&vin>; ++ ldo5-supply = <&vin>; ++ ldo6-supply = <&v3v3>; ++ vref_ddr-supply = <&vin>; ++ boost-supply = <&vin>; ++ pwr_sw1-supply = <&bst_out>; ++ pwr_sw2-supply = <&bst_out>; ++ ++ vddcore: buck1 { ++ regulator-name = "vddcore"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_ddr: buck2 { ++ regulator-name = "vdd_ddr"; ++ regulator-min-microvolt = <1350000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd: buck3 { ++ regulator-name = "vdd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ st,mask-reset; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ v3v3: buck4 { ++ regulator-name = "v3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ regulator-initial-mode = <0>; ++ }; ++ ++ v1v8_audio: ldo1 { ++ regulator-name = "v1v8_audio"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ interrupts = ; ++ }; ++ ++ v3v3_hdmi: ldo2 { ++ regulator-name = "v3v3_hdmi"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ interrupts = ; ++ }; ++ ++ vtt_ddr: ldo3 { ++ regulator-name = "vtt_ddr"; ++ regulator-min-microvolt = <500000>; ++ regulator-max-microvolt = <750000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_usb: ldo4 { ++ regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ interrupts = ; ++ regulator-always-on; ++ }; ++ ++ 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 = ; ++ }; ++ ++ vbus_sw: pwr_sw2 { ++ regulator-name = "vbus_sw"; ++ interrupts = ; ++ regulator-active-discharge = <1>; ++ }; ++ }; ++ ++ onkey { ++ compatible = "st,stpmic1-onkey"; ++ interrupts = , ; ++ interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; ++ status = "okay"; ++ }; ++ ++ watchdog { ++ compatible = "st,stpmic1-wdt"; ++ status = "disabled"; ++ }; ++ }; ++}; ++ ++&i2c5 { ++ 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>; ++ clock-frequency = <400000>; ++ /* spare dmas for other usage */ ++ /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"; ++ 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 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <<dc_pins_a>; ++ pinctrl-1 = <<dc_pins_sleep_a>; ++ 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>; ++ wakeup-source; ++ status = "okay"; ++}; ++ ++&pwr_regulators { ++ vdd-supply = <&vdd>; ++ vdd_3v3_usbfs-supply = <&vdd_usb>; ++}; ++ ++&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>; ++ clocks = <&rcc SAI2_K>, <&sai2a>; ++ clock-names = "sai_ck", "MCLK"; ++ status = "okay"; ++ ++ 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>; ++ cd-gpios = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; ++ disable-wp; ++ st,neg-edge; ++ bus-width = <4>; ++ vmmc-supply = <&v3v3>; ++ 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>; ++ 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"; ++}; ++ ++&sram { ++ dma_pool: dma_pool@0 { ++ reg = <0x50000 0x10000>; ++ pool; ++ }; ++}; ++ ++&timers1 { ++ /* 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>; ++ pinctrl-names = "default", "sleep"; ++ status = "okay"; ++ }; ++ timer@0 { ++ status = "okay"; ++ }; ++}; ++ ++&timers3 { ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ 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; ++ status = "disabled"; ++ 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; ++ status = "disabled"; ++ pwm { ++ pinctrl-0 = <&pwm5_pins_a>; ++ pinctrl-1 = <&pwm5_sleep_pins_a>; ++ pinctrl-names = "default", "sleep"; ++ status = "okay"; ++ }; ++ timer@4 { ++ status = "okay"; ++ }; ++}; ++ ++&timers6 { ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ timer@5 { ++ status = "okay"; ++ }; ++}; ++ ++&timers12 { ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ 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"; ++ pinctrl-0 = <&uart4_pins_a>; ++ 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"; ++}; ++ ++&uart7 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&uart7_pins_b>; ++ pinctrl-1 = <&uart7_sleep_pins_b>; ++ pinctrl-2 = <&uart7_idle_pins_b>; ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++}; ++ ++&usart3 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&usart3_pins_b>; ++ pinctrl-1 = <&usart3_sleep_pins_b>; ++ pinctrl-2 = <&usart3_idle_pins_b>; ++ uart-has-rtscts; ++ status = "disabled"; ++}; ++ ++&usbh_ehci { ++ phys = <&usbphyc_port0>; ++ status = "okay"; ++}; ++ ++&usbotg_hs { ++ phys = <&usbphyc_port1 0>; ++ phy-names = "usb2-phy"; ++ usb-role-switch; ++ status = "okay"; ++ ++ port { ++ usbotg_hs_ep: endpoint { ++ remote-endpoint = <&con_usbotg_hs_ep>; ++ }; ++ }; ++}; ++ ++&usbphyc { ++ status = "okay"; ++}; ++ ++&usbphyc_port0 { ++ phy-supply = <&vdd_usb>; ++ st,phy-tuning = <&usb_phy_tuning>; ++}; ++ ++&usbphyc_port1 { ++ phy-supply = <&vdd_usb>; ++ 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/boot/dts/stm32mp15xx-edx.dtsi b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi +new file mode 100644 +index 000000000..7ed6b14d7 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi +@@ -0,0 +1,408 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++ ++#include ++#include ++ ++/ { ++ memory@c0000000 { ++ device_type = "memory"; ++ reg = <0xC0000000 0x40000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ mcuram2: mcuram2@10000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10000000 0x40000>; ++ no-map; ++ }; ++ ++ vdev0vring0: vdev0vring0@10040000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10040000 0x1000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@10041000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10041000 0x1000>; ++ no-map; ++ }; ++ ++ vdev0buffer: vdev0buffer@10042000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10042000 0x4000>; ++ no-map; ++ }; ++ ++ mcuram: mcuram@30000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x30000000 0x40000>; ++ no-map; ++ }; ++ ++ retram: retram@38000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x38000000 0x10000>; ++ no-map; ++ }; ++ }; ++ ++ 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"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <2900000>; ++ regulator-type = "voltage"; ++ regulator-always-on; ++ ++ gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; ++ gpios-states = <0>; ++ states = <1800000 0x1 2900000 0x0>; ++ }; ++ ++ vin: vin { ++ compatible = "regulator-fixed"; ++ regulator-name = "vin"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++}; ++ ++&adc { ++ /* ANA0, ANA1 are dedicated pins and don't need pinctrl: only in6. */ ++ pinctrl-0 = <&adc1_in6_pins_a>; ++ pinctrl-names = "default"; ++ vdd-supply = <&vdd>; ++ vdda-supply = <&vdda>; ++ vref-supply = <&vdda>; ++ status = "disabled"; ++ adc1: adc@0 { ++ st,adc-channels = <0 1 6>; ++ /* 16.5 ck_cycles sampling time */ ++ st,min-sample-time-nsecs = <400>; ++ status = "okay"; ++ }; ++}; ++ ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&crc1 { ++ status = "okay"; ++}; ++ ++&dac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; ++ vref-supply = <&vdda>; ++ status = "disabled"; ++ dac1: dac@1 { ++ status = "okay"; ++ }; ++ dac2: dac@2 { ++ status = "okay"; ++ }; ++}; ++ ++&dma1 { ++ sram = <&dma_pool>; ++}; ++ ++&dma2 { ++ sram = <&dma_pool>; ++}; ++ ++&dts { ++ status = "okay"; ++}; ++ ++&hash1 { ++ status = "okay"; ++}; ++ ++&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>; ++ clock-frequency = <400000>; ++ status = "okay"; ++ /* spare dmas for other usage */ ++ /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"; ++ ++ regulators { ++ compatible = "st,stpmic1-regulators"; ++ buck1-supply = <&vin>; ++ buck2-supply = <&vin>; ++ buck3-supply = <&vin>; ++ buck4-supply = <&vin>; ++ ldo1-supply = <&v3v3>; ++ ldo2-supply = <&v3v3>; ++ ldo3-supply = <&vdd_ddr>; ++ ldo4-supply = <&vin>; ++ ldo5-supply = <&v3v3>; ++ ldo6-supply = <&v3v3>; ++ vref_ddr-supply = <&vin>; ++ boost-supply = <&vin>; ++ pwr_sw1-supply = <&bst_out>; ++ pwr_sw2-supply = <&bst_out>; ++ ++ vddcore: buck1 { ++ regulator-name = "vddcore"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_ddr: buck2 { ++ regulator-name = "vdd_ddr"; ++ regulator-min-microvolt = <1350000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd: buck3 { ++ regulator-name = "vdd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ st,mask-reset; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ v3v3: buck4 { ++ regulator-name = "v3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ regulator-initial-mode = <0>; ++ }; ++ ++ vdda: ldo1 { ++ regulator-name = "vdda"; ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ interrupts = ; ++ }; ++ ++ v2v8: ldo2 { ++ regulator-name = "v2v8"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ 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 = ; ++ regulator-always-on; ++ }; ++ ++ vdd_sd: ldo5 { ++ regulator-name = "vdd_sd"; ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ interrupts = ; ++ regulator-boot-on; ++ }; ++ ++ v1v8: ldo6 { ++ regulator-name = "v1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ 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 = ; ++ }; ++ ++ vbus_sw: pwr_sw2 { ++ regulator-name = "vbus_sw"; ++ interrupts = ; ++ regulator-active-discharge = <1>; ++ }; ++ }; ++ ++ onkey { ++ compatible = "st,stpmic1-onkey"; ++ interrupts = , ; ++ interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; ++ 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>; ++ wakeup-source; ++ status = "okay"; ++}; ++ ++&pwr_regulators { ++ vdd-supply = <&vdd>; ++ vdd_3v3_usbfs-supply = <&vdd_usb>; ++}; ++ ++&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>; ++ cd-gpios = <&gpiog 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; ++ disable-wp; ++ st,sig-dir; ++ st,neg-edge; ++ st,use-ckin; ++ bus-width = <4>; ++ vmmc-supply = <&vdd_sd>; ++ vqmmc-supply = <&sd_switch>; ++ sd-uhs-sdr12; ++ sd-uhs-sdr25; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ status = "okay"; ++}; ++ ++&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,neg-edge; ++ bus-width = <8>; ++ vmmc-supply = <&v3v3>; ++ vqmmc-supply = <&vdd>; ++ mmc-ddr-3_3v; ++ status = "okay"; ++}; ++ ++&sram { ++ dma_pool: dma_pool@0 { ++ reg = <0x50000 0x10000>; ++ pool; ++ }; ++}; ++ ++&timers6 { ++ status = "okay"; ++ /* spare dmas for other usage */ ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ timer@5 { ++ status = "okay"; ++ }; ++}; ++ ++&uart4 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&uart4_pins_a>; ++ 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"; ++}; ++ ++&usbotg_hs { ++ vbus-supply = <&vbus_otg>; ++}; ++ ++&usbphyc_port0 { ++ phy-supply = <&vdd_usb>; ++}; ++ ++&usbphyc_port1 { ++ phy-supply = <&vdd_usb>; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xx-evx.dtsi b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi +new file mode 100644 +index 000000000..07cb93db9 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi +@@ -0,0 +1,680 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++ ++#include ++#include ++ ++/ { ++ 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>; ++ sound-name-prefix = "dmic0"; ++ status = "okay"; ++ ++ port { ++ dmic0_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint0>; ++ }; ++ }; ++ }; ++ ++ dmic1: dmic-1 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ sound-name-prefix = "dmic1"; ++ status = "okay"; ++ ++ port { ++ dmic1_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint1>; ++ }; ++ }; ++ }; ++ ++ dmic2: dmic-2 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ sound-name-prefix = "dmic2"; ++ status = "okay"; ++ ++ port { ++ dmic2_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint2>; ++ }; ++ }; ++ }; ++ ++ dmic3: dmic-3 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ sound-name-prefix = "dmic3"; ++ 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-0 = <&cec_pins_a>; ++ status = "okay"; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++ðernet0 { ++ status = "okay"; ++ pinctrl-0 = <ðernet0_rgmii_pins_a>; ++ pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; ++ pinctrl-names = "default", "sleep"; ++ phy-mode = "rgmii-id"; ++ 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@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", "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"; ++ reg = <0x3c>; ++ clocks = <&clk_ext_camera>; ++ clock-names = "xclk"; ++ DOVDD-supply = <&v2v8>; ++ 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"; ++ ++ 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>; ++ ++ goodix_pins: goodix { ++ pins = "gpio14"; ++ bias-pull-down; ++ }; ++ ++ joystick_pins: joystick { ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; ++ bias-pull-down; ++ }; ++ }; ++ }; ++}; ++ ++&i2c4 { ++ pmic: stpmic@33 { ++ regulators { ++ v1v8: ldo6 { ++ regulator-enable-ramp-delay = <300000>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c5 { ++ 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; ++ status = "okay"; ++}; ++ ++<dc { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ltdc_ep0_out: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&dsi_in>; ++ }; ++ }; ++}; ++ ++&qspi { ++ 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>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ ++ flash1: mx66l51235l@1 { ++ compatible = "jedec,spi-nor"; ++ reg = <1>; ++ spi-rx-bus-width = <4>; ++ spi-max-frequency = <108000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++}; ++ ++&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 { ++ /* spare dmas for other usage (un-delete to enable pwm capture) */ ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ pwm { ++ pinctrl-0 = <&pwm2_pins_a>; ++ pinctrl-1 = <&pwm2_sleep_pins_a>; ++ pinctrl-names = "default", "sleep"; ++ status = "okay"; ++ }; ++ timer@1 { ++ status = "okay"; ++ }; ++}; ++ ++&timers8 { ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ pwm { ++ pinctrl-0 = <&pwm8_pins_a>; ++ pinctrl-1 = <&pwm8_sleep_pins_a>; ++ pinctrl-names = "default", "sleep"; ++ status = "okay"; ++ }; ++ timer@7 { ++ status = "okay"; ++ }; ++}; ++ ++&timers12 { ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ status = "disabled"; ++ pwm { ++ pinctrl-0 = <&pwm12_pins_a>; ++ pinctrl-1 = <&pwm12_sleep_pins_a>; ++ pinctrl-names = "default", "sleep"; ++ status = "okay"; ++ }; ++ timer@11 { ++ status = "okay"; ++ }; ++}; ++ ++&usart3 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&usart3_pins_a>; ++ pinctrl-1 = <&usart3_sleep_pins_a>; ++ pinctrl-2 = <&usart3_idle_pins_a>; ++ uart-has-rtscts; ++ status = "disabled"; ++}; ++ ++&usbh_ehci { ++ phys = <&usbphyc_port0>; ++ status = "okay"; ++}; ++ ++&usbotg_hs { ++ pinctrl-0 = <&usbotg_hs_pins_a>; ++ pinctrl-names = "default"; ++ phys = <&usbphyc_port1 0>; ++ phy-names = "usb2-phy"; ++ status = "okay"; ++}; ++ ++&usbphyc { ++ status = "okay"; ++}; ++ ++&usbphyc_port0 { ++ st,phy-tuning = <&usb_phy_tuning>; ++}; ++ ++&usbphyc_port1 { ++ st,phy-tuning = <&usb_phy_tuning>; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi +new file mode 100644 +index 000000000..64e566bf8 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi +@@ -0,0 +1,85 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++&pinctrl { ++ 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 { ++ st,package = ; ++ ++ gpioz: gpio@54004000 { ++ status = "okay"; ++ ngpios = <8>; ++ gpio-ranges = <&pinctrl_z 0 400 8>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi +new file mode 100644 +index 000000000..d29af8986 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++&pinctrl { ++ 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/boot/dts/stm32mp15xxac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi +new file mode 100644 +index 000000000..5d8199fd1 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi +@@ -0,0 +1,73 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++&pinctrl { ++ 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 { ++ st,package = ; ++ ++ gpioz: gpio@54004000 { ++ status = "okay"; ++ ngpios = <8>; ++ gpio-ranges = <&pinctrl_z 0 400 8>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi +new file mode 100644 +index 000000000..023f5404c +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++&pinctrl { ++ 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/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h +index 4cdaf1358..ec7b1a932 100644 +--- a/include/dt-bindings/clock/stm32mp1-clks.h ++++ b/include/dt-bindings/clock/stm32mp1-clks.h +@@ -179,6 +179,12 @@ + #define DAC12_K 168 + #define ETHPTP_K 169 + ++#define PCLK1 170 ++#define PCLK2 171 ++#define PCLK3 172 ++#define PCLK4 173 ++#define PCLK5 174 ++ + /* PLL */ + #define PLL1 176 + #define PLL2 177 +@@ -248,4 +254,31 @@ + + #define STM32MP1_LAST_CLK 232 + ++/* SCMI clock identifiers */ ++#define CK_SCMI0_HSE 0 ++#define CK_SCMI0_HSI 1 ++#define CK_SCMI0_CSI 2 ++#define CK_SCMI0_LSE 3 ++#define CK_SCMI0_LSI 4 ++#define CK_SCMI0_PLL2_Q 5 ++#define CK_SCMI0_PLL2_R 6 ++#define CK_SCMI0_MPU 7 ++#define CK_SCMI0_AXI 8 ++#define CK_SCMI0_BSEC 9 ++#define CK_SCMI0_CRYP1 10 ++#define CK_SCMI0_GPIOZ 11 ++#define CK_SCMI0_HASH1 12 ++#define CK_SCMI0_I2C4 13 ++#define CK_SCMI0_I2C6 14 ++#define CK_SCMI0_IWDG1 15 ++#define CK_SCMI0_RNG1 16 ++#define CK_SCMI0_RTC 17 ++#define CK_SCMI0_RTCAPB 18 ++#define CK_SCMI0_SPI6 19 ++#define CK_SCMI0_USART1 20 ++ ++#define CK_SCMI1_PLL3_Q 0 ++#define CK_SCMI1_PLL3_R 1 ++#define CK_SCMI1_MCU 2 ++ + #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ +diff --git a/include/dt-bindings/mfd/stm32f4-rcc.h b/include/dt-bindings/mfd/stm32f4-rcc.h +index 309e8c79f..36448a561 100644 +--- a/include/dt-bindings/mfd/stm32f4-rcc.h ++++ b/include/dt-bindings/mfd/stm32f4-rcc.h +@@ -34,7 +34,6 @@ + #define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8)) + #define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit) + +- + /* AHB2 */ + #define STM32F4_RCC_AHB2_DCMI 0 + #define STM32F4_RCC_AHB2_CRYP 4 +diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h +index e6fb8ada3..370a25a93 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)) +diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h +index f0c3aaef6..bc71924fa 100644 +--- a/include/dt-bindings/reset/stm32mp1-resets.h ++++ b/include/dt-bindings/reset/stm32mp1-resets.h +@@ -105,4 +105,17 @@ + #define GPIOJ_R 19785 + #define GPIOK_R 19786 + ++/* SCMI reset domain identifiers */ ++#define RST_SCMI0_SPI6 0 ++#define RST_SCMI0_I2C4 1 ++#define RST_SCMI0_I2C6 2 ++#define RST_SCMI0_USART1 3 ++#define RST_SCMI0_STGEN 4 ++#define RST_SCMI0_GPIOZ 5 ++#define RST_SCMI0_CRYP1 6 ++#define RST_SCMI0_HASH1 7 ++#define RST_SCMI0_RNG1 8 ++#define RST_SCMI0_MDMA 9 ++#define RST_SCMI0_MCU 10 ++ + #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ +diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h +new file mode 100644 +index 000000000..4373c4dea +--- /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 000000000..d98665327 +--- /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 */ +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch similarity index 86% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch index fce739b..7bc22da 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch @@ -1,22 +1,22 @@ -From 62cd375deb0762da00fbfce0f211a02404f5ab54 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:53 +0100 -Subject: [PATCH 31/31] ARM stm32mp1 r3 DEFCONFIG +From c85af400114b9a862a0e9df538d00e1eb42d0028 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:50:29 +0200 +Subject: [PATCH 21/23] ARM-stm32mp1-r1-CONFIG --- - .../arm/configs/fragment-01-multiv7_cleanup.config | 69 +++ - arch/arm/configs/fragment-02-multiv7_addons.config | 508 +++++++++++++++++++++ - arch/arm/configs/multi_v7_defconfig | 1 + - 3 files changed, 578 insertions(+) + .../fragment-01-multiv7_cleanup.config | 152 +++++++ + .../configs/fragment-02-multiv7_addons.config | 420 ++++++++++++++++++ + arch/arm/configs/multi_v7_defconfig | 1 + + 3 files changed, 573 insertions(+) create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config diff --git a/arch/arm/configs/fragment-01-multiv7_cleanup.config b/arch/arm/configs/fragment-01-multiv7_cleanup.config new file mode 100644 -index 0000000..22f6ffb +index 000000000..76dd83cf0 --- /dev/null +++ b/arch/arm/configs/fragment-01-multiv7_cleanup.config -@@ -0,0 +1,69 @@ +@@ -0,0 +1,152 @@ +# +# CPU Core family selection +# @@ -35,6 +35,7 @@ index 0000000..22f6ffb +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MEDIATEK is not set + ++ +# +# TI OMAP/AM/DM/DRA Family +# @@ -82,47 +83,10 @@ index 0000000..22f6ffb +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set + -+ -+ -+ -+ -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -new file mode 100644 -index 0000000..e68bb1e ---- /dev/null -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -0,0 +1,508 @@ -+# -+# General setup -+# -+CONFIG_POSIX_MQUEUE=y -+CONFIG_USELIB=y -+CONFIG_FUTEX=y -+ -+# -+# RCU Subsystem -+# -+# allow user to access kernel config through /proc/config.gz -+CONFIG_IKCONFIG=y -+CONFIG_IKCONFIG_PROC=y -+CONFIG_LOG_BUF_SHIFT=16 -+CONFIG_MEMCG=y -+CONFIG_NAMESPACES=y -+ -+# -+# Kernel Performance Events And Counters -+# -+CONFIG_PROFILING=y -+ -+# -+# CPU Core family selection -+# -+ +# +# Processor Features +# +# CONFIG_CACHE_L2X0 is not set -+ +# +# Bus support +# @@ -133,128 +97,29 @@ index 0000000..e68bb1e +# +# Kernel Features +# -+CONFIG_SCHED_MC=y -+CONFIG_MCPM=y -+CONFIG_NR_CPUS=4 +# CONFIG_PREEMPT_NONE is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_COUNT=y -+CONFIG_AEABI=y -+CONFIG_HIGHMEM=y -+CONFIG_FORCE_MAX_ZONEORDER=12 + +# +# Boot options +# +# CONFIG_ATAGS is not set -+CONFIG_ZBOOT_ROM_TEXT=0x0 -+CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_KEXEC is not set -+ -+# -+# CPU Power Management -+# -+# -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_EFI is not set + +# +# CPU Idle +# +# CONFIG_CPU_IDLE is not set -+ -+# -+# Floating point emulation -+# -+CONFIG_VFP=y -+ -+# -+# Networking options -+# -+CONFIG_DNS_RESOLVER=y -+ -+# -+# CAN Device Drivers -+# -+CONFIG_CAN_M_CAN=y -+ +# +# CAN SPI interfaces +# +# CONFIG_CAN_MCP251X is not set -+ -+# -+# CAN USB interfaces -+# -+ -+# -+# Bluetooth device drivers -+# -+CONFIG_BT_RTL=m -+CONFIG_BT_HCIBTUSB=m -+CONFIG_BT_HCIBTUSB=m -+CONFIG_BT_HCIBTUSB_RTL=y -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y -+ -+# -+# Default contiguous memory area size: -+# -+CONFIG_CMA_SIZE_MBYTES=128 -+ -+# -+# Disk-On-Chip Device Drivers -+# -+ -+# -+# LPDDR & LPDDR2 PCM memory drivers -+# -+ -+# -+# Misc devices -+# -+CONFIG_SRAM=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_CHR_DEV_SG=y -+ -+# -+# MII PHY device drivers -+# -+CONFIG_RTL_CARDS=m -+CONFIG_RTL8192CU=m -+CONFIG_RTLWIFI=m -+CONFIG_RTLWIFI_USB=m -+CONFIG_RTLWIFI_DEBUG=y -+CONFIG_RTL8192C_COMMON=m -+# -+# Input Device Drivers -+# -+ -+# -+# Character devices -+# -+CONFIG_SERIAL_NONSTANDARD=y -+ +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# -+# Touchscreen drivers -+# -+CONFIG_TOUCHSCREEN_EDT_FT5X06=m -+CONFIG_TOUCHSCREEN_GOODIX=m -+ -+# +# Non-8250 serial port support +# +# CONFIG_SERIAL_BCM63XX is not set @@ -279,28 +144,183 @@ index 0000000..e68bb1e +# CONFIG_I2C_SLAVE_EEPROM is not set + +# ++# STMicroelectronics STMPE Interface Drivers ++# ++# CONFIG_REGULATOR_WM8994 is not set ++ ++# ++# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) ++# ++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MUSB_HDRC is not set ++# CONFIG_USB_DWC3 is not set ++ ++# ++# USB GPIO expanders ++# ++# CONFIG_POWER_AVS is not set ++# CONFIG_POWER_SUPPLY is not set ++ ++# ++# Debug Lockups and Hangs ++# ++# CONFIG_SCHED_DEBUG is not set +diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config +new file mode 100644 +index 000000000..62c0de302 +--- /dev/null ++++ b/arch/arm/configs/fragment-02-multiv7_addons.config +@@ -0,0 +1,420 @@ ++# ++# General setup ++# ++CONFIG_POSIX_MQUEUE=y ++CONFIG_USELIB=y ++CONFIG_FUTEX=y ++ ++# ++# RCU Subsystem ++# ++# allow user to access kernel config through /proc/config.gz ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=16 ++CONFIG_MEMCG=y ++CONFIG_NAMESPACES=y ++ ++# ++# Kernel Performance Events And Counters ++# ++CONFIG_PROFILING=y ++ ++# ++# Kernel Features ++# ++CONFIG_SCHED_MC=y ++CONFIG_MCPM=y ++CONFIG_NR_CPUS=2 ++CONFIG_PREEMPT=y ++CONFIG_PREEMPT_COUNT=y ++CONFIG_AEABI=y ++CONFIG_HIGHMEM=y ++CONFIG_FORCE_MAX_ZONEORDER=12 ++ ++# ++# Boot options ++# ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++ ++# ++# CPU Power Management ++# ++# ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y ++ ++ ++# ++# Floating point emulation ++# ++CONFIG_VFP=y ++ ++# ++# Networking options ++# ++CONFIG_DNS_RESOLVER=y ++ ++# ++# CAN Device Drivers ++# ++CONFIG_CAN_M_CAN=y ++CONFIG_CAN_M_CAN_PLATFORM=y ++ ++# ++# CAN USB interfaces ++# ++ ++# ++# Bluetooth device drivers ++# ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y ++ ++# ++# Default contiguous memory area size: ++# ++CONFIG_CMA_SIZE_MBYTES=128 ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set ++ ++# ++# LPDDR & LPDDR2 PCM memory drivers ++# ++ ++# ++# Misc devices ++# ++CONFIG_SRAM=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_CHR_DEV_SG=y ++ ++# ++# MII PHY device drivers ++# ++ ++# ++# Input Device Drivers ++# ++ ++# ++# Touchscreen drivers ++# ++CONFIG_TOUCHSCREEN_EDT_FT5X06=y ++CONFIG_TOUCHSCREEN_GOODIX=y ++ ++# ++# Character devices ++# ++CONFIG_SERIAL_NONSTANDARD=y ++ ++# +# SPI Master Controller Drivers +# -+CONFIG_SPI_STM32=y -+CONFIG_SPI_STM32_QSPI=y + +# +# Pin controllers +# -+CONFIG_PINCTRL_STMFX=y + +# +# Memory mapped GPIO drivers +# + +# ++# Memory Technology Device (MTD) support ++# ++ ++CONFIG_MTD_SPI_NAND=y ++ ++# +# USB GPIO expanders +# -+# CONFIG_POWER_AVS is not set +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y -+CONFIG_SYSCON_REBOOT_MODE=y -+# CONFIG_POWER_SUPPLY is not set + +# +# Native drivers @@ -312,12 +332,11 @@ index 0000000..e68bb1e +# STMicroelectronics thermal drivers +# + -+ -+ +# +# Watchdog Device Drivers +# +CONFIG_WATCHDOG_NOWAYOUT=y ++CONFIG_WATCHDOG_SYSFS=y + +# +# Sonics Silicon Backplane @@ -329,9 +348,9 @@ index 0000000..e68bb1e +CONFIG_PROTECTION_CONSUMER=y + +# -+# STMicroelectronics STMPE Interface Drivers ++# Regulator drivers +# -+# CONFIG_REGULATOR_WM8994 is not set ++CONFIG_REGULATOR_STM32_PWR=y + +# +# Multimedia core support @@ -343,14 +362,10 @@ index 0000000..e68bb1e +CONFIG_VIDEO_STM32_HDMI_CEC=m + +# -+# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) -+# -+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -+ -+# +# Camera sensor devices +# -+CONFIG_VIDEO_OV5640=y ++CONFIG_VIDEO_OV5640=m ++CONFIG_VIDEO_ST_MIPID02=m + +# +# Graphics support @@ -372,7 +387,7 @@ index 0000000..e68bb1e +# +# Display Interface Bridges +# -+CONFIG_VIDEO_ADV7511=y ++CONFIG_DRM_I2C_ADV7511=y +CONFIG_DRM_SII902X=y + +# @@ -410,7 +425,6 @@ index 0000000..e68bb1e +CONFIG_SND_SOC_DMIC=y +CONFIG_SND_SOC_CS42L42=y +CONFIG_SND_SOC_CS42L51_I2C=y -+ +# +# USB Device Class drivers +# @@ -421,12 +435,6 @@ index 0000000..e68bb1e +# + +# -+# USB Imaging devices -+# -+# CONFIG_USB_MUSB_HDRC is not set -+# CONFIG_USB_DWC3 is not set -+ -+# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# +CONFIG_USB_CONFIGFS=y @@ -457,7 +465,6 @@ index 0000000..e68bb1e +# File systems +# +CONFIG_OVERLAY_FS=y -+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_JFFS2_FS=y + +# @@ -484,7 +491,6 @@ index 0000000..e68bb1e +# +# Debug Lockups and Hangs +# -+# CONFIG_SCHED_DEBUG is not set +CONFIG_DEBUG_PREEMPT=y + +# @@ -495,6 +501,9 @@ index 0000000..e68bb1e +# +CONFIG_KEYS=y + ++CONFIG_CRYPTO_DEV_STM32_CRC=y ++CONFIG_CRYPTO_DEV_STM32_HASH=y ++CONFIG_CRYPTO_DEV_STM32_CRYP=y + +# +# Library routines @@ -502,61 +511,35 @@ index 0000000..e68bb1e +CONFIG_CRC_ITU_T=m + +# -+# STM32 PWR -+# -+CONFIG_MFD_STM32MP1_PWR=y -+CONFIG_REGULATOR_STM32_PWR=y -+ -+# -+# STPMIC1 -+# -+CONFIG_MFD_STPMIC1=y -+CONFIG_REGULATOR_STPMIC1=y -+CONFIG_STPMIC1_WATCHDOG=y -+CONFIG_INPUT_STPMIC1_ONKEY=y -+ -+# -+# STM32 TIMER -+# -+CONFIG_MFD_STM32_TIMERS=y -+CONFIG_IIO_STM32_TIMER_TRIGGER=y -+CONFIG_PWM_STM32=y -+ -+# -+# STM32 LPTIMER -+# -+CONFIG_MFD_STM32_LPTIMER=y -+CONFIG_PWM_STM32_LP=y -+CONFIG_IIO_STM32_LPTIMER_TRIGGER=y -+CONFIG_STM32_LPTIMER_CNT=y -+ -+# +# STM32 DFSDM +# +CONFIG_SD_ADC_MODULATOR=y +CONFIG_STM32_DFSDM_ADC=y + +# -+# FMC2 -+# -+CONFIG_MTD_NAND_STM32_FMC2=y -+ -+# -+# STM32 VREFBUF -+# -+CONFIG_REGULATOR_STM32_VREFBUF=y -+ -+# +# STM32 BSEC NVMEM +# +CONFIG_NVMEM_STM32_ROMEM=y + +# ++# STM32 HSEM ++# ++CONFIG_HWSPINLOCK=y ++CONFIG_HWSPINLOCK_STM32=y ++ ++# +# STM32 IPCC +# +CONFIG_STM32_IPCC=y + +# ++# STM32 RPROC ++# ++CONFIG_REMOTEPROC=y ++CONFIG_STM32_RPROC=y ++CONFIG_RPMSG_VIRTIO=y ++ ++# +# RPMSG_TTY +# +CONFIG_RPMSG_VIRTIO=y @@ -569,26 +552,27 @@ index 0000000..e68bb1e +CONFIG_SAMPLE_RPMSG_CLIENT=m + +# -+# STM32 RPROC ++# STM32 TIMER +# -+# CONFIG_MAILBOX is not set -+CONFIG_REMOTEPROC=y -+CONFIG_STM32_RPROC=y -+CONFIG_RPMSG_VIRTIO=y ++CONFIG_MFD_STM32_TIMERS=y ++CONFIG_IIO_STM32_TIMER_TRIGGER=y ++CONFIG_PWM_STM32=y ++CONFIG_COUNTER=y ++CONFIG_STM32_TIMER_CNT=y + +# -+# Cryptographic ++# STM32 LPTIMER +# -+CONFIG_CRYPTO_DEV_STM32_CRC=y -+CONFIG_CRYPTO_DEV_STM32_HASH=y -+CONFIG_CRYPTO_DEV_STM32_CRYP=y ++CONFIG_MFD_STM32_LPTIMER=y ++CONFIG_PWM_STM32_LP=y ++CONFIG_IIO_STM32_LPTIMER_TRIGGER=y ++CONFIG_STM32_LPTIMER_CNT=y + +# +# STM32 ADC +# +CONFIG_STM32_ADC_CORE=y +CONFIG_STM32_ADC=y -+CONFIG_STM32_ADC_TEMP=y + +# +# STM32 DAC @@ -596,22 +580,33 @@ index 0000000..e68bb1e +CONFIG_STM32_DAC=y + +# -+# STM32 HSEM ++# STM32 VREFBUF +# -+CONFIG_HWSPINLOCK=y -+CONFIG_HWSPINLOCK_STM32=y ++CONFIG_REGULATOR_STM32_VREFBUF=y ++ ++# ++# SCMI ++# ++CONFIG_ARM_SCMI_PROTOCOL=y ++CONFIG_COMMON_CLK_SCMI=y ++CONFIG_ARM_SMC_MBOX=y ++ ++# ++# TTY ++# ++CONFIG_LEGACY_PTY_COUNT=8 diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig -index fc33444..ac1e50b 100644 +index e4c8def9a..4231ad37e 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig -@@ -946,6 +946,7 @@ CONFIG_PHY_DM816X_USB=m - CONFIG_OMAP_USB2=y - CONFIG_TI_PIPE3=y +@@ -1038,6 +1038,7 @@ CONFIG_TI_PIPE3=y CONFIG_TWL4030_USB=m + CONFIG_MESON_MX_EFUSE=m + CONFIG_ROCKCHIP_EFUSE=m +CONFIG_STM32_DDR_PMU=y CONFIG_NVMEM_IMX_OCOTP=y CONFIG_NVMEM_SUNXI_SID=y CONFIG_NVMEM_VF610_OCOTP=y -- -2.7.4 +2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch new file mode 100644 index 0000000..d9e6f94 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch @@ -0,0 +1,24 @@ +From 65ad7ed110b25b333679e5084fb82db0d5a15a6c Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Fri, 10 Apr 2020 14:50:46 +0200 +Subject: [PATCH 22/23] ARM-stm32mp1-r1-POWER + +--- + kernel/power/suspend.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 27f149f5d..4581702e8 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -34,7 +34,6 @@ + #include "power.h" + + const char * const pm_labels[] = { +- [PM_SUSPEND_TO_IDLE] = "freeze", + [PM_SUSPEND_STANDBY] = "standby", + [PM_SUSPEND_MEM] = "mem", + }; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch index 74c1af4..d69e92f 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch @@ -1,20 +1,20 @@ -From 6b4eeb6fe243c0c077a9b9ce4f631a5310f7b058 Mon Sep 17 00:00:00 2001 -From: Lionel VITTE -Date: Fri, 8 Nov 2019 16:52:43 +0100 -Subject: [PATCH 18/31] ARM stm32mp1 r3 PERF +From cc23b579a850b77f33f331fe854a4d52910ed0d1 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 9 Jun 2020 13:06:44 +0200 +Subject: [PATCH 23/23] ARM-stm32mp1-r1-PERF --- Documentation/perf/stm32-ddr-pmu.txt | 41 +++ drivers/perf/Kconfig | 6 + drivers/perf/Makefile | 1 + - drivers/perf/stm32_ddr_pmu.c | 505 +++++++++++++++++++++++++++++++++++ + drivers/perf/stm32_ddr_pmu.c | 505 +++++++++++++++++++++++++++ 4 files changed, 553 insertions(+) create mode 100644 Documentation/perf/stm32-ddr-pmu.txt create mode 100644 drivers/perf/stm32_ddr_pmu.c diff --git a/Documentation/perf/stm32-ddr-pmu.txt b/Documentation/perf/stm32-ddr-pmu.txt new file mode 100644 -index 0000000..d5b35b3 +index 000000000..d5b35b326 --- /dev/null +++ b/Documentation/perf/stm32-ddr-pmu.txt @@ -0,0 +1,41 @@ @@ -60,10 +60,10 @@ index 0000000..d5b35b3 + $ cat /sys/bus/event_source/devices/ddrperfm/bandwidth + Read = 403, Write = 239, Read & Write = 642 (MB/s) diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig -index 08ebaf7..57e8f6c 100644 +index 09ae8a970..2c5041314 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig -@@ -87,6 +87,12 @@ config QCOM_L3_PMU +@@ -105,6 +105,12 @@ config QCOM_L3_PMU Adds the L3 cache PMU into the perf events subsystem for monitoring L3 cache events. @@ -73,23 +73,24 @@ index 08ebaf7..57e8f6c 100644 + help + Support for STM32 DDR performance monitor (DDRPERFM). + - config XGENE_PMU - depends on ARCH_XGENE - bool "APM X-Gene SoC PMU" + config THUNDERX2_PMU + tristate "Cavium ThunderX2 SoC PMU UNCORE" + depends on ARCH_THUNDER2 && ARM64 && ACPI && NUMA diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile -index b3902bd..04f7f64 100644 +index 2ebb4de17..fd3368c1b 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile -@@ -7,5 +7,6 @@ obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o +@@ -9,6 +9,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o obj-$(CONFIG_HISI_PMU) += hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o +obj-$(CONFIG_STM32_DDR_PMU) += stm32_ddr_pmu.o + obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c new file mode 100644 -index 0000000..4f30f6f +index 000000000..4f30f6f8b --- /dev/null +++ b/drivers/perf/stm32_ddr_pmu.c @@ -0,0 +1,505 @@ @@ -599,5 +600,5 @@ index 0000000..4f30f6f +MODULE_AUTHOR("Gerald Baeza "); +MODULE_LICENSE("GPL v2"); -- -2.7.4 +2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-03-systemd.config similarity index 100% rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config rename to recipes-kernel/linux/linux-stm32mp/5.4/fragment-03-systemd.config diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-04-optee.config b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-04-optee.config similarity index 100% rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-04-optee.config rename to recipes-kernel/linux/linux-stm32mp/5.4/fragment-04-optee.config diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-05-modules.config similarity index 81% rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config rename to recipes-kernel/linux/linux-stm32mp/5.4/fragment-05-modules.config index d15f1c7..94b8df6 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config +++ b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-05-modules.config @@ -13,3 +13,9 @@ CONFIG_IIO_ST_LSM6DSX_I2C=m # support of event emulation CONFIG_INPUT_UINPUT=m + +# USBIP +CONFIG_USBIP_CORE=m +CONFIG_USBIP_HOST=m +# CONFIG_USBIP_DEBUG is not set + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/fragment-06-signature.config b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-06-signature.config new file mode 100644 index 0000000..dba65a8 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/fragment-06-signature.config @@ -0,0 +1,10 @@ +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_SHA256=y +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +CONFIG_MODULE_SIG_SHA256=y +# CONFIG_MODULE_SIG_SHA384 is not set +# CONFIG_MODULE_SIG_SHA512 is not set diff --git a/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt b/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt index 3baf91f..8aee00f 100644 --- a/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt +++ b/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt @@ -12,12 +12,15 @@ Compilation of kernel: OpenSTLinux SDK must be installed. For kernel build, you need to install: -- libncurses and libncursesw dev package - Ubuntu: sudo apt-get install libncurses5-dev libncursesw5-dev - Fedora: sudo yum install ncurses-devel +- libncurses and libncursesw dev package libyaml-dev + Ubuntu: sudo apt-get install libncurses5-dev libncursesw5-dev libyaml-dev + Fedora: sudo yum install ncurses-devel libyaml-devel - mkimage Ubuntu: sudo apt-get install u-boot-tools Fedora: sudo yum install u-boot-tools +- yaml (check dts) + Ubuntu: sudo apt-get install libyaml-dev + Fedora: sudo yum install libyaml-devel Only if you like to have a git management of the code (see section 4 [Manage the kernel source code]): @@ -26,18 +29,18 @@ Only if you like to have a git management of the code (see section 4 Fedora: sudo yum install git If you have never configured your git configuration, run the following commands: - $> git config --global user.name "your_name" - $> git config --global user.email "your_email@example.com" + $ git config --global user.name "your_name" + $ git config --global user.email "your_email@example.com" 2. Initialise cross-compilation via SDK: ---------------------------------------- Source SDK environment: - $> source /environment-setup-cortexa7t2hf-neon-vfpv4-openstlinux_weston-linux-gnueabi + $ source /environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi To verify if your cross-compilation environment has been put in place correctly, run the following command: - $> set | grep CROSS - CROSS_COMPILE=arm-openstlinux_weston-linux-gnueabi- + $ set | grep CROSS + CROSS_COMPILE=arm-ostl-linux-gnueabi- Warning: the environment is valid only on the shell session where you have sourced the SDK environment. @@ -46,18 +49,14 @@ sourced the SDK environment. ------------------------- If you have the tarball and the list of patches, then you must extract the tarball and apply the patches. - $> tar xfz .tar.gz - or - $> tar xfj .tar.bz2 - or - $> tar xfJ .tar.xz + $> tar xfJ linux-##PV##.tar.xz A new directory containing kernel standard source code will be created, go into it: - $> cd + $> cd linux-##PV## NB: if you like to have a git management of the code, see section 4 [Manage the kernel source code] if there is some patch, please apply it on source code - $> for p in `ls -1 /*.patch`; do patch -p1 < $p; done + $> for p in `ls -1 ../*.patch`; do patch -p1 < $p; done 4. Manage the kernel source code: --------------------------------- @@ -67,11 +66,11 @@ If you like to have a better management of change made on kernel source, you can use git. * With the kernel source code extracted in the section 3 [Prepare kernel source] - $> cd - $> test -d .git || git init . && git add . && git commit -m "new kernel" && git gc - $> git checkout -b WORKING + $ cd + $ test -d .git || git init . && git add . && git commit -m "new kernel" && git gc + $ git checkout -b WORKING Apply patches: - $> for p in `ls -1 /*.patch`; do git am $p; done + $ for p in `ls -1 /*.patch`; do git am $p; done NB: this is the fastest way to get your kernel source code ready for development Or @@ -81,10 +80,10 @@ Or Branch: ##GIT_BRANCH## Revision: ##GIT_SRCREV## - $> git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git - $> cd - $> git checkout -b WORKING ##GIT_SRCREV## - $> for p in `ls -1 /*.patch`; do git am $p; done + $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git + $ cd + $ git checkout -b WORKING ##GIT_SRCREV## + $ for p in `ls -1 /*.patch`; do git am $p; done NB: this way is slightly slower than the tarball extraction but you get advantage of all git history. @@ -94,8 +93,8 @@ If you are using git for managing your source code, kernel makefile get the SHA1 of current git and add it to kernel version number generated. ex.: 4.9.23-g3e866b0 (kernel version + SHA1 of current git commit) To bypass this auto-generation of kernel version number: - $> cd - $> echo "" > .scmversion + $ cd + $ echo "" > .scmversion This file avoid to have a kernel version with SHA1: - With scmversion file: 4.9.23 - Without scmversion file: 4.9.23-g3e866b0 @@ -121,33 +120,33 @@ We highly preconized the build is a build directory method as: * Configure on a build directory (different of kernel source code directory) Here for example, build directory is located at the same level of kernel source code - $> cd + $ cd $> mkdir -p ../build $> make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment*.config If there are some fragments, apply them * manually one by one: - $> scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-01-xxx.config - $> scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-02-xxx.config + $ scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-01-xxx.config + $ scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-02-xxx.config ... - $> yes '' | make ARCH=arm oldconfig O="$PWD/../build" + $ yes '' | make ARCH=arm oldconfig O="$PWD/../build" * or, by loop: $> for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config $f; done $> yes '' | make ARCH=arm oldconfig O="$PWD/../build" * Configure on the current source code directory - $> cd - $> make ARCH=arm multi_v7_defconfig fragment*.config + $ cd + $ make ARCH=arm multi_v7_defconfig fragment*.config If there are some fragments, apply them * manually one by one: - $> scripts/kconfig/merge_config.sh -m -r .config ../fragment-01-xxxx.config - $> scripts/kconfig/merge_config.sh -m -r .config ../fragment-02-xxxx.config + $ scripts/kconfig/merge_config.sh -m -r .config ../fragment-01-xxxx.config + $ scripts/kconfig/merge_config.sh -m -r .config ../fragment-02-xxxx.config ... - $> yes '' | make oldconfig + $ yes '' | make oldconfig * or, by loop: - $> for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done - $> yes '' | make ARCH=arm oldconfig + $ for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done + $ yes '' | make ARCH=arm oldconfig NB: Two types of fragments are provided: * official fragments (fragment-xxx.config) @@ -168,7 +167,7 @@ managment of changes made on source code (as all build artifacts will be located inside the dedicated build directory). * Compile and install on a build directory (different of kernel source code directory) - $> cd + $ cd * Build kernel images (uImage and vmlinux) and device tree (dtbs) $> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 O="$PWD/../build" * Build kernel module @@ -181,28 +180,34 @@ inside the dedicated build directory). or - $> cd + $ cd * Build kernel images (uImage and vmlinux) and device tree (dtbs) - $> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 + $ make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 * Build kernel module - $> make ARCH=arm modules + $ make ARCH=arm modules * Generate output build artifacts - $> make ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install - $> mkdir -p $PWD/../build/install_artifact/boot/ - $> cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/ - $> cp $PWD/../build/arch/arm/boot/dts/st*.dtb $PWD/../build/install_artifact/boot/ + $ make ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install + $ mkdir -p $PWD/../build/install_artifact/boot/ + $ cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/ + $ cp $PWD/../build/arch/arm/boot/dts/st*.dtb $PWD/../build/install_artifact/boot/ * Compile and install on the current source code directory - $> cd + $ cd * Build kernel images (uImage and vmlinux) and device tree (dtbs) - $> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 + $ make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 * Build kernel module - $> make ARCH=arm modules + $ make ARCH=arm modules * Generate output build artifacts - $> make ARCH=arm INSTALL_MOD_PATH="$PWD/install_artifact" modules_install - $> mkdir -p $PWD/install_artifact/boot/ - $> cp $PWD/arch/arm/boot/uImage $PWD/install_artifact/boot/ - $> cp $PWD/arch/arm/boot/dts/st*.dtb $PWD/install_artifact/boot/ + $ make ARCH=arm INSTALL_MOD_PATH="$PWD/install_artifact" modules_install + $ mkdir -p $PWD/install_artifact/boot/ + $ cp $PWD/arch/arm/boot/uImage $PWD/install_artifact/boot/ + $ cp $PWD/arch/arm/boot/dts/st*.dtb $PWD/install_artifact/boot/ + +Generated files are : + #> $PWD/install_artifact/boot/uImage + #> $PWD/install_artifact/boot/.dtb + + 7. Update software on board: ---------------------------- @@ -217,63 +222,63 @@ Please refer to User guide for more details. 7.2. Update via network: ------------------------ * kernel + devicetree - $> cd /install_artifact + $ cd /install_artifact if bootfs are not monted on target, mount it - $> ssh root@ df to see if there is a partition mounted on /boot + $ ssh root@ df to see if there is a partition mounted on /boot else - $> ssh root@ mount /boot - $> scp -r boot/* root@:/boot/ - $> ssh root@ umount /boot + $ ssh root@ mount /boot + $ scp -r boot/* root@:/boot/ + $ ssh root@ umount /boot * kernel modules - $> cd /install_artifact + $ cd /install_artifact Remove the link on install_artifact/lib/modules// - $> rm lib/modules//source lib/modules//build + $ rm lib/modules//source lib/modules//build Optionally, strip kernel modules (to reduce the size of each kernel modules) - $> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates + $ find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates Copy kernel modules: - $> scp -r lib/modules/* root@:/lib/modules/ + $ scp -r lib/modules/* root@:/lib/modules/ Generate a list of module dependencies (modules.dep) and a list of symbols provided by modules (modules.symbols): - $> ssh root@ /sbin/depmod -a + $ ssh root@ /sbin/depmod -a Synchronize data on disk with memory - $> ssh root@ sync + $ ssh root@ sync Reboot the board in order to take update into account - $> ssh root@ reboot + $ ssh root@ reboot 7.3. Update via SDCARD on your Linux PC: ---------------------------------------- * kernel + devicetree - $> cd /install_artifact + $ cd /install_artifact Verify sdcard are mounted on your Linux PC: /media/$USER/bootfs - $> cp -r boot/* /media/$USER/bootfs/ + $ cp -r boot/* /media/$USER/bootfs/ Depending of your Linux configuration, you may call the command under sudo - $> sudo cp -r boot/* /media/$USER/bootfs/ + $ sudo cp -r boot/* /media/$USER/bootfs/ Don't forget to unmount properly sdcard * kernel modules - $> cd /install_artifact + $ cd /install_artifact Remove the link on install_artifact/lib/modules// - $> rm lib/modules//source lib/modules//build + $ rm lib/modules//source lib/modules//build Optionally, strip kernel modules (to reduce the size of each kernel modules) - $> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates + $ find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates Verify sdcard are mounted on your Linux PC: /media/$USER/rootfs Copy kernel modules: - $> cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ + $ cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ Depending of your Linux configuration, you may call the command under sudo - $> sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ + $ sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ Don't forget to unmount properly sdcard Generate a list of module dependencies (modules.dep) and a list of symbols provided by modules (modules.symbols): - $> ssh root@ depmod -a + $ ssh root@ depmod -a Synchronize data on disk with memory - $> ssh root@ sync + $ ssh root@ sync Reboot the board in order to take update into account - $> ssh root@ reboot + $ ssh root@ reboot 7.4. Update via SDCARD on your BOARD (via U-Boot): -------------------------------------------------- @@ -291,32 +296,32 @@ For SDCARD: ums 0 mmc 0 For USB Disk: ums 0 usb 0 * kernel + devicetree - $> cd /install_artifact + $ cd /install_artifact Remove the link on install_artifact/lib/modules// - $> rm lib/modules//source lib/modules//build + $ rm lib/modules//source lib/modules//build Optionally, strip kernel modules (to reduce the size of each kernel modules) - $> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates + $ find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates Verify sdcard mount point are mounted on your Linux PC: /media/$USER/bootfs - $> cp -r boot/* /media/$USER/bootfs/ + $ cp -r boot/* /media/$USER/bootfs/ Depending of your Linux configuration, you may call the command under sudo - $> sudo cp -rf boot/* /media/$USER/bootfs/ + $ sudo cp -rf boot/* /media/$USER/bootfs/ Don't forget to unmount properly sdcard Warning: kernel and device tree file name must be aligned between extlinux.conf file and file system. * kernel modules - $> cd /install_artifact + $ cd /install_artifact Remove the link on install_artifact/lib/modules// - $> rm lib/modules//source lib/modules//build + $ rm lib/modules//source lib/modules//build Optionally, strip kernel modules (to reduce the size of each kernel modules) - $> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates + $ find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates Verify sdcard mount point are mounted on your Linux PC: /media/$USER/rootfs Copy kernel modules: - $> cp -rf lib/modules/* /media/$USER/rootfs/lib/modules/ + $ cp -rf lib/modules/* /media/$USER/rootfs/lib/modules/ Depending of your Linux configuration, you may call the command under sudo - $> sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ + $ sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/ Don't forget to unmount properly sdcard At next runtime, don't forget to generate a list of module dependencies @@ -338,13 +343,13 @@ For USB Disk: ums 0 usb 0 $on board> lsmod * How to see information about kernel module: - $on board> modinfo ./install_artifact/lib/modules//kernel/drivers/leds/led-class-flash.ko -Example usage: -filename: ./install_artifact/lib/modules/4.9.23-g3e866b0/kernel/drivers/leds/led-class-flash.ko + $on board> modinfo /lib/modules/5.4.31/kernel/drivers/leds/led-class-flash.ko +filename: /lib/modules/5.4.31/kernel/drivers/leds/led-class-flash.ko license: GPL v2 description: LED Flash class interface author: Jacek Anaszewski -depends: +depends: intree: Y -vermagic: 4.9.23-g3e866b0 SMP mod_unload ARMv7 p2v8 +name: led_class_flash +vermagic: 5.4.31 SMP preempt mod_unload modversions ARMv7 p2v8 diff --git a/recipes-kernel/linux/linux-stm32mp_4.19.bb b/recipes-kernel/linux/linux-stm32mp_4.19.bb deleted file mode 100644 index 7d7bf8f..0000000 --- a/recipes-kernel/linux/linux-stm32mp_4.19.bb +++ /dev/null @@ -1,95 +0,0 @@ -SUMMARY = "Linux STM32MP Kernel" -SECTION = "kernel" -LICENSE = "GPLv2" -LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814" - -include linux-stm32mp.inc - -SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.94.tar.xz" -SRC_URI[md5sum] = "3f5621e9b463a3574618f3edfe438e4a" -SRC_URI[sha256sum] = "c62a10a75a7c4213e41287040e7c7509b7d42117d6830feb7dfe505949fa7467" - -SRC_URI += " \ - file://${LINUX_VERSION}/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch \ - file://${LINUX_VERSION}/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch \ - file://${LINUX_VERSION}/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch \ - file://${LINUX_VERSION}/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch \ - file://${LINUX_VERSION}/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch \ - file://${LINUX_VERSION}/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch \ - file://${LINUX_VERSION}/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch \ - file://${LINUX_VERSION}/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch \ - file://${LINUX_VERSION}/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch \ - file://${LINUX_VERSION}/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch \ - file://${LINUX_VERSION}/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch \ - file://${LINUX_VERSION}/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch \ - file://${LINUX_VERSION}/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch \ - file://${LINUX_VERSION}/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch \ - file://${LINUX_VERSION}/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch \ - file://${LINUX_VERSION}/4.19.94/0016-ARM-stm32mp1-r3-NET.patch \ - file://${LINUX_VERSION}/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch \ - file://${LINUX_VERSION}/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch \ - file://${LINUX_VERSION}/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch \ - file://${LINUX_VERSION}/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch \ - file://${LINUX_VERSION}/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch \ - file://${LINUX_VERSION}/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch \ - file://${LINUX_VERSION}/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch \ - file://${LINUX_VERSION}/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch \ - file://${LINUX_VERSION}/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch \ - file://${LINUX_VERSION}/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch \ - file://${LINUX_VERSION}/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch \ - file://${LINUX_VERSION}/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch \ - file://${LINUX_VERSION}/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch \ - file://${LINUX_VERSION}/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch \ - " - -LINUX_VERSION = "4.19" - -PV = "${LINUX_VERSION}" - -S = "${WORKDIR}/linux-4.19.94" - -# --------------------------------- -# Configure devupstream class usage -# --------------------------------- -BBCLASSEXTEND = "devupstream:target" - -SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/linux.git;protocol=https;branch=v${LINUX_VERSION}-stm32mp;name=linux" -SRCREV_class-devupstream = "1cb30cb5ffc29a53ec2031b6a29878ddd266516c" -SRCREV_FORMAT_class-devupstream = "linux" -PV_class-devupstream = "${LINUX_VERSION}+github+${SRCPV}" - -# --------------------------------- -# Configure default preference to manage dynamic selection between tarball and github -# --------------------------------- -STM32MP_SOURCE_SELECTION ?= "tarball" - -DEFAULT_PREFERENCE = "${@bb.utils.contains('STM32MP_SOURCE_SELECTION', 'github', '-1', '1', d)}" - -# --------------------------------- -# Configure archiver use -# --------------------------------- -include ${@oe.utils.ifelse(d.getVar('ST_ARCHIVER_ENABLE') == '1', 'linux-stm32mp-archiver.inc','')} - -# ------------------------------------------------------------- -# Defconfig -# -KERNEL_DEFCONFIG = "multi_v7_defconfig" -KERNEL_CONFIG_FRAGMENTS = "${@bb.utils.contains('KERNEL_DEFCONFIG', 'multi_v7_defconfig', '${S}/arch/arm/configs/fragment-01-multiv7_cleanup.config', '', d)}" -KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('KERNEL_DEFCONFIG', 'multi_v7_defconfig', '${S}/arch/arm/configs/fragment-02-multiv7_addons.config', '', d)}" -KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${WORKDIR}/fragments/4.19/fragment-03-systemd.config', '', d)} " -KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('COMBINED_FEATURES', 'optee', '${WORKDIR}/fragments/4.19/fragment-04-optee.config', '', d)}" -KERNEL_CONFIG_FRAGMENTS += "${WORKDIR}/fragments/4.19/fragment-05-modules.config" - -SRC_URI += "file://4.19/fragment-03-systemd.config;subdir=fragments" -SRC_URI += "file://4.19/fragment-04-optee.config;subdir=fragments" -SRC_URI += "file://4.19/fragment-05-modules.config;subdir=fragments" -# Don't forget to add/del for devupstream -SRC_URI_class-devupstream += " file://4.19/fragment-03-systemd.config;subdir=fragments " -SRC_URI_class-devupstream += " file://4.19/fragment-04-optee.config;subdir=fragments " -SRC_URI_class-devupstream += " file://4.19/fragment-05-modules.config;subdir=fragments " - -# ------------------------------------------------------------- -# Kernel Args -# -KERNEL_EXTRA_ARGS += "LOADADDR=${ST_KERNEL_LOADADDR}" diff --git a/recipes-kernel/linux/linux-stm32mp_5.4.bb b/recipes-kernel/linux/linux-stm32mp_5.4.bb new file mode 100644 index 0000000..8bfca00 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp_5.4.bb @@ -0,0 +1,89 @@ +SUMMARY = "Linux STM32MP Kernel" +SECTION = "kernel" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814" + +include linux-stm32mp.inc + +LINUX_VERSION = "5.4" +LINUX_SUBVERSION = "31" +SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${LINUX_VERSION}.${LINUX_SUBVERSION}.tar.xz;name=kernel" +SRC_URI[kernel.sha256sum] = "a11083f8f809887f6a0f8d4467532385b99418f17998fe6e837807491c276eeb" + +SRC_URI += " \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0001-ARM-stm32mp1-r1-MACHINE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0002-ARM-stm32mp1-r1-CPUFREQ.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0003-ARM-stm32mp1-r1-CRYPTO.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0005-ARM-stm32mp1-r1-CLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0006-ARM-stm32mp1-r1-DMA.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0007-ARM-stm32mp1-r1-DRM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0013-ARM-stm32mp1-r1-MFD.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0014-ARM-stm32mp1-r1-MMC-NAND.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0015-ARM-stm32mp1-r1-NET-TTY.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0016-ARM-stm32mp1-r1-PHY-USB.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0018-ARM-stm32mp1-r1-SOUND.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0019-ARM-stm32mp1-r1-MISC.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0020-ARM-stm32mp1-r1-DEVICETREE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0021-ARM-stm32mp1-r1-CONFIG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0022-ARM-stm32mp1-r1-POWER.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0023-ARM-stm32mp1-r1-PERF.patch \ +" + +PV = "${LINUX_VERSION}.${LINUX_SUBVERSION}" + +S = "${WORKDIR}/linux-${LINUX_VERSION}.${LINUX_SUBVERSION}" + +# --------------------------------- +# Configure devupstream class usage +# --------------------------------- +#BBCLASSEXTEND = "devupstream:target" + +#SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/linux.git;protocol=https;branch=v${LINUX_VERSION}-stm32mp;name=linux" +#SRCREV_class-devupstream = "196201973b7048ccf75aa63ac3c3673f8b6ee1c1" +#SRCREV_FORMAT_class-devupstream = "linux" +#PV_class-devupstream = "${LINUX_VERSION}+github+${SRCPV}" + +# --------------------------------- +# Configure default preference to manage dynamic selection between tarball and github +# --------------------------------- +#STM32MP_SOURCE_SELECTION ?= "tarball" + +#DEFAULT_PREFERENCE = "${@bb.utils.contains('STM32MP_SOURCE_SELECTION', 'github', '-1', '1', d)}" + +# --------------------------------- +# Configure archiver use +# --------------------------------- +include ${@oe.utils.ifelse(d.getVar('ST_ARCHIVER_ENABLE') == '1', 'linux-stm32mp-archiver.inc','')} + +# ------------------------------------------------------------- +# Defconfig +# +KERNEL_DEFCONFIG = "defconfig" +KERNEL_CONFIG_FRAGMENTS = "${@bb.utils.contains('KERNEL_DEFCONFIG', 'defconfig', '${S}/arch/arm/configs/fragment-01-multiv7_cleanup.config', '', d)}" +KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('KERNEL_DEFCONFIG', 'defconfig', '${S}/arch/arm/configs/fragment-02-multiv7_addons.config', '', d)}" +KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${WORKDIR}/fragments/5.4/fragment-03-systemd.config', '', d)} " +KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('COMBINED_FEATURES', 'optee', '${WORKDIR}/fragments/5.4/fragment-04-optee.config', '', d)}" +KERNEL_CONFIG_FRAGMENTS += "${WORKDIR}/fragments/5.4/fragment-05-modules.config" +KERNEL_CONFIG_FRAGMENTS += "${@oe.utils.ifelse(d.getVar('KERNEL_SIGN_ENABLE') == '1', '${WORKDIR}/fragments/5.4/fragment-06-signature.config','')} " + +SRC_URI += "file://${LINUX_VERSION}/fragment-03-systemd.config;subdir=fragments" +SRC_URI += "file://${LINUX_VERSION}/fragment-04-optee.config;subdir=fragments" +SRC_URI += "file://${LINUX_VERSION}/fragment-05-modules.config;subdir=fragments" +SRC_URI += "file://${LINUX_VERSION}/fragment-06-signature.config;subdir=fragments" + +# Don't forget to add/del for devupstream +#SRC_URI_class-devupstream += " file://${LINUX_VERSION}/fragment-03-systemd.config;subdir=fragments " +#SRC_URI_class-devupstream += " file://${LINUX_VERSION}/fragment-04-optee.config;subdir=fragments " +#SRC_URI_class-devupstream += " file://${LINUX_VERSION}/fragment-05-modules.config;subdir=fragments " + +# ------------------------------------------------------------- +# Kernel Args +# +KERNEL_EXTRA_ARGS += "LOADADDR=${ST_KERNEL_LOADADDR}"